aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/headless/main.cpp146
-rw-r--r--src/openvic-simulation/Modifier.cpp104
-rw-r--r--src/openvic-simulation/Modifier.hpp40
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp8
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.hpp4
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.cpp31
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp18
-rw-r--r--src/openvic-simulation/economy/Building.cpp62
-rw-r--r--src/openvic-simulation/economy/Building.hpp25
-rw-r--r--src/openvic-simulation/economy/Good.hpp2
-rw-r--r--src/openvic-simulation/economy/ProductionType.cpp66
-rw-r--r--src/openvic-simulation/economy/ProductionType.hpp39
-rw-r--r--src/openvic-simulation/map/Map.cpp8
-rw-r--r--src/openvic-simulation/map/Province.cpp4
-rw-r--r--src/openvic-simulation/map/Province.hpp3
-rw-r--r--src/openvic-simulation/map/TerrainType.cpp15
-rw-r--r--src/openvic-simulation/map/TerrainType.hpp4
-rw-r--r--src/openvic-simulation/military/Unit.cpp224
-rw-r--r--src/openvic-simulation/military/Unit.hpp46
-rw-r--r--src/openvic-simulation/politics/Government.cpp2
-rw-r--r--src/openvic-simulation/politics/Government.hpp2
-rw-r--r--src/openvic-simulation/pop/Culture.cpp16
-rw-r--r--src/openvic-simulation/pop/Culture.hpp4
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.cpp8
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.hpp213
-rw-r--r--src/openvic-simulation/types/fixed_point/FixedPoint.hpp22
-rw-r--r--src/openvic-simulation/utility/Logger.cpp16
-rw-r--r--src/openvic-simulation/utility/Logger.hpp53
28 files changed, 699 insertions, 486 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index 3935c2d..6cb6661 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -1,3 +1,5 @@
+#include <cstring>
+
#include <openvic-simulation/GameManager.hpp>
#include <openvic-simulation/dataloader/Dataloader.hpp>
#include <openvic-simulation/utility/Logger.hpp>
@@ -5,36 +7,20 @@
using namespace OpenVic;
-static char const* get_program_name(char const* name) {
- static constexpr char const* missing_name = "<program>";
- if (name == nullptr) return missing_name;
- char const* last_separator = name;
- while (*name != '\0') {
- if (*name == '/' || *name == '\\') {
- last_separator = name + 1;
- }
- ++name;
- }
- if (*last_separator == '\0') return missing_name;
- return last_separator;
+static void print_help(std::ostream& stream, char const* program_name) {
+ stream
+ << "Usage: " << program_name << " [-h] [-t] [-b <path>] [path]+\n"
+ << " -h : Print this help message and exit the program.\n"
+ << " -t : Run tests after loading defines.\n"
+ << " -b : Use the following path as the base directory (instead of searching for one).\n"
+ << " -s : Use the following path as a hint to search for a base directory.\n"
+ << "Any following paths are read as mod directories, with priority starting at one above the base directory.\n"
+ << "(Paths with spaces need to be enclosed in \"quotes\").\n";
}
-static bool headless_load(Dataloader::path_vector_t const& roots) {
+static bool headless_load(GameManager& game_manager, Dataloader const& dataloader) {
bool ret = true;
- Logger::set_info_func([](std::string&& str) { std::cout << str; });
- Logger::set_warning_func([](std::string&& str) { std::cerr << str; });
- Logger::set_error_func([](std::string&& str) { std::cerr << str; });
-
- GameManager game_manager { []() {
- Logger::info("State updated");
- } };
- Dataloader dataloader;
-
- if (!dataloader.set_roots(roots)) {
- Logger::error("Failed to set dataloader roots!");
- ret = false;
- }
if (!dataloader.load_defines(game_manager)) {
Logger::error("Failed to load defines!");
ret = false;
@@ -52,37 +38,105 @@ static bool headless_load(Dataloader::path_vector_t const& roots) {
ret = false;
}
+ return ret;
+}
+
+static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) {
+ bool ret = true;
+
+ Dataloader dataloader;
+ if (!dataloader.set_roots(roots)) {
+ Logger::error("Failed to set dataloader roots!");
+ ret = false;
+ }
+
+ GameManager game_manager { []() {
+ Logger::info("State updated");
+ } };
+
+ ret &= headless_load(game_manager, dataloader);
- Testing testing = Testing(&game_manager);
- std::cout << std::endl << "Testing Loaded" << std::endl << std::endl;
- testing.execute_all_scripts();
- testing.report_results();
- std::cout << "Testing Executed" << std::endl << std::endl;
+ if (run_tests) {
+ Testing testing = Testing(&game_manager);
+ std::cout << std::endl << "Testing Loaded" << std::endl << std::endl;
+ testing.execute_all_scripts();
+ testing.report_results();
+ std::cout << "Testing Executed" << std::endl << std::endl;
+ }
return ret;
}
+/*
+ $ program [-h] [-t] [-b] [path]+
+*/
+
int main(int argc, char const* argv[]) {
- Dataloader::path_vector_t roots;
- if (argc < 2) {
- // TODO - non-Windows default paths
- static const fs::path default_path = "C:/Program Files (x86)/Steam/steamapps/common/Victoria 2";
-
- std::cout
- << "Usage: " << get_program_name(argc > 0 ? argv[0] : nullptr) << " <base defines dir> [[mod defines dir]+]\n"
- << "Requires defines path(s) as arguments, starting with the base defines and continuing with mods.\n"
- << "(Paths with spaces need to be enclosed in \"quotes\").\n"
- << "Defaulting to " << default_path << std::endl;
- roots.push_back(default_path);
- } else {
- for (int i = 1; i < argc; ++i) {
- roots.push_back(argv[i]);
+ Logger::set_logger_funcs();
+
+ char const* program_name = Logger::get_filename(argc > 0 ? argv[0] : nullptr, "<program>");
+ fs::path root;
+ bool run_tests = false;
+ int argn = 0;
+
+ /* Reads the next argument and converts it to a path via path_transform. If reading or converting fails, an error
+ * message and the help text are displayed, along with returning false to signify the program should exit.
+ */
+ const auto _read = [&root, &argn, argc, argv, program_name](std::string_view command, std::string_view path_use, auto path_transform) -> bool {
+ if (root.empty()) {
+ if (++argn < argc) {
+ char const* path = argv[argn];
+ root = path_transform(path);
+ if (!root.empty()) {
+ return true;
+ } else {
+ std::cerr << "Empty path after giving \"" << path << "\" to " << path_use << " command line argument \"" << command << "\"." << std::endl;
+ }
+ } else {
+ std::cerr << "Missing path after " << path_use << " command line argument \"" << command << "\"." << std::endl;
+ }
+ } else {
+ std::cerr << "Duplicate " << path_use << " command line argument \"-b\"." << std::endl;
}
+ print_help(std::cerr, program_name);
+ return false;
+ };
+
+ while (++argn < argc) {
+ char const* arg = argv[argn];
+ if (strcmp(arg, "-h") == 0) {
+ print_help(std::cout, program_name);
+ return 0;
+ } else if (strcmp(arg, "-t") == 0) {
+ run_tests = true;
+ } else if (strcmp(arg, "-b") == 0) {
+ if (!_read("-b", "base directory", std::identity{})) {
+ return -1;
+ }
+ } else if (strcmp(arg, "-s") == 0) {
+ if (!_read("-s", "search hint", Dataloader::search_for_game_path)) {
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+ if (root.empty()) {
+ root = Dataloader::search_for_game_path();
+ if (root.empty()) {
+ std::cerr << "Search for base directory path failed!" << std::endl;
+ print_help(std::cerr, program_name);
+ return -1;
+ }
+ }
+ Dataloader::path_vector_t roots = { root };
+ while (argn < argc) {
+ roots.emplace_back(root / argv[argn++]);
}
std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl;
- const bool ret = headless_load(roots);
+ const bool ret = run_headless(roots, run_tests);
std::cout << "!!! HEADLESS SIMULATION END !!!" << std::endl;
diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp
index 4e5b860..fc5dcaf 100644
--- a/src/openvic-simulation/Modifier.cpp
+++ b/src/openvic-simulation/Modifier.cpp
@@ -3,13 +3,17 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-ModifierEffect::ModifierEffect(std::string_view new_identifier, bool new_positive_good)
- : HasIdentifier { new_identifier }, positive_good { new_positive_good } {}
+ModifierEffect::ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format)
+ : HasIdentifier { new_identifier }, positive_good { new_positive_good }, format { new_format } {}
bool ModifierEffect::get_positive_good() const {
return positive_good;
}
+ModifierEffect::format_t ModifierEffect::get_format() const {
+ return format;
+}
+
ModifierValue::ModifierValue() = default;
ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {}
ModifierValue::ModifierValue(ModifierValue const&) = default;
@@ -94,12 +98,12 @@ Date const& ModifierInstance::get_expiry_date() const {
ModifierManager::ModifierManager()
: modifier_effects { "modifier effects"}, modifiers { "modifiers" } {}
-bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good) {
+bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good, ModifierEffect::format_t format) {
if (identifier.empty()) {
Logger::error("Invalid modifier effect identifier - empty!");
return false;
}
- return modifier_effects.add_item({ identifier, positive_good });
+ return modifier_effects.add_item({ identifier, positive_good, format });
}
bool ModifierManager::add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) {
@@ -117,47 +121,105 @@ bool ModifierManager::add_modifier(std::string_view identifier, ModifierValue&&
bool ModifierManager::setup_modifier_effects() {
bool ret = true;
+ using enum ModifierEffect::format_t;
+
ret &= add_modifier_effect("movement_cost", false);
ret &= add_modifier_effect("farm_rgo_size", true);
ret &= add_modifier_effect("farm_rgo_eff", true);
ret &= add_modifier_effect("mine_rgo_size", true);
ret &= add_modifier_effect("mine_rgo_eff", true);
- ret &= add_modifier_effect("min_build_railroad", false);
- ret &= add_modifier_effect("supply_limit", true);
+ ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL);
ret &= add_modifier_effect("combat_width", false);
- ret &= add_modifier_effect("defence", true);
+ ret &= add_modifier_effect("defence", true, RAW_DECIMAL);
+ ret &= add_modifier_effect("local_ship_build", false);
+ ret &= add_modifier_effect("research_points_modifier", true);
+ ret &= add_modifier_effect("local_rgo_output", true);
+ ret &= add_modifier_effect("attrition", false, RAW_DECIMAL);
+ ret &= add_modifier_effect("immigrant_push", false);
+ ret &= add_modifier_effect("population_growth", true);
+ ret &= add_modifier_effect("local_RGO_throughput", true);
+ ret &= add_modifier_effect("assimilation_rate", true);
+
+ /* These should be added automatically for each Building loaded (or at least
+ * non-factories), however currently we need modifier effects locked before we
+ * can load buildings, so some architectural changes will be needed.
+ */
+ ret &= add_modifier_effect("max_fort", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("min_build_fort", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("max_naval_base", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("min_build_naval_base", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("max_railroad", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("min_build_railroad", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("max_university", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("min_build_university", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("max_bank", true, ModifierEffect::format_t::INT);
+ ret &= add_modifier_effect("min_build_bank", true, ModifierEffect::format_t::INT);
modifier_effects.lock();
return ret;
}
-node_callback_t ModifierManager::expect_modifier_value_and_default(callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback) const {
- return [this, modifier_callback, default_callback](ast::NodeCPtr root) -> bool {
- ModifierValue modifier;
- bool ret = expect_dictionary(
- [this, &modifier, default_callback](std::string_view key, ast::NodeCPtr value) -> bool {
- ModifierEffect const* effect = get_modifier_effect_by_identifier(key);
- if (effect != nullptr) {
- if (modifier.values.find(effect) == modifier.values.end()) {
- return expect_fixed_point(
- assign_variable_callback(modifier.values[effect])
- )(value);
- }
+key_value_callback_t ModifierManager::_modifier_effect_callback(
+ ModifierValue& modifier, key_value_callback_t default_callback,
+ ModifierEffectValidator auto effect_validator) const {
+
+ return [this, &modifier, default_callback, effect_validator](std::string_view key, ast::NodeCPtr value) -> bool {
+ ModifierEffect const* effect = get_modifier_effect_by_identifier(key);
+ if (effect != nullptr) {
+ if (effect_validator(*effect)) {
+ if (modifier.values.find(effect) == modifier.values.end()) {
+ return expect_fixed_point(
+ assign_variable_callback(modifier.values[effect])
+ )(value);
+ } else {
Logger::error("Duplicate modifier effect: ", key);
return false;
}
- return default_callback(key, value);
+ } else {
+ Logger::error("Failed to validate modifier effect: ", key);
+ return false;
}
- )(root);
+ }
+ return default_callback(key, value);
+ };
+}
+
+node_callback_t ModifierManager::expect_validated_modifier_value_and_default(callback_t<ModifierValue&&> modifier_callback,
+ key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator) const {
+ return [this, modifier_callback, default_callback, effect_validator](ast::NodeCPtr root) -> bool {
+ ModifierValue modifier;
+ bool ret = expect_dictionary(_modifier_effect_callback(modifier, default_callback, effect_validator))(root);
ret &= modifier_callback(std::move(modifier));
return ret;
};
}
+node_callback_t ModifierManager::expect_validated_modifier_value(callback_t<ModifierValue&&> modifier_callback,
+ ModifierEffectValidator auto effect_validator) const {
+ return expect_validated_modifier_value_and_default(modifier_callback, key_value_invalid_callback, effect_validator);
+}
+
+node_callback_t ModifierManager::expect_modifier_value_and_default(callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback) const {
+ return expect_validated_modifier_value_and_default(modifier_callback, default_callback,
+ [](ModifierEffect const&) -> bool { return true; }
+ );
+}
node_callback_t ModifierManager::expect_modifier_value(callback_t<ModifierValue&&> modifier_callback) const {
return expect_modifier_value_and_default(modifier_callback, key_value_invalid_callback);
}
+node_callback_t ModifierManager::expect_whitelisted_modifier_value_and_default(callback_t<ModifierValue&&> modifier_callback, std::set<std::string, std::less<void>> const& whitelist, key_value_callback_t default_callback) const {
+ return expect_validated_modifier_value_and_default(modifier_callback, default_callback,
+ [&whitelist](ModifierEffect const& effect) -> bool {
+ return whitelist.contains(effect.get_identifier());
+ }
+ );
+}
+
+node_callback_t ModifierManager::expect_whitelisted_modifier_value(callback_t<ModifierValue&&> modifier_callback, std::set<std::string, std::less<void>> const& whitelist) const {
+ return expect_whitelisted_modifier_value_and_default(modifier_callback, whitelist, key_value_invalid_callback);
+}
+
node_callback_t ModifierManager::expect_modifier_value_and_key_map_and_default(callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback, key_map_t&& key_map) const {
return [this, modifier_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool {
bool ret = expect_modifier_value_and_default(
diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp
index 2e1b03a..0801aa5 100644
--- a/src/openvic-simulation/Modifier.hpp
+++ b/src/openvic-simulation/Modifier.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <set>
+
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -8,26 +10,32 @@ namespace OpenVic {
struct ModifierEffect : HasIdentifier {
friend struct ModifierManager;
+ enum class format_t {
+ RAW_DECIMAL, PERCENTAGE_DECIMAL, INT
+ };
+
private:
/* If true, positive values will be green and negative values will be red.
* If false, the colours will be switced.
*/
const bool positive_good;
+ const format_t format;
// TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200%
- ModifierEffect(std::string_view new_identifier, bool new_positive_good);
+ ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format);
public:
ModifierEffect(ModifierEffect&&) = default;
bool get_positive_good() const;
+ format_t get_format() const;
};
struct ModifierValue {
friend struct ModifierManager;
- using effect_map_t = std::map<ModifierEffect const*, fixed_point_t>;
+ using effect_map_t = decimal_map_t<ModifierEffect const*>;
private:
effect_map_t values;
@@ -86,16 +94,24 @@ namespace OpenVic {
Date const& get_expiry_date() const;
};
+ template<typename Fn>
+ concept ModifierEffectValidator = std::predicate<Fn, ModifierEffect const&>;
+
struct ModifierManager {
private:
IdentifierRegistry<ModifierEffect> modifier_effects;
IdentifierRegistry<Modifier> modifiers;
+ /* effect_validator takes in ModifierEffect const& */
+ NodeTools::key_value_callback_t _modifier_effect_callback(ModifierValue& modifier,
+ NodeTools::key_value_callback_t default_callback,
+ ModifierEffectValidator auto effect_validator) const;
+
public:
ModifierManager();
- bool add_modifier_effect(std::string_view identifier, bool province_good);
+ bool add_modifier_effect(std::string_view identifier, bool province_good, ModifierEffect::format_t format = ModifierEffect::format_t::PERCENTAGE_DECIMAL);
IDENTIFIER_REGISTRY_ACCESSORS(modifier_effect)
bool add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon);
@@ -103,19 +119,25 @@ namespace OpenVic {
bool setup_modifier_effects();
+ NodeTools::node_callback_t expect_validated_modifier_value_and_default(NodeTools::callback_t<ModifierValue&&> modifier_callback,
+ NodeTools::key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator) const;
+ NodeTools::node_callback_t expect_validated_modifier_value(NodeTools::callback_t<ModifierValue&&> modifier_callback,
+ ModifierEffectValidator auto effect_validator) const;
+
NodeTools::node_callback_t expect_modifier_value_and_default(NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback) const;
NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t<ModifierValue&&> modifier_callback) const;
+ NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default(NodeTools::callback_t<ModifierValue&&> modifier_callback, std::set<std::string, std::less<void>> const& whitelist, NodeTools::key_value_callback_t default_callback) const;
+ NodeTools::node_callback_t expect_whitelisted_modifier_value(NodeTools::callback_t<ModifierValue&&> modifier_callback, std::set<std::string, std::less<void>> const& whitelist) const;
+
NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default(NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, NodeTools::key_map_t&& key_map) const;
NodeTools::node_callback_t expect_modifier_value_and_key_map(NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_map_t&& key_map) const;
template<typename... Args>
- NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default(
- NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, NodeTools::key_map_t&& key_map,
- std::string_view key, NodeTools::dictionary_entry_t::expected_count_t expected_count, NodeTools::node_callback_t callback,
- Args... args) const {
- NodeTools::add_key_map_entry(key_map, key, expected_count, callback);
- return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, std::move(key_map), args...);
+ NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default(NodeTools::callback_t<ModifierValue&&> modifier_callback,
+ NodeTools::key_value_callback_t default_callback, NodeTools::key_map_t&& key_map, Args... args) const {
+ NodeTools::add_key_map_entries(key_map, args...);
+ return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, std::move(key_map));
}
template<typename... Args>
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index b9d7496..72e3113 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -46,8 +46,8 @@ constexpr bool path_equals(std::string_view lhs, std::string_view rhs) {
}
template<typename LT, typename RT>
-constexpr bool filename_equals(const LT& lhs, const RT& rhs) {
- std::string_view left, right;
+bool filename_equals(const LT& lhs, const RT& rhs) {
+ std::string left, right;
if constexpr (std::same_as<LT, std::filesystem::path>)
left = lhs.filename().string();
else left = lhs;
@@ -314,7 +314,7 @@ fs::path Dataloader::search_for_game_path(fs::path hint_path) {
return _cached_paths[hint_path] = _search_for_game_path(hint_path);
}
-bool Dataloader::set_roots(path_vector_t new_roots) {
+bool Dataloader::set_roots(path_vector_t const& new_roots) {
if (!roots.empty()) {
Logger::error("Overriding existing dataloader roots!");
roots.clear();
@@ -700,7 +700,7 @@ static bool _load_localisation_file(Dataloader::localisation_callback_t callback
return ret;
}
-bool Dataloader::load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir) {
+bool Dataloader::load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir) const {
return apply_to_files_in_dir(localisation_dir, ".csv",
[callback](fs::path path) -> bool {
return _load_localisation_file(callback, parse_csv(path).get_lines());
diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp
index c4cd7c7..c268a94 100644
--- a/src/openvic-simulation/dataloader/Dataloader.hpp
+++ b/src/openvic-simulation/dataloader/Dataloader.hpp
@@ -54,7 +54,7 @@ namespace OpenVic {
static fs::path search_for_game_path(fs::path hint_path = {});
/* In reverse-load order, so base defines first and final loaded mod last */
- bool set_roots(path_vector_t new_roots);
+ bool set_roots(path_vector_t const& new_roots);
/* REQUIREMENTS:
* DAT-24
@@ -76,7 +76,7 @@ namespace OpenVic {
/* Args: key, locale, localisation */
using localisation_callback_t = NodeTools::callback_t<std::string_view, locale_t, std::string_view>;
- bool load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir = "localisation");
+ bool load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir = "localisation") const;
private:
struct fshash
diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp
index 391ffb6..c2edb18 100644
--- a/src/openvic-simulation/dataloader/NodeTools.cpp
+++ b/src/openvic-simulation/dataloader/NodeTools.cpp
@@ -360,20 +360,25 @@ node_callback_t NodeTools::expect_dictionary_key_map(key_map_t key_map) {
return expect_dictionary_key_map_and_length_and_default(std::move(key_map), default_length_callback, key_value_invalid_callback);
}
-node_callback_t NodeTools::name_list_callback(std::vector<std::string>& list) {
- return expect_list_reserve_length(
- list,
- expect_identifier_or_string(
- [&list](std::string_view str) -> bool {
- if (!str.empty()) {
- list.push_back(std::string { str });
- return true;
+node_callback_t NodeTools::name_list_callback(callback_t<std::vector<std::string>&&> callback) {
+ return [callback](ast::NodeCPtr node) -> bool {
+ std::vector<std::string> list;
+ bool ret = expect_list_reserve_length(
+ list,
+ expect_identifier_or_string(
+ [&list](std::string_view str) -> bool {
+ if (!str.empty()) {
+ list.push_back(std::string { str });
+ return true;
+ }
+ Logger::error("Empty identifier or string");
+ return false;
}
- Logger::error("Empty identifier or string");
- return false;
- }
- )
- );
+ )
+ )(node);
+ ret &= callback(std::move(list));
+ return ret;
+ };
}
callback_t<std::string_view> NodeTools::assign_variable_callback_string(std::string& var) {
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 44ac271..e98a4b0 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -123,18 +123,24 @@ namespace OpenVic {
key_value_callback_t dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback);
bool check_key_map_counts(key_map_t& key_map);
+ constexpr bool add_key_map_entries(key_map_t& key_map) { return true; }
+ template<typename... Args>
+ bool add_key_map_entries(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback, Args... args) {
+ bool ret = add_key_map_entry(key_map, key, expected_count, callback);
+ ret &= add_key_map_entries(key_map, args...);
+ return ret;
+ }
+
node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback);
node_callback_t expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback);
node_callback_t expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback);
node_callback_t expect_dictionary_key_map(key_map_t key_map);
template<typename... Args>
- node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback,
- std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback,
- Args... args) {
+ node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback, Args... args) {
// TODO - pass return value back up (part of big key_map_t rewrite?)
- add_key_map_entry(key_map, key, expected_count, callback);
- return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback, args...);
+ add_key_map_entries(key_map, args...);
+ return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback);
}
template<typename... Args>
@@ -177,7 +183,7 @@ namespace OpenVic {
return expect_list_reserve_length(t, expect_assign(callback));
}
- node_callback_t name_list_callback(std::vector<std::string>& list);
+ node_callback_t name_list_callback(callback_t<std::vector<std::string>&&> callback);
template<typename T>
callback_t<std::string_view> expect_mapped_string(string_map_t<T> const& map, callback_t<T> callback) {
diff --git a/src/openvic-simulation/economy/Building.cpp b/src/openvic-simulation/economy/Building.cpp
index 23bd04c..d132e8e 100644
--- a/src/openvic-simulation/economy/Building.cpp
+++ b/src/openvic-simulation/economy/Building.cpp
@@ -5,18 +5,24 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Building::Building(std::string_view identifier, BuildingType const& type, ARGS) : HasIdentifier { identifier }, ModifierValue { std::move(modifiers) }, type { type },
- on_completion { on_completion }, completion_size { completion_size }, max_level { max_level }, goods_cost { goods_cost }, cost { cost }, build_time { build_time },
- visibility { visibility }, on_map { on_map }, default_enabled { default_enabled }, production_type { production_type }, pop_build_factory { pop_build_factory },
- strategic_factory { strategic_factory }, advanced_factory { advanced_factory }, fort_level { fort_level }, naval_capacity { naval_capacity },
- colonial_points { colonial_points }, in_province { in_province }, one_per_state { one_per_state }, colonial_range { colonial_range },
- infrastructure { infrastructure }, movement_cost { movement_cost }, local_ship_build { local_ship_build }, spawn_railway_track { spawn_railway_track },
+Building::Building(std::string_view identifier, BuildingType const& type, ARGS)
+ : HasIdentifier { identifier }, type { type }, modifier { std::move(modifier) }, on_completion { on_completion },
+ completion_size { completion_size }, max_level { max_level }, goods_cost { std::move(goods_cost) }, cost { cost },
+ build_time { build_time }, visibility { visibility }, on_map { on_map }, default_enabled { default_enabled },
+ production_type { production_type }, pop_build_factory { pop_build_factory }, strategic_factory { strategic_factory },
+ advanced_factory { advanced_factory }, fort_level { fort_level }, naval_capacity { naval_capacity },
+ colonial_points { std::move(colonial_points) }, in_province { in_province }, one_per_state { one_per_state },
+ colonial_range { colonial_range }, infrastructure { infrastructure }, spawn_railway_track { spawn_railway_track },
sail { sail }, steam { steam }, capital { capital }, port { port } {}
BuildingType const& Building::get_type() const {
return type;
}
+ModifierValue const& Building::get_modifier() const {
+ return modifier;
+}
+
std::string_view Building::get_on_completion() const {
return on_completion;
}
@@ -29,7 +35,7 @@ Building::level_t Building::get_max_level() const {
return max_level;
}
-std::map<Good const*, fixed_point_t> const& Building::get_goods_cost() const {
+Good::good_map_t const& Building::get_goods_cost() const {
return goods_cost;
}
@@ -97,17 +103,14 @@ fixed_point_t Building::get_infrastructure() const {
return infrastructure;
}
-fixed_point_t Building::get_movement_cost() const {
- return movement_cost;
-}
-
bool Building::spawned_railway_track() const {
return spawn_railway_track;
}
BuildingType::BuildingType(std::string_view new_identifier) : HasIdentifier { new_identifier } {}
-BuildingInstance::BuildingInstance(Building const& building) : HasIdentifier { building.get_identifier() }, building { building } {}
+BuildingInstance::BuildingInstance(Building const& building)
+ : HasIdentifier { building.get_identifier() }, building { building } {}
Building const& BuildingInstance::get_building() const {
return building;
@@ -181,7 +184,7 @@ bool BuildingManager::add_building_type(std::string_view identifier) {
Logger::error("Invalid building type identifier - empty!");
return false;
}
- return building_types.add_item({ identifier });
+ return building_types.add_item({ identifier }, duplicate_ignore_callback);
}
bool BuildingManager::add_building(std::string_view identifier, BuildingType const* type, ARGS) {
@@ -195,21 +198,16 @@ bool BuildingManager::add_building(std::string_view identifier, BuildingType con
}
return buildings.add_item({
- identifier, *type, on_completion, completion_size, max_level, goods_cost, cost, build_time, visibility, on_map, default_enabled,
- production_type, pop_build_factory, strategic_factory, advanced_factory, fort_level, naval_capacity, colonial_points, in_province, one_per_state,
- colonial_range, infrastructure, movement_cost, local_ship_build, spawn_railway_track, sail, steam, capital, port, std::move(modifiers)
+ identifier, *type, std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), cost, build_time, visibility, on_map, default_enabled,
+ production_type, pop_build_factory, strategic_factory, advanced_factory, fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state,
+ colonial_range, infrastructure, spawn_railway_track, sail, steam, capital, port
});
}
bool BuildingManager::load_buildings_file(GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root) {
bool ret = expect_dictionary_reserve_length(buildings, [this](std::string_view, ast::NodeCPtr value) -> bool {
return expect_key("type", expect_identifier(
- [this](std::string_view identifier) -> bool {
- if (!building_types.has_identifier(identifier)) {
- return building_types.add_item({ identifier });
- }
- return true;
- }
+ std::bind(&BuildingManager::add_building_type, this, std::placeholders::_1)
))(value);
})(root);
lock_building_types();
@@ -218,17 +216,17 @@ bool BuildingManager::load_buildings_file(GoodManager const& good_manager, Produ
BuildingType const* type = nullptr;
ProductionType const* production_type = nullptr;
std::string_view on_completion;
- fixed_point_t completion_size = 0, cost = 0, infrastructure = 0, movement_cost = 0, colonial_range = 0, local_ship_build = 0;
+ fixed_point_t completion_size = 0, cost = 0, infrastructure = 0, colonial_range = 0;
Building::level_t max_level = 0, fort_level = 0;
- std::map<Good const*, fixed_point_t> goods_cost;
+ Good::good_map_t goods_cost;
Timespan build_time;
bool visibility = false, on_map = false, default_enabled = false, pop_build_factory = false, strategic_factory = false, advanced_factory = false;
bool in_province = false, one_per_state = false, spawn_railway_track = false, sail = false, steam = false, capital = false, port = false;
uint64_t naval_capacity = 0;
std::vector<fixed_point_t> colonial_points;
- ModifierValue modifiers;
+ ModifierValue modifier;
- bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifiers),
+ bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifier),
"type", ONE_EXACTLY, expect_identifier(expect_building_type_identifier(assign_variable_callback_pointer(type))),
"on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(on_completion)),
"completion_size", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(completion_size)),
@@ -239,7 +237,8 @@ bool BuildingManager::load_buildings_file(GoodManager const& good_manager, Produ
"visibility", ONE_EXACTLY, expect_bool(assign_variable_callback(visibility)),
"onmap", ONE_EXACTLY, expect_bool(assign_variable_callback(on_map)),
"default_enabled", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_enabled)),
- "production_type", ZERO_OR_ONE, expect_identifier(production_type_manager.expect_production_type_identifier(assign_variable_callback_pointer(production_type))),
+ "production_type", ZERO_OR_ONE, expect_identifier(production_type_manager.expect_production_type_identifier(
+ assign_variable_callback_pointer(production_type))),
"pop_build_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(pop_build_factory)),
"strategic_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(strategic_factory)),
"advanced_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(advanced_factory)),
@@ -253,8 +252,6 @@ bool BuildingManager::load_buildings_file(GoodManager const& good_manager, Produ
"one_per_state", ZERO_OR_ONE, expect_bool(assign_variable_callback(one_per_state)),
"colonial_range", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_range)),
"infrastructure", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(infrastructure)),
- "movement_cost", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(movement_cost)),
- "local_ship_build", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(local_ship_build)),
"spawn_railway_track", ZERO_OR_ONE, expect_bool(assign_variable_callback(spawn_railway_track)),
"sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)),
"steam", ZERO_OR_ONE, expect_bool(assign_variable_callback(steam)),
@@ -263,9 +260,10 @@ bool BuildingManager::load_buildings_file(GoodManager const& good_manager, Produ
)(value);
ret &= add_building(
- key, type, on_completion, completion_size, max_level, goods_cost, cost, build_time, visibility, on_map, default_enabled,
- production_type, pop_build_factory, strategic_factory, advanced_factory, fort_level, naval_capacity, colonial_points, in_province,
- one_per_state, colonial_range, infrastructure, movement_cost, local_ship_build, spawn_railway_track, sail, steam, capital, port, std::move(modifiers)
+ key, type,std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), cost, build_time,
+ visibility, on_map, default_enabled, production_type, pop_build_factory, strategic_factory, advanced_factory,
+ fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state, colonial_range, infrastructure,
+ spawn_railway_track, sail, steam, capital, port
);
return ret;
diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp
index 3d1e24b..b56c9a2 100644
--- a/src/openvic-simulation/economy/Building.hpp
+++ b/src/openvic-simulation/economy/Building.hpp
@@ -7,12 +7,13 @@
#include "openvic-simulation/economy/ProductionType.hpp"
#include "openvic-simulation/Modifier.hpp"
-#define ARGS std::string_view on_completion, fixed_point_t completion_size, level_t max_level, \
- std::map<Good const*, fixed_point_t> goods_cost, fixed_point_t cost, Timespan build_time, bool visibility, bool on_map, bool default_enabled, \
- ProductionType const* production_type, bool pop_build_factory, bool strategic_factory, bool advanced_factory, level_t fort_level, \
- uint64_t naval_capacity, std::vector<fixed_point_t> colonial_points, bool in_province, bool one_per_state, fixed_point_t colonial_range, \
- fixed_point_t infrastructure, fixed_point_t movement_cost, fixed_point_t local_ship_build, bool spawn_railway_track, bool sail, bool steam, \
- bool capital, bool port, ModifierValue&& modifiers
+#define ARGS \
+ ModifierValue&& modifier, std::string_view on_completion, fixed_point_t completion_size, level_t max_level, \
+ Good::good_map_t&& goods_cost, fixed_point_t cost, Timespan build_time, bool visibility, bool on_map, bool default_enabled, \
+ ProductionType const* production_type, bool pop_build_factory, bool strategic_factory, bool advanced_factory, level_t fort_level, \
+ uint64_t naval_capacity, std::vector<fixed_point_t>&& colonial_points, bool in_province, bool one_per_state, fixed_point_t colonial_range, \
+ fixed_point_t infrastructure, bool spawn_railway_track, bool sail, bool steam, \
+ bool capital, bool port
namespace OpenVic {
@@ -24,17 +25,18 @@ namespace OpenVic {
* MAP-12, MAP-75, MAP-76
* MAP-13, MAP-78, MAP-79
*/
- struct Building : HasIdentifier, ModifierValue {
+ struct Building : HasIdentifier {
friend struct BuildingManager;
using level_t = int16_t;
private:
BuildingType const& type;
+ const ModifierValue modifier;
const std::string on_completion; //probably sound played on completion
const fixed_point_t completion_size;
const level_t max_level;
- const std::map<Good const*, fixed_point_t> goods_cost;
+ const Good::good_map_t goods_cost;
const fixed_point_t cost;
const Timespan build_time; //time
const bool visibility;
@@ -55,8 +57,6 @@ namespace OpenVic {
const fixed_point_t colonial_range;
const fixed_point_t infrastructure;
- const fixed_point_t movement_cost;
- const fixed_point_t local_ship_build;
const bool spawn_railway_track;
const bool sail; //only in clipper shipyard
@@ -70,10 +70,11 @@ namespace OpenVic {
Building(Building&&) = default;
BuildingType const& get_type() const;
+ ModifierValue const& get_modifier() const;
std::string_view get_on_completion() const;
fixed_point_t get_completion_size() const;
level_t get_max_level() const;
- std::map<Good const*, fixed_point_t> const& get_goods_cost() const;
+ Good::good_map_t const& get_goods_cost() const;
fixed_point_t get_cost() const;
Timespan get_build_time() const;
bool has_visibility() const;
@@ -94,8 +95,6 @@ namespace OpenVic {
fixed_point_t get_colonial_range() const;
fixed_point_t get_infrastructure() const;
- fixed_point_t get_movement_cost() const;
- fixed_point_t get_local_ship_build() const;
bool spawned_railway_track() const;
};
diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp
index 1dce41f..2a850fa 100644
--- a/src/openvic-simulation/economy/Good.hpp
+++ b/src/openvic-simulation/economy/Good.hpp
@@ -33,6 +33,8 @@ namespace OpenVic {
using price_t = fixed_point_t;
static constexpr price_t NULL_PRICE = fixed_point_t::_0();
+ using good_map_t = decimal_map_t<Good const*>;
+
private:
GoodCategory const& category;
const price_t base_price;
diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp
index 01d45be..3a27cd6 100644
--- a/src/openvic-simulation/economy/ProductionType.cpp
+++ b/src/openvic-simulation/economy/ProductionType.cpp
@@ -8,29 +8,29 @@ using namespace OpenVic::NodeTools;
EmployedPop::EmployedPop(PopType const* pop_type, bool artisan, effect_t effect, fixed_point_t effect_multiplier, fixed_point_t amount)
: pop_type { pop_type }, artisan { artisan }, effect { effect }, effect_multiplier { effect_multiplier }, amount { amount } {}
-PopType const* EmployedPop::get_pop_type() {
+PopType const* EmployedPop::get_pop_type() const {
return pop_type;
}
-bool EmployedPop::is_artisan() {
+bool EmployedPop::is_artisan() const {
return artisan;
}
-EmployedPop::effect_t EmployedPop::get_effect() {
+EmployedPop::effect_t EmployedPop::get_effect() const {
return effect;
}
-fixed_point_t EmployedPop::get_effect_multiplier() {
+fixed_point_t EmployedPop::get_effect_multiplier() const {
return effect_multiplier;
}
-fixed_point_t EmployedPop::get_amount() {
+fixed_point_t EmployedPop::get_amount() const {
return amount;
}
-ProductionType::ProductionType(PRODUCTION_TYPE_ARGS) : HasIdentifier { identifier }, owner { owner },
- employees { employees }, type { type }, workforce { workforce }, input_goods { input_goods }, output_goods { output_goods },
- value { value }, bonuses { bonuses }, efficiency { efficiency }, coastal { coastal }, farm { farm }, mine { mine } {}
+ProductionType::ProductionType(PRODUCTION_TYPE_ARGS) : HasIdentifier { identifier }, owner { owner }, employees { employees },
+ type { type }, workforce { workforce }, input_goods { std::move(input_goods) }, output_goods { output_goods },
+ value { value }, bonuses { std::move(bonuses) }, efficiency { std::move(efficiency) }, coastal { coastal }, farm { farm }, mine { mine } {}
EmployedPop const& ProductionType::get_owner() const {
return owner;
@@ -48,7 +48,7 @@ Pop::pop_size_t ProductionType::get_workforce() const {
return workforce;
}
-std::map<Good const*, fixed_point_t> const& ProductionType::get_input_goods() {
+Good::good_map_t const& ProductionType::get_input_goods() const {
return input_goods;
}
@@ -60,11 +60,11 @@ fixed_point_t ProductionType::get_value() const {
return value;
}
-std::vector<Bonus> const& ProductionType::get_bonuses() {
+std::vector<Bonus> const& ProductionType::get_bonuses() const {
return bonuses;
}
-std::map<Good const*, fixed_point_t> const& ProductionType::get_efficiency() {
+Good::good_map_t const& ProductionType::get_efficiency() const {
return efficiency;
}
@@ -83,7 +83,7 @@ bool ProductionType::is_mine() const {
ProductionTypeManager::ProductionTypeManager() : production_types { "production types" } {}
node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager,
- callback_t<EmployedPop> cb) {
+ callback_t<EmployedPop&&> cb) {
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
std::string_view pop_type;
@@ -113,12 +113,12 @@ node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager const& g
}
}
- return res & cb(EmployedPop { found_pop_type, artisan, effect, effect_multiplier, amount });
+ return res & cb({ found_pop_type, artisan, effect, effect_multiplier, amount });
};
}
node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager,
- callback_t<std::vector<EmployedPop>> cb) {
+ callback_t<std::vector<EmployedPop>&&> cb) {
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
std::vector<EmployedPop> employed_pops;
@@ -128,7 +128,7 @@ node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager con
employed_pops.push_back(owner);
return res_partial;
})(node);
- return res & cb(employed_pops);
+ return res & cb(std::move(employed_pops));
};
}
@@ -166,25 +166,25 @@ bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManage
}
return production_types.add_item({
- identifier, owner, employees, type, workforce, input_goods,
- output_goods, value, bonuses, efficiency, coastal, farm, mine
+ identifier, owner, employees, type, workforce, std::move(input_goods),
+ output_goods, value, std::move(bonuses), std::move(efficiency), coastal, farm, mine
});
}
#define PARSE_NODE expect_dictionary_keys_and_default( \
- key_value_success_callback, \
- "owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)), \
- "employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)), \
- "type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))), \
- "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)), \
- "input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)), \
- "output_goods", ZERO_OR_ONE, expect_identifier(good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods))), \
- "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)), \
- "efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)), \
- "is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)), \
- "farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)), \
- "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine)) \
- )
+ key_value_success_callback, \
+ "owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)), \
+ "employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)), \
+ "type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))), \
+ "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)), \
+ "input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)), \
+ "output_goods", ZERO_OR_ONE, expect_identifier(good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods))), \
+ "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)), \
+ "efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)), \
+ "is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)), \
+ "farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)), \
+ "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine)) \
+ )
bool ProductionTypeManager::load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root) {
size_t expected_types = 0;
@@ -236,7 +236,7 @@ bool ProductionTypeManager::load_production_types_file(GoodManager const& good_m
ProductionType::type_t type;
Good const* output_goods = nullptr;
Pop::pop_size_t workforce = 0; // 0 is a meaningless value -> unset
- std::map<Good const*, fixed_point_t> input_goods, efficiency;
+ Good::good_map_t input_goods, efficiency;
fixed_point_t value = 0; // 0 is a meaningless value -> unset
std::vector<Bonus> bonuses;
bool coastal = false, farm = false, mine = false;
@@ -260,8 +260,8 @@ bool ProductionTypeManager::load_production_types_file(GoodManager const& good_m
ret &= PARSE_NODE(node);
ret &= add_production_type(
- key, owner, employees, type, workforce, input_goods, output_goods, value,
- bonuses, efficiency, coastal, farm, mine, good_manager
+ key, owner, employees, type, workforce, std::move(input_goods), output_goods, value,
+ std::move(bonuses), std::move(efficiency), coastal, farm, mine, good_manager
);
return ret;
}
diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp
index 420e70e..2deb461 100644
--- a/src/openvic-simulation/economy/ProductionType.hpp
+++ b/src/openvic-simulation/economy/ProductionType.hpp
@@ -7,9 +7,8 @@
#define PRODUCTION_TYPE_ARGS \
std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type, \
- Pop::pop_size_t workforce, std::map<Good const*, fixed_point_t> input_goods, Good const* output_goods, \
- fixed_point_t value, std::vector<Bonus> bonuses, std::map<Good const*, fixed_point_t> efficiency, \
- bool coastal, bool farm, bool mine
+ Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value, \
+ std::vector<Bonus>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
namespace OpenVic {
struct ProductionTypeManager;
@@ -17,14 +16,16 @@ namespace OpenVic {
struct EmployedPop {
friend struct ProductionTypeManager;
- private:
- PopType const* pop_type; // poptype
- bool artisan; // set by the parser if the magic "artisan" poptype is passed
enum struct effect_t {
INPUT,
OUTPUT,
THROUGHPUT
- } effect;
+ };
+
+ private:
+ PopType const* pop_type; // poptype
+ bool artisan; // set by the parser if the magic "artisan" poptype is passed
+ effect_t effect;
fixed_point_t effect_multiplier;
fixed_point_t amount;
@@ -33,11 +34,11 @@ namespace OpenVic {
public:
EmployedPop() = default;
- PopType const* get_pop_type();
- bool is_artisan();
- effect_t get_effect();
- fixed_point_t get_effect_multiplier();
- fixed_point_t get_amount();
+ PopType const* get_pop_type() const;
+ bool is_artisan() const;
+ effect_t get_effect() const;
+ fixed_point_t get_effect_multiplier() const;
+ fixed_point_t get_amount() const;
};
struct Bonus {
@@ -58,12 +59,12 @@ namespace OpenVic {
} type;
const Pop::pop_size_t workforce;
- const std::map<Good const*, fixed_point_t> input_goods;
+ const Good::good_map_t input_goods;
Good const* output_goods;
const fixed_point_t value;
const std::vector<Bonus> bonuses;
- const std::map<Good const*, fixed_point_t> efficiency;
+ const Good::good_map_t efficiency;
const bool coastal; // is_coastal
const bool farm;
@@ -79,12 +80,12 @@ namespace OpenVic {
type_t get_type() const;
Pop::pop_size_t get_workforce() const;
- std::map<Good const*, fixed_point_t> const& get_input_goods();
+ Good::good_map_t const& get_input_goods() const;
Good const* get_output_goods() const;
fixed_point_t get_value() const;
- std::vector<Bonus> const& get_bonuses();
+ std::vector<Bonus> const& get_bonuses() const;
- std::map<Good const*, fixed_point_t> const& get_efficiency();
+ Good::good_map_t const& get_efficiency() const;
bool is_coastal() const;
bool is_farm() const;
@@ -96,9 +97,9 @@ namespace OpenVic {
IdentifierRegistry<ProductionType> production_types;
NodeTools::node_callback_t _expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager,
- NodeTools::callback_t<EmployedPop> cb);
+ NodeTools::callback_t<EmployedPop&&> cb);
NodeTools::node_callback_t _expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager,
- NodeTools::callback_t<std::vector<EmployedPop>> cb);
+ NodeTools::callback_t<std::vector<EmployedPop>&&> cb);
public:
ProductionTypeManager();
diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp
index acd882e..777579e 100644
--- a/src/openvic-simulation/map/Map.cpp
+++ b/src/openvic-simulation/map/Map.cpp
@@ -525,16 +525,16 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain
for (size_t idx = 0; idx < province_checklist.size(); ++idx) {
Province* province = provinces.get_item_by_index(idx);
province->_set_terrain_type(reinterpret_cast<TerrainType const*>(get_largest_item(terrain_type_pixels_list[idx]).first));
- if (!province_checklist[idx]) {
+ province->on_map = province_checklist[idx];
+ if (!province->on_map) {
if (detailed_errors) {
- Logger::error("Province missing from shape image: ", province->to_string());
+ Logger::warning("Province missing from shape image: ", province->to_string());
}
missing++;
}
}
if (missing > 0) {
- Logger::error("Province image is missing ", missing, " province colours");
- ret = false;
+ Logger::warning("Province image is missing ", missing, " province colours");
}
return ret;
diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp
index 5b1a130..45b3987 100644
--- a/src/openvic-simulation/map/Province.cpp
+++ b/src/openvic-simulation/map/Province.cpp
@@ -17,6 +17,10 @@ Region* Province::get_region() const {
return region;
}
+bool Province::get_on_map() const {
+ return on_map;
+}
+
bool Province::get_has_region() const {
return has_region;
}
diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp
index d925898..2704354 100644
--- a/src/openvic-simulation/map/Province.hpp
+++ b/src/openvic-simulation/map/Province.hpp
@@ -61,7 +61,7 @@ namespace OpenVic {
private:
const index_t index;
Region* region = nullptr;
- bool has_region = false, water = false;
+ bool on_map = false, has_region = false, water = false;
life_rating_t life_rating = 0;
IdentifierRegistry<BuildingInstance> buildings;
// TODO - change this into a factory-like structure
@@ -85,6 +85,7 @@ namespace OpenVic {
index_t get_index() const;
Region* get_region() const;
+ bool get_on_map() const;
bool get_has_region() const;
bool get_water() const;
TerrainType const* get_terrain_type() const;
diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp
index ce0b7e7..8624cdb 100644
--- a/src/openvic-simulation/map/TerrainType.cpp
+++ b/src/openvic-simulation/map/TerrainType.cpp
@@ -5,8 +5,12 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-TerrainType::TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, bool new_is_water)
- : HasIdentifierAndColour { new_identifier, new_colour, true, false }, ModifierValue { std::move(new_values) }, is_water { new_is_water } {}
+TerrainType::TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water)
+ : HasIdentifierAndColour { new_identifier, new_colour, true, false }, modifier { std::move(new_modifier) }, is_water { new_is_water } {}
+
+ModifierValue const& TerrainType::get_modifier() const {
+ return modifier;
+}
bool TerrainType::get_is_water() const {
return is_water;
@@ -125,11 +129,8 @@ bool TerrainTypeManager::_load_terrain_type_mapping(std::string_view mapping_key
"priority", ZERO_OR_ONE, expect_uint(assign_variable_callback(priority)),
"has_texture", ZERO_OR_ONE, expect_bool(assign_variable_callback(has_texture))
)(mapping_value);
- if (has_texture) {
- if (++terrain_texture_count == terrain_texture_limit + 1) {
- Logger::error("More terrain textures than limit!");
- ret = false;
- }
+ if (has_texture && ++terrain_texture_count == terrain_texture_limit + 1) {
+ Logger::warning("More terrain textures than limit!");
}
ret &= add_terrain_type_mapping(mapping_key, type, std::move(terrain_indicies), priority, has_texture);
return true;
diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp
index 1353130..edda0a9 100644
--- a/src/openvic-simulation/map/TerrainType.hpp
+++ b/src/openvic-simulation/map/TerrainType.hpp
@@ -9,13 +9,15 @@ namespace OpenVic {
friend struct TerrainTypeManager;
private:
+ const ModifierValue modifier;
const bool is_water;
- TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, bool new_is_water);
+ TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water);
public:
TerrainType(TerrainType&&) = default;
+ ModifierValue const& get_modifier() const;
bool get_is_water() const;
};
diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp
index 63ece91..8b010e3 100644
--- a/src/openvic-simulation/military/Unit.cpp
+++ b/src/openvic-simulation/military/Unit.cpp
@@ -2,22 +2,27 @@
#include <set>
-#define UNIT_ARGS icon, sprite, active, unit_type, floating_flag, priority, max_strength, \
- default_organisation, maximum_speed, weighted_value, build_time, build_cost, supply_consumption, \
- supply_cost
-#define LAND_ARGS primary_culture, sprite_override, sprite_mount, sprite_mount_attach_node, \
- reconnaissance, attack, defence, discipline, support, maneuver, siege
-#define NAVY_ARGS naval_icon, sail, transport, capital, move_sound, select_sound, colonial_points, build_overseas, min_port_level, \
- limit_per_port, supply_consumption_score, hull, gun_power, fire_range, evasion, torpedo_attack
+#define UNIT_ARGS \
+ icon, sprite, active, unit_type, floating_flag, priority, max_strength, default_organisation, maximum_speed, \
+ weighted_value, move_sound, select_sound, build_time, std::move(build_cost), supply_consumption, std::move(supply_cost)
+
+#define LAND_ARGS \
+ primary_culture, sprite_override, sprite_mount, sprite_mount_attach_node, \
+ reconnaissance, attack, defence, discipline, support, maneuver, siege
+
+#define NAVY_ARGS \
+ naval_icon, sail, transport, capital, colonial_points, build_overseas, min_port_level, \
+ limit_per_port, supply_consumption_score, hull, gun_power, fire_range, evasion, torpedo_attack
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Unit::Unit(std::string_view identifier, type_t type, UNIT_PARAMS) : HasIdentifier { identifier },
- icon { icon }, type { type }, sprite { sprite }, active { active }, unit_type { unit_type },
- floating_flag { floating_flag }, priority { priority }, max_strength { max_strength },
+Unit::Unit(std::string_view identifier, type_t type, UNIT_PARAMS)
+ : HasIdentifier { identifier }, icon { icon }, type { type }, sprite { sprite }, active { active },
+ unit_type { unit_type }, floating_flag { floating_flag }, priority { priority }, max_strength { max_strength },
default_organisation { default_organisation }, maximum_speed { maximum_speed }, weighted_value { weighted_value },
- build_time { build_time }, build_cost { build_cost }, supply_consumption { supply_consumption }, supply_cost { supply_cost } {}
+ move_sound { move_sound }, select_sound { select_sound }, build_time { build_time }, build_cost { std::move(build_cost) },
+ supply_consumption { supply_consumption }, supply_cost { std::move(supply_cost) } {}
Unit::icon_t Unit::get_icon() const {
return icon;
@@ -67,7 +72,15 @@ fixed_point_t Unit::get_weighted_value() const {
return weighted_value;
}
-std::map<Good const*, fixed_point_t> const& Unit::get_build_cost() const {
+std::string_view Unit::get_move_sound() const {
+ return move_sound;
+}
+
+std::string_view Unit::get_select_sound() const {
+ return select_sound;
+}
+
+Good::good_map_t const& Unit::get_build_cost() const {
return build_cost;
}
@@ -75,14 +88,15 @@ fixed_point_t Unit::get_supply_consumption() const {
return supply_consumption;
}
-std::map<Good const*, fixed_point_t> const& Unit::get_supply_cost() const {
+Good::good_map_t const& Unit::get_supply_cost() const {
return supply_cost;
}
LandUnit::LandUnit(std::string_view identifier, UNIT_PARAMS, LAND_PARAMS)
- : Unit { identifier, type_t::LAND, UNIT_ARGS }, primary_culture { primary_culture }, sprite_override { sprite_override },
- sprite_mount { sprite_mount }, sprite_mount_attach_node { sprite_mount_attach_node }, reconnaissance { reconnaissance },
- attack { attack }, defence { defence }, discipline { discipline }, support { support }, maneuver { maneuver }, siege { siege } {}
+ : Unit { identifier, type_t::LAND, UNIT_ARGS }, primary_culture { primary_culture },
+ sprite_override { sprite_override }, sprite_mount { sprite_mount }, sprite_mount_attach_node { sprite_mount_attach_node },
+ reconnaissance { reconnaissance }, attack { attack }, defence { defence }, discipline { discipline }, support { support },
+ maneuver { maneuver }, siege { siege } {}
bool LandUnit::get_primary_culture() const {
return primary_culture;
@@ -128,11 +142,12 @@ fixed_point_t LandUnit::get_siege() const {
return siege;
}
-NavalUnit::NavalUnit(std::string_view identifier, UNIT_PARAMS, NAVY_PARAMS) : Unit { identifier, type_t::NAVAL, UNIT_ARGS },
- naval_icon { naval_icon }, sail { sail }, transport { transport }, capital { capital }, move_sound { move_sound },
- select_sound { select_sound }, colonial_points { colonial_points }, build_overseas { build_overseas },
- min_port_level { min_port_level }, limit_per_port { limit_per_port }, supply_consumption_score { supply_consumption_score },
- hull { hull }, gun_power { gun_power }, fire_range { fire_range }, evasion { evasion }, torpedo_attack { torpedo_attack } {};
+NavalUnit::NavalUnit(std::string_view identifier, UNIT_PARAMS, NAVY_PARAMS)
+ : Unit { identifier, type_t::NAVAL, UNIT_ARGS }, naval_icon { naval_icon }, sail { sail },
+ transport { transport }, capital { capital }, colonial_points { colonial_points },
+ build_overseas { build_overseas }, min_port_level { min_port_level },limit_per_port { limit_per_port },
+ supply_consumption_score { supply_consumption_score }, hull { hull }, gun_power { gun_power },
+ fire_range { fire_range }, evasion { evasion }, torpedo_attack { torpedo_attack } {};
NavalUnit::icon_t NavalUnit::get_naval_icon() const {
return naval_icon;
@@ -146,14 +161,6 @@ bool NavalUnit::is_transport() const {
return transport;
}
-std::string_view NavalUnit::get_move_sound() const {
- return move_sound;
-}
-
-std::string_view NavalUnit::get_select_sound() const {
- return select_sound;
-}
-
fixed_point_t NavalUnit::get_colonial_points() const {
return colonial_points;
}
@@ -235,32 +242,33 @@ bool UnitManager::add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_
return units.add_item(NavalUnit { identifier, UNIT_ARGS, NAVY_ARGS });
}
-static bool shared_keys_callback(std::string_view key, ast::NodeCPtr) {
- static const std::set<std::string, std::less<void>> reserved_keys = {
- "icon", "type", "sprite", "active", "unit_type", "floating_flag", "priority",
- "max_strength", "default_organisation", "maximum_speed", "weighted_value",
- "build_time", "build_cost", "supply_consumption", "supply_cost"
- };
- if (reserved_keys.contains(key)) return true;
- Logger::error("Invalid key: ", key);
- return false;
-};
-
bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root) {
return expect_dictionary([this, &good_manager](std::string_view key, ast::NodeCPtr value) -> bool {
+ Unit::type_t type;
Unit::icon_t icon = 0;
- std::string_view type, unit_type, sprite;
+ std::string_view unit_type, sprite, move_sound, select_sound; // TODO defaults for move_sound and select_sound
bool active = true, floating_flag = false;
uint32_t priority = 0;
Timespan build_time;
fixed_point_t maximum_speed = 0, max_strength = 0, default_organisation = 0, weighted_value = 0, supply_consumption = 0;
- std::map<Good const*, fixed_point_t> build_cost, supply_cost;
+ Good::good_map_t build_cost, supply_cost;
+ using enum Unit::type_t;
+ static const string_map_t<Unit::type_t> type_map = {
+ { "land", LAND }, { "naval", NAVAL }
+ };
+ bool ret = expect_key("type", expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))))(value);
+
+ if (!ret) {
+ Logger::error("Failed to read type for unit: ", key);
+ return false;
+ }
+
+ key_map_t key_map;
//shared
- bool ret = expect_dictionary_keys_and_default(
- key_value_success_callback,
+ ret &= add_key_map_entries(key_map,
"icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)),
- "type", ONE_EXACTLY, expect_identifier(assign_variable_callback(type)),
+ "type", ONE_EXACTLY, success_callback,
"sprite", ONE_EXACTLY, expect_identifier(assign_variable_callback(sprite)),
"active", ZERO_OR_ONE, expect_bool(assign_variable_callback(active)),
"unit_type", ONE_EXACTLY, expect_identifier(assign_variable_callback(unit_type)),
@@ -270,69 +278,77 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr
"default_organisation", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(default_organisation)),
"maximum_speed", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(maximum_speed)),
"weighted_value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(weighted_value)),
+ "move_sound", ZERO_OR_ONE, expect_identifier(assign_variable_callback(move_sound)),
+ "select_sound", ZERO_OR_ONE, expect_identifier(assign_variable_callback(select_sound)),
"build_time", ONE_EXACTLY, expect_days(assign_variable_callback(build_time)),
"build_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(build_cost)),
"supply_consumption", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(supply_consumption)),
"supply_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(supply_cost))
- )(value);
-
- if (type == "land") {
- bool primary_culture = false;
- std::string_view sprite_override, sprite_mount, sprite_mount_attach_node;
- fixed_point_t reconnaissance = 0, attack = 0, defence = 0, discipline = 0, support = 0, maneuver = 0, siege = 0;
-
- ret &= expect_dictionary_keys_and_default(
- shared_keys_callback,
- "primary_culture", ZERO_OR_ONE, expect_bool(assign_variable_callback(primary_culture)),
- "sprite_override", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_override)),
- "sprite_mount", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount)),
- "sprite_mount_attach_node", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount_attach_node)),
- "reconnaissance", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reconnaissance)),
- "attack", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(attack)),
- "defence", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(defence)),
- "discipline", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(discipline)),
- "support", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(support)),
- "maneuver", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(maneuver)),
- "siege", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(siege))
- )(value);
-
- ret &= add_land_unit(key, UNIT_ARGS, LAND_ARGS);
-
- return ret;
- } else if (type == "naval") {
- Unit::icon_t naval_icon = 0;
- bool sail = false, transport = false, capital = false, build_overseas = false;
- std::string_view move_sound, select_sound; //TODO defaults for both
- uint32_t min_port_level = 0;
- int32_t limit_per_port = 0;
- fixed_point_t fire_range = 0, evasion = 0, supply_consumption_score = 0, hull = 0, gun_power = 0, colonial_points = 0, torpedo_attack = 0;
-
- ret &= expect_dictionary_keys_and_default(
- shared_keys_callback,
- "naval_icon", ONE_EXACTLY, expect_uint(assign_variable_callback(naval_icon)),
- "sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)),
- "transport", ZERO_OR_ONE, expect_bool(assign_variable_callback(transport)),
- "capital", ZERO_OR_ONE, expect_bool(assign_variable_callback(capital)),
- "move_sound", ZERO_OR_ONE, expect_identifier(assign_variable_callback(move_sound)),
- "select_sound", ZERO_OR_ONE, expect_identifier(assign_variable_callback(select_sound)),
- "colonial_points", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_points)),
- "can_build_overseas", ZERO_OR_ONE, expect_bool(assign_variable_callback(build_overseas)),
- "min_port_level", ONE_EXACTLY, expect_uint(assign_variable_callback(min_port_level)),
- "limit_per_port", ONE_EXACTLY, expect_int(assign_variable_callback(limit_per_port)),
- "supply_consumption_score", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(supply_consumption_score)),
- "hull", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(hull)),
- "gun_power", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gun_power)),
- "fire_range", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(fire_range)),
- "evasion", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(evasion)),
- "torpedo_attack", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(torpedo_attack))
- )(value);
-
- ret &= add_naval_unit(key, UNIT_ARGS, NAVY_ARGS);
-
- return ret;
- } else {
- Logger::error("Invalid type for unit ", key, ": ", type);
+ );
+
+ switch (type) {
+ case LAND:
+ {
+ bool primary_culture = false;
+ std::string_view sprite_override, sprite_mount, sprite_mount_attach_node;
+ fixed_point_t reconnaissance = 0, attack = 0, defence = 0, discipline = 0, support = 0, maneuver = 0, siege = 0;
+
+ ret &= add_key_map_entries(key_map,
+ "primary_culture", ZERO_OR_ONE, expect_bool(assign_variable_callback(primary_culture)),
+ "sprite_override", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_override)),
+ "sprite_mount", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount)),
+ "sprite_mount_attach_node", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount_attach_node)),
+ "reconnaissance", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reconnaissance)),
+ "attack", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(attack)),
+ "defence", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(defence)),
+ "discipline", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(discipline)),
+ "support", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(support)),
+ "maneuver", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(maneuver)),
+ "siege", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(siege))
+ );
+
+ ret &= expect_dictionary_key_map(key_map)(value);
+
+ ret &= add_land_unit(key, UNIT_ARGS, LAND_ARGS);
+
+ return ret;
+ }
+ break;
+ case NAVAL:
+ {
+ Unit::icon_t naval_icon = 0;
+ bool sail = false, transport = false, capital = false, build_overseas = false;
+ uint32_t min_port_level = 0;
+ int32_t limit_per_port = 0;
+ fixed_point_t fire_range = 0, evasion = 0, supply_consumption_score = 0, hull = 0, gun_power = 0, colonial_points = 0, torpedo_attack = 0;
+
+ ret &= add_key_map_entries(key_map,
+ "naval_icon", ONE_EXACTLY, expect_uint(assign_variable_callback(naval_icon)),
+ "sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)),
+ "transport", ZERO_OR_ONE, expect_bool(assign_variable_callback(transport)),
+ "capital", ZERO_OR_ONE, expect_bool(assign_variable_callback(capital)),
+ "colonial_points", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_points)),
+ "can_build_overseas", ZERO_OR_ONE, expect_bool(assign_variable_callback(build_overseas)),
+ "min_port_level", ONE_EXACTLY, expect_uint(assign_variable_callback(min_port_level)),
+ "limit_per_port", ONE_EXACTLY, expect_int(assign_variable_callback(limit_per_port)),
+ "supply_consumption_score", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(supply_consumption_score)),
+ "hull", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(hull)),
+ "gun_power", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gun_power)),
+ "fire_range", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(fire_range)),
+ "evasion", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(evasion)),
+ "torpedo_attack", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(torpedo_attack))
+ );
+
+ ret &= expect_dictionary_key_map(key_map)(value);
+
+ ret &= add_naval_unit(key, UNIT_ARGS, NAVY_ARGS);
+
+ return ret;
+ }
+ break;
+ default:
+ Logger::error("Unknown unit type for ", key, ": ", static_cast<int>(type));
return false;
}
})(root);
-} \ No newline at end of file
+}
diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp
index de30763..17408cf 100644
--- a/src/openvic-simulation/military/Unit.hpp
+++ b/src/openvic-simulation/military/Unit.hpp
@@ -9,18 +9,22 @@
#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/types/Date.hpp"
-#define UNIT_PARAMS Unit::icon_t icon, std::string_view sprite, bool active, std::string_view unit_type, \
- bool floating_flag, uint32_t priority, fixed_point_t max_strength, fixed_point_t default_organisation, \
- fixed_point_t maximum_speed, fixed_point_t weighted_value, Timespan build_time, \
- std::map<Good const*, fixed_point_t> build_cost, fixed_point_t supply_consumption, \
- std::map<Good const*, fixed_point_t> supply_cost
-#define LAND_PARAMS bool primary_culture, std::string_view sprite_override, std::string_view sprite_mount, \
- std::string_view sprite_mount_attach_node, fixed_point_t reconnaissance, fixed_point_t attack, \
- fixed_point_t defence, fixed_point_t discipline, fixed_point_t support, fixed_point_t maneuver, fixed_point_t siege
-#define NAVY_PARAMS Unit::icon_t naval_icon, bool sail, bool transport, bool capital, std::string_view move_sound, \
- std::string_view select_sound, fixed_point_t colonial_points, bool build_overseas, uint32_t min_port_level, \
- int32_t limit_per_port, fixed_point_t supply_consumption_score, fixed_point_t hull, fixed_point_t gun_power, \
- fixed_point_t fire_range, fixed_point_t evasion, fixed_point_t torpedo_attack
+#define UNIT_PARAMS \
+ Unit::icon_t icon, std::string_view sprite, bool active, std::string_view unit_type, \
+ bool floating_flag, uint32_t priority, fixed_point_t max_strength, fixed_point_t default_organisation, \
+ fixed_point_t maximum_speed, fixed_point_t weighted_value, std::string_view move_sound, \
+ std::string_view select_sound, Timespan build_time, Good::good_map_t&& build_cost, \
+ fixed_point_t supply_consumption, Good::good_map_t&& supply_cost
+
+#define LAND_PARAMS \
+ bool primary_culture, std::string_view sprite_override, std::string_view sprite_mount, \
+ std::string_view sprite_mount_attach_node, fixed_point_t reconnaissance, fixed_point_t attack, fixed_point_t defence, \
+ fixed_point_t discipline, fixed_point_t support, fixed_point_t maneuver, fixed_point_t siege
+
+#define NAVY_PARAMS \
+ Unit::icon_t naval_icon, bool sail, bool transport, bool capital, fixed_point_t colonial_points, bool build_overseas, \
+ uint32_t min_port_level, int32_t limit_per_port, fixed_point_t supply_consumption_score, fixed_point_t hull, \
+ fixed_point_t gun_power, fixed_point_t fire_range, fixed_point_t evasion, fixed_point_t torpedo_attack
namespace OpenVic {
struct Unit : HasIdentifier {
@@ -44,10 +48,13 @@ namespace OpenVic {
const fixed_point_t maximum_speed;
const fixed_point_t weighted_value;
+ const std::string move_sound;
+ const std::string select_sound;
+
const Timespan build_time;
- const std::map<Good const*, fixed_point_t> build_cost;
+ const Good::good_map_t build_cost;
const fixed_point_t supply_consumption;
- const std::map<Good const*, fixed_point_t> supply_cost;
+ const Good::good_map_t supply_cost;
protected:
Unit(std::string_view identifier, type_t type, UNIT_PARAMS);
@@ -68,10 +75,13 @@ namespace OpenVic {
fixed_point_t get_maximum_speed() const;
fixed_point_t get_weighted_value() const;
+ std::string_view get_move_sound() const;
+ std::string_view get_select_sound() const;
+
Timespan get_build_time() const;
- std::map<Good const*, fixed_point_t> const& get_build_cost() const;
+ Good::good_map_t const& get_build_cost() const;
fixed_point_t get_supply_consumption() const;
- std::map<Good const*, fixed_point_t> const& get_supply_cost() const;
+ Good::good_map_t const& get_supply_cost() const;
};
struct LandUnit : Unit {
@@ -115,8 +125,6 @@ namespace OpenVic {
const bool sail;
const bool transport;
const bool capital;
- const std::string move_sound;
- const std::string select_sound;
const fixed_point_t colonial_points;
const bool build_overseas;
const uint32_t min_port_level;
@@ -138,8 +146,6 @@ namespace OpenVic {
bool can_sail() const;
bool is_transport() const;
bool is_capital() const;
- std::string_view get_move_sound() const;
- std::string_view get_select_sound() const;
fixed_point_t get_colonial_points() const;
bool can_build_overseas() const;
uint32_t get_min_port_level() const;
diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp
index 16b3bc4..c65abc6 100644
--- a/src/openvic-simulation/politics/Government.cpp
+++ b/src/openvic-simulation/politics/Government.cpp
@@ -36,7 +36,7 @@ std::string_view GovernmentType::get_flag_type() const {
GovernmentTypeManager::GovernmentTypeManager() : government_types { "government types" } {}
-bool GovernmentTypeManager::add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type) {
+bool GovernmentTypeManager::add_government_type(std::string_view identifier, std::vector<Ideology const*>&& ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type) {
if (identifier.empty()) {
Logger::error("Invalid government type identifier - empty!");
return false;
diff --git a/src/openvic-simulation/politics/Government.hpp b/src/openvic-simulation/politics/Government.hpp
index ba8496f..8cdee48 100644
--- a/src/openvic-simulation/politics/Government.hpp
+++ b/src/openvic-simulation/politics/Government.hpp
@@ -34,7 +34,7 @@ namespace OpenVic {
public:
GovernmentTypeManager();
- bool add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type);
+ bool add_government_type(std::string_view identifier, std::vector<Ideology const*>&& ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type);
IDENTIFIER_REGISTRY_ACCESSORS(government_type)
bool load_government_types_file(IdeologyManager const& ideology_manager, ast::NodeCPtr root);
diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp
index e3ba5dd..bbfa35a 100644
--- a/src/openvic-simulation/pop/Culture.cpp
+++ b/src/openvic-simulation/pop/Culture.cpp
@@ -28,11 +28,11 @@ bool CultureGroup::get_is_overseas() const {
}
Culture::Culture(std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group,
- std::vector<std::string> const& new_first_names, std::vector<std::string> const& new_last_names)
+ std::vector<std::string>&& new_first_names, std::vector<std::string>&& new_last_names)
: HasIdentifierAndColour { new_identifier, new_colour, true, false },
group { new_group },
- first_names { new_first_names },
- last_names { new_last_names } {}
+ first_names { std::move(new_first_names) },
+ last_names { std::move(new_last_names) } {}
CultureGroup const& Culture::get_group() const {
return group;
@@ -79,7 +79,7 @@ bool CultureManager::add_culture_group(std::string_view identifier, std::string_
return culture_groups.add_item({ identifier, leader, *graphical_culture_type, is_overseas });
}
-bool CultureManager::add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector<std::string> const& first_names, std::vector<std::string> const& last_names) {
+bool CultureManager::add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector<std::string>&& first_names, std::vector<std::string>&& last_names) {
if (!culture_groups.is_locked()) {
Logger::error("Cannot register cultures until culture groups are locked!");
return false;
@@ -96,7 +96,7 @@ bool CultureManager::add_culture(std::string_view identifier, colour_t colour, C
Logger::error("Invalid culture colour for ", identifier, ": ", colour_to_hex_string(colour));
return false;
}
- return cultures.add_item({ identifier, colour, *group, first_names, last_names });
+ return cultures.add_item({ identifier, colour, *group, std::move(first_names), std::move(last_names) });
}
bool CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) {
@@ -137,12 +137,12 @@ bool CultureManager::_load_culture(CultureGroup const* culture_group,
bool ret = expect_dictionary_keys(
"color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)),
- "first_names", ONE_EXACTLY, name_list_callback(first_names),
- "last_names", ONE_EXACTLY, name_list_callback(last_names),
+ "first_names", ONE_EXACTLY, name_list_callback(move_variable_callback(first_names)),
+ "last_names", ONE_EXACTLY, name_list_callback(move_variable_callback(last_names)),
"radicalism", ZERO_OR_ONE, success_callback,
"primary", ZERO_OR_ONE, success_callback
)(culture_node);
- ret &= add_culture(culture_key, colour, culture_group, first_names, last_names);
+ ret &= add_culture(culture_key, colour, culture_group, std::move(first_names), std::move(last_names));
return ret;
}
diff --git a/src/openvic-simulation/pop/Culture.hpp b/src/openvic-simulation/pop/Culture.hpp
index d36a90b..688733e 100644
--- a/src/openvic-simulation/pop/Culture.hpp
+++ b/src/openvic-simulation/pop/Culture.hpp
@@ -45,7 +45,7 @@ namespace OpenVic {
// TODO - radicalism, primary tag
- Culture(std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, std::vector<std::string> const& new_first_names, std::vector<std::string> const& new_last_names);
+ Culture(std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, std::vector<std::string>&& new_first_names, std::vector<std::string>&& new_last_names);
public:
Culture(Culture&&) = default;
@@ -74,7 +74,7 @@ namespace OpenVic {
bool add_culture_group(std::string_view identifier, std::string_view leader, GraphicalCultureType const* new_graphical_culture_type, bool is_overseas);
IDENTIFIER_REGISTRY_ACCESSORS(culture_group)
- bool add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector<std::string> const& first_names, std::vector<std::string> const& last_names);
+ bool add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector<std::string>&& first_names, std::vector<std::string>&& last_names);
IDENTIFIER_REGISTRY_ACCESSORS(culture)
bool load_graphical_culture_type_file(ast::NodeCPtr root);
diff --git a/src/openvic-simulation/types/IdentifierRegistry.cpp b/src/openvic-simulation/types/IdentifierRegistry.cpp
index 8e93cb1..f92750b 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.cpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.cpp
@@ -35,11 +35,3 @@ HasIdentifierAndColour::HasIdentifierAndColour(std::string_view new_identifier,
const colour_t new_colour, bool can_be_null, bool can_have_alpha)
: HasIdentifier { new_identifier },
HasColour { new_colour, can_be_null, can_have_alpha } {}
-
-distribution_t::value_type OpenVic::get_largest_item(distribution_t const& dist) {
- const distribution_t::const_iterator result = std::max_element(dist.begin(), dist.end(),
- [](distribution_t::value_type a, distribution_t::value_type b) -> bool {
- return a.second < b.second;
- });
- return result != dist.end() ? *result : distribution_t::value_type { nullptr, -1.0f };
-}
diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp
index 3ba7fc4..1a03e75 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.hpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.hpp
@@ -68,15 +68,45 @@ namespace OpenVic {
HasIdentifierAndColour& operator=(HasIdentifierAndColour&&) = delete;
};
- using distribution_t = std::map<HasIdentifierAndColour const*, float>;
-
- distribution_t::value_type get_largest_item(distribution_t const& dist);
+ template<typename T>
+ using decimal_map_t = std::map<T, fixed_point_t>;
template<typename T>
- using get_identifier_func_t = std::string_view(T::*)(void) const;
+ constexpr typename decimal_map_t<T>::value_type get_largest_item(decimal_map_t<T> const& map) {
+ constexpr auto pred = [](typename decimal_map_t<T>::value_type a, typename decimal_map_t<T>::value_type b) -> bool {
+ return a.second < b.second;
+ };
+ const typename decimal_map_t<T>::const_iterator result = std::max_element(
+ map.begin(), map.end(), pred
+ );
+ if (result != map.end()) {
+ return *result;
+ } else {
+ return { nullptr, -1 };
+ }
+ }
+
+ using distribution_t = decimal_map_t<HasIdentifierAndColour const*>;
- template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier,
- typename _Storage, _Type* (*get_ptr)(_Storage&), _Type const* (*get_cptr)(_Storage const&)>
+ /* Callbacks for trying to add duplicate keys via UniqueKeyRegistry::add_item */
+ static bool duplicate_fail_callback(std::string_view registry_name, std::string_view duplicate_identifier) {
+ Logger::error("Failure adding item to the ", registry_name, " registry - an item with the identifier \"",
+ duplicate_identifier, "\" already exists!");
+ return false;
+ }
+ static bool duplicate_warning_callback(std::string_view registry_name, std::string_view duplicate_identifier) {
+ Logger::warning("Warning adding item to the ", registry_name, " registry - an item with the identifier \"",
+ duplicate_identifier, "\" already exists!");
+ return true;
+ }
+ static bool duplicate_ignore_callback(std::string_view registry_name, std::string_view duplicate_identifier) {
+ return true;
+ }
+
+ /* _GetIdentifier - takes _Type const* and returns std::string_view
+ * _GetPointer - takes _Storage [const]& and returns T [const]*
+ */
+ template<typename _Type, typename _Storage, typename _GetIdentifier, typename _GetPointer>
class UniqueKeyRegistry {
const std::string name;
@@ -85,35 +115,29 @@ namespace OpenVic {
bool locked = false;
string_map_t<size_t> identifier_index_map;
+ _GetIdentifier GetIdentifier;
+ _GetPointer GetPointer;
+
public:
using value_type = _Type;
using storage_type = _Storage;
- UniqueKeyRegistry(std::string_view new_name, bool new_log_lock = true)
- : name { new_name }, log_lock { new_log_lock } {}
+ UniqueKeyRegistry(std::string_view new_name, bool new_log_lock = true, _GetIdentifier new_GetIdentifier = {}, _GetPointer new_GetPointer = {})
+ : name { new_name }, log_lock { new_log_lock }, GetIdentifier { new_GetIdentifier }, GetPointer { new_GetPointer } {}
std::string_view get_name() const {
return name;
}
- bool add_item(storage_type&& item, bool fail_on_duplicate = true) {
+ bool add_item(storage_type&& item, NodeTools::callback_t<std::string_view, std::string_view> duplicate_callback = duplicate_fail_callback) {
if (locked) {
Logger::error("Cannot add item to the ", name, " registry - locked!");
return false;
}
- value_type const* new_item = (*get_cptr)(item);
- const std::string_view new_identifier = (new_item->*get_identifier)();
+ const std::string_view new_identifier = GetIdentifier(GetPointer(item));
value_type const* old_item = get_item_by_identifier(new_identifier);
if (old_item != nullptr) {
-#define DUPLICATE_MESSAGE "Cannot add item to the ", name, " registry - an item with the identifier \"", new_identifier, "\" already exists!"
- if (fail_on_duplicate) {
- Logger::error(DUPLICATE_MESSAGE);
- return false;
- } else {
- Logger::warning(DUPLICATE_MESSAGE);
- return true;
- }
-#undef DUPLICATE_MESSAGE
+ return duplicate_callback(name, new_identifier);
}
identifier_index_map.emplace(new_identifier, items.size());
items.push_back(std::move(item));
@@ -155,30 +179,47 @@ namespace OpenVic {
}
}
- value_type* get_item_by_identifier(std::string_view identifier) {
- const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier);
- if (it != identifier_index_map.end()) return (*get_ptr)(items[it->second]);
- return nullptr;
+#define GETTERS \
+ value_type _const* get_item_by_identifier(std::string_view identifier) _const { \
+ const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier); \
+ if (it != identifier_index_map.end()) return GetPointer(items[it->second]); \
+ return nullptr; \
+ } \
+ value_type _const* get_item_by_index(size_t index) _const { \
+ return index < items.size() ? &items[index] : nullptr; \
+ } \
+ NodeTools::callback_t<std::string_view> expect_item_identifier(NodeTools::callback_t<value_type _const&> callback) _const { \
+ return [this, callback](std::string_view identifier) -> bool { \
+ value_type _const* item = get_item_by_identifier(identifier); \
+ if (item != nullptr) return callback(*item); \
+ Logger::error("Invalid ", name, ": ", identifier); \
+ return false; \
+ }; \
+ } \
+ NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<value_type _const&, ast::NodeCPtr> callback) _const { \
+ return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { \
+ value_type _const* item = get_item_by_identifier(key); \
+ if (item != nullptr) { \
+ return callback(*item, value); \
+ } \
+ Logger::error("Invalid ", name, " identifier: ", key); \
+ return false; \
+ }); \
}
- value_type const* get_item_by_identifier(std::string_view identifier) const {
- const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier);
- if (it != identifier_index_map.end()) return (*get_cptr)(items[it->second]);
- return nullptr;
- }
+#define _const
+GETTERS
+#undef _const
+#define _const const
+GETTERS
+#undef _const
+
+#undef GETTERS
bool has_identifier(std::string_view identifier) const {
return get_item_by_identifier(identifier) != nullptr;
}
- value_type* get_item_by_index(size_t index) {
- return index < items.size() ? &items[index] : nullptr;
- }
-
- value_type const* get_item_by_index(size_t index) const {
- return index < items.size() ? &items[index] : nullptr;
- }
-
bool has_index(size_t index) const {
return get_item_by_index(index) != nullptr;
}
@@ -194,49 +235,9 @@ namespace OpenVic {
return identifiers;
}
- NodeTools::callback_t<std::string_view> expect_item_identifier(NodeTools::callback_t<value_type&> callback) {
- return [this, callback](std::string_view identifier) -> bool {
- value_type* item = get_item_by_identifier(identifier);
- if (item != nullptr) return callback(*item);
- Logger::error("Invalid ", name, ": ", identifier);
- return false;
- };
- }
-
- NodeTools::callback_t<std::string_view> expect_item_identifier(NodeTools::callback_t<value_type const&> callback) const {
- return [this, callback](std::string_view identifier) -> bool {
- value_type const* item = get_item_by_identifier(identifier);
- if (item != nullptr) return callback(*item);
- Logger::error("Invalid ", name, ": ", identifier);
- return false;
- };
- }
-
- NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<value_type&, ast::NodeCPtr> callback) {
- return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool {
- value_type* item = get_item_by_identifier(key);
- if (item != nullptr) {
- return callback(*item, value);
- }
- Logger::error("Invalid ", name, " identifier: ", key);
- return false;
- });
- }
-
- NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<value_type const&, ast::NodeCPtr> callback) const {
- return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool {
- value_type const* item = get_item_by_identifier(key);
- if (item != nullptr) {
- return callback(*item, value);
- }
- Logger::error("Invalid ", name, " identifier: ", key);
- return false;
- });
- }
-
- NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t<std::map<value_type const*, fixed_point_t>&&> callback) const {
+ NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t<decimal_map_t<value_type const*>&&> callback) const {
return [this, callback](ast::NodeCPtr node) -> bool {
- std::map<value_type const*, fixed_point_t> map;
+ decimal_map_t<value_type const*> map;
bool ret = expect_item_dictionary([&map](value_type const& key, ast::NodeCPtr value) -> bool {
fixed_point_t val;
const bool ret = NodeTools::expect_fixed_point(NodeTools::assign_variable_callback(val))(value);
@@ -249,35 +250,47 @@ namespace OpenVic {
}
};
+ /* Standard value storage */
template<typename T>
- [[nodiscard]] inline constexpr T* _addressof(T& v) noexcept {
- return std::addressof<T>(v);
- }
+ struct _addressof {
+ constexpr T* operator()(T& item) const {
+ return std::addressof(item);
+ }
+ constexpr T const* operator()(T const& item) const {
+ return std::addressof(item);
+ }
+ };
- template<typename T>
- const T* _addressof(const T&&) = delete;
+ template<typename _Type, typename _GetIdentifier>
+ using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>>;
- template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier>
- using ValueRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, _Type, _addressof<_Type>, _addressof<const _Type>>;
+ /* std::unique_ptr dynamic storage */
+ template<typename T>
+ struct _uptr_get {
+ constexpr T* operator()(std::unique_ptr<T>& item) const {
+ return item.get();
+ }
+ constexpr T const* operator()(std::unique_ptr<T> const& item) const {
+ return item.get();
+ }
+ };
- template<typename _Type>
- constexpr _Type* get_ptr(std::unique_ptr<_Type>& storage) {
- return storage.get();
- }
- template<typename _Type>
- constexpr _Type const* get_cptr(std::unique_ptr<_Type> const& storage) {
- return storage.get();
- }
+ template<typename _Type, typename _GetIdentifier>
+ using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>>;
- template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier>
- using InstanceRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, std::unique_ptr<_Type>,
- get_ptr<_Type>, get_cptr<_Type>>;
+ /* HasIdentifier versions */
+ template<std::derived_from<HasIdentifier> T>
+ struct _get_identifier {
+ constexpr std::string_view operator()(T const* item) const {
+ return item->get_identifier();
+ }
+ };
template<std::derived_from<HasIdentifier> _Type>
- using IdentifierRegistry = ValueRegistry<HasIdentifier, _Type, &HasIdentifier::get_identifier>;
+ using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>>;
template<std::derived_from<HasIdentifier> _Type>
- using IdentifierInstanceRegistry = InstanceRegistry<HasIdentifier, _Type, &HasIdentifier::get_identifier>;
+ using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>>;
#define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(singular, plural) \
void lock_##plural() { plural.lock(); } \
@@ -296,7 +309,7 @@ namespace OpenVic {
return plural.expect_item_identifier(callback); } \
NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t<decltype(plural)::value_type const&, ast::NodeCPtr> callback) const { \
return plural.expect_item_dictionary(callback); } \
- NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t<std::map<decltype(plural)::value_type const*, fixed_point_t>&&> callback) const { \
+ NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t<decimal_map_t<decltype(plural)::value_type const*>&&> callback) const { \
return plural.expect_item_decimal_map(callback); }
#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(singular, plural) \
diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
index 459d9c4..649d3f6 100644
--- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
+++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
@@ -428,6 +428,28 @@ namespace OpenVic {
return *this;
}
+ constexpr fixed_point_t& operator++() {
+ value += ONE;
+ return *this;
+ }
+
+ constexpr fixed_point_t operator++(int) {
+ const fixed_point_t old = *this;
+ value += ONE;
+ return old;
+ }
+
+ constexpr fixed_point_t& operator--() {
+ value -= ONE;
+ return *this;
+ }
+
+ constexpr fixed_point_t operator--(int) {
+ const fixed_point_t old = *this;
+ value -= ONE;
+ return old;
+ }
+
constexpr friend fixed_point_t operator*(fixed_point_t const& lhs, fixed_point_t const& rhs) {
return lhs.value * rhs.value >> PRECISION;
}
diff --git a/src/openvic-simulation/utility/Logger.cpp b/src/openvic-simulation/utility/Logger.cpp
index fca08a5..68c43dd 100644
--- a/src/openvic-simulation/utility/Logger.cpp
+++ b/src/openvic-simulation/utility/Logger.cpp
@@ -4,19 +4,19 @@
using namespace OpenVic;
-Logger::log_func_t Logger::info_func {};
-Logger::log_queue_t Logger::info_queue {};
-Logger::log_func_t Logger::warning_func {};
-Logger::log_queue_t Logger::warning_queue {};
-Logger::log_func_t Logger::error_func {};
-Logger::log_queue_t Logger::error_queue {};
+void Logger::set_logger_funcs() {
+ Logger::set_info_func([](std::string&& str) { std::cout << str; });
+ Logger::set_warning_func([](std::string&& str) { std::cerr << str; });
+ Logger::set_error_func([](std::string&& str) { std::cerr << str; });
+}
-char const* Logger::get_filename(char const* filepath) {
- if (filepath == nullptr) return nullptr;
+char const* Logger::get_filename(char const* filepath, char const* default_path) {
+ if (filepath == nullptr) return default_path;
char const* last_slash = filepath;
while (*filepath != '\0') {
if (*filepath == '\\' || *filepath == '/') last_slash = filepath + 1;
filepath++;
}
+ if (*last_slash == '\0') return default_path;
return last_slash;
}
diff --git a/src/openvic-simulation/utility/Logger.hpp b/src/openvic-simulation/utility/Logger.hpp
index 55e0862..d60e59e 100644
--- a/src/openvic-simulation/utility/Logger.hpp
+++ b/src/openvic-simulation/utility/Logger.hpp
@@ -32,7 +32,7 @@ namespace OpenVic {
};
#endif
- class Logger {
+ class Logger final {
using log_func_t = std::function<void(std::string&&)>;
using log_queue_t = std::queue<std::string>;
@@ -42,42 +42,49 @@ namespace OpenVic {
using source_location = OpenVic::source_location;
#endif
- static char const* get_filename(char const* filepath);
+ public:
+ static void set_logger_funcs();
+ static char const* get_filename(char const* filepath, char const* default_path = nullptr);
+
+ private:
+ struct log_channel_t {
+ log_func_t func;
+ log_queue_t queue;
+ };
template<typename... Ts>
struct log {
- log(log_func_t log_func, log_queue_t& log_queue, Ts&&... ts, source_location const& location) {
+ log(log_channel_t& log_channel, Ts&&... ts, source_location const& location) {
std::stringstream stream;
stream << "\n" << get_filename(location.file_name()) << "("
//<< location.line() << ") `" << location.function_name() << "`: ";
<< location.line() << "): ";
((stream << std::forward<Ts>(ts)), ...);
stream << std::endl;
- log_queue.push(stream.str());
- if (log_func) {
+ log_channel.queue.push(stream.str());
+ if (log_channel.func) {
do {
- log_func(std::move(log_queue.front()));
- log_queue.pop();
- } while (!log_queue.empty());
+ log_channel.func(std::move(log_channel.queue.front()));
+ log_channel.queue.pop();
+ } while (!log_channel.queue.empty());
}
}
};
-#define LOG_FUNC(name) \
- private: \
- static log_func_t name##_func; \
- static log_queue_t name##_queue; \
- public: \
- static void set_##name##_func(log_func_t log_func) { \
- name##_func = log_func; \
- } \
- template<typename... Ts> \
- struct name { \
- name(Ts&&... ts, source_location const& location = source_location::current()) { \
- log<Ts...>{ name##_func, name##_queue, std::forward<Ts>(ts)..., location }; \
- } \
- }; \
- template<typename... Ts> \
+#define LOG_FUNC(name) \
+ private: \
+ static inline log_channel_t name##_channel{}; \
+ public: \
+ static inline void set_##name##_func(log_func_t log_func) { \
+ name##_channel.func = log_func; \
+ } \
+ template<typename... Ts> \
+ struct name { \
+ name(Ts&&... ts, source_location const& location = source_location::current()) { \
+ log<Ts...>{ name##_channel, std::forward<Ts>(ts)..., location }; \
+ } \
+ }; \
+ template<typename... Ts> \
name(Ts&&...) -> name<Ts...>;
LOG_FUNC(info)