From ce6e70d079f4ab18cdfa082032dc3580ab233b0e Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 13 Oct 2023 17:34:25 +0100 Subject: TGC compatibility fixes + other cleanup --- src/openvic-simulation/Modifier.cpp | 44 +++- src/openvic-simulation/Modifier.hpp | 22 +- src/openvic-simulation/dataloader/Dataloader.cpp | 4 +- src/openvic-simulation/dataloader/Dataloader.hpp | 4 +- src/openvic-simulation/dataloader/NodeTools.cpp | 31 +-- src/openvic-simulation/dataloader/NodeTools.hpp | 18 +- src/openvic-simulation/economy/Building.cpp | 62 +++--- src/openvic-simulation/economy/Building.hpp | 25 ++- src/openvic-simulation/economy/Good.hpp | 2 + src/openvic-simulation/economy/ProductionType.cpp | 66 +++--- src/openvic-simulation/economy/ProductionType.hpp | 39 ++-- src/openvic-simulation/map/Map.cpp | 8 +- src/openvic-simulation/map/Province.cpp | 4 + src/openvic-simulation/map/Province.hpp | 3 +- src/openvic-simulation/map/TerrainType.cpp | 7 +- src/openvic-simulation/military/Unit.cpp | 224 +++++++++++---------- src/openvic-simulation/military/Unit.hpp | 46 +++-- src/openvic-simulation/politics/Government.cpp | 2 +- src/openvic-simulation/politics/Government.hpp | 2 +- src/openvic-simulation/pop/Culture.cpp | 16 +- src/openvic-simulation/pop/Culture.hpp | 4 +- .../types/IdentifierRegistry.cpp | 8 - .../types/IdentifierRegistry.hpp | 53 +++-- .../types/fixed_point/FixedPoint.hpp | 22 ++ src/openvic-simulation/utility/Logger.hpp | 30 +-- 25 files changed, 425 insertions(+), 321 deletions(-) (limited to 'src/openvic-simulation') diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp index 4e5b860..1273fdd 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,16 +121,40 @@ 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; } diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp index 2e1b03a..663d359 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -8,26 +8,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; + using effect_map_t = decimal_map_t; private: effect_map_t values; @@ -95,7 +101,7 @@ namespace OpenVic { 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); @@ -110,12 +116,10 @@ namespace OpenVic { NodeTools::node_callback_t expect_modifier_value_and_key_map(NodeTools::callback_t modifier_callback, NodeTools::key_map_t&& key_map) const; template - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t 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 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 diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index b9d7496..5134054 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -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; - 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& 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&&> callback) { + return [callback](ast::NodeCPtr node) -> bool { + std::vector 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 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 + 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 - 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 @@ -177,7 +183,7 @@ namespace OpenVic { return expect_list_reserve_length(t, expect_assign(callback)); } - node_callback_t name_list_callback(std::vector& list); + node_callback_t name_list_callback(callback_t&&> callback); template callback_t expect_mapped_string(string_map_t const& map, callback_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 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 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 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..cbf5bfd 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 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 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&& 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; + 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 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 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; + 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 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 const& ProductionType::get_bonuses() { +std::vector const& ProductionType::get_bonuses() const { return bonuses; } -std::map 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 cb) { + callback_t 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> cb) { + callback_t&&> cb) { return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool { std::vector 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 input_goods, efficiency; + Good::good_map_t input_goods, efficiency; fixed_point_t value = 0; // 0 is a meaningless value -> unset std::vector 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 employees, ProductionType::type_t type, \ - Pop::pop_size_t workforce, std::map input_goods, Good const* output_goods, \ - fixed_point_t value, std::vector bonuses, std::map 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&& 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 input_goods; + const Good::good_map_t input_goods; Good const* output_goods; const fixed_point_t value; const std::vector bonuses; - const std::map 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 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 const& get_bonuses(); + std::vector const& get_bonuses() const; - std::map 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 production_types; NodeTools::node_callback_t _expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager, - NodeTools::callback_t cb); + NodeTools::callback_t cb); NodeTools::node_callback_t _expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager, - NodeTools::callback_t> cb); + NodeTools::callback_t&&> 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(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 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..017b220 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -125,11 +125,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/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 -#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 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 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> 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 build_cost, supply_cost; + Good::good_map_t build_cost, supply_cost; + using enum Unit::type_t; + static const string_map_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(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 build_cost, fixed_point_t supply_consumption, \ - std::map 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 build_cost; + const Good::good_map_t build_cost; const fixed_point_t supply_consumption; - const std::map 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 const& get_build_cost() const; + Good::good_map_t const& get_build_cost() const; fixed_point_t get_supply_consumption() const; - std::map 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 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&& 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 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&& 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 const& new_first_names, std::vector const& new_last_names) + std::vector&& new_first_names, std::vector&& 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 const& first_names, std::vector const& last_names) { +bool CultureManager::add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector&& first_names, std::vector&& 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 const& new_first_names, std::vector const& new_last_names); + Culture(std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, std::vector&& new_first_names, std::vector&& 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 const& first_names, std::vector const& last_names); + bool add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector&& first_names, std::vector&& 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..b2f52b2 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -68,9 +68,40 @@ namespace OpenVic { HasIdentifierAndColour& operator=(HasIdentifierAndColour&&) = delete; }; - using distribution_t = std::map; + template + using decimal_map_t = std::map; + + template + constexpr typename decimal_map_t::value_type get_largest_item(decimal_map_t const& map) { + constexpr auto pred = [](typename decimal_map_t::value_type a, typename decimal_map_t::value_type b) -> bool { + return a.second < b.second; + }; + const typename decimal_map_t::const_iterator result = std::max_element( + map.begin(), map.end(), pred + ); + if (result != map.end()) { + return *result; + } else { + return { nullptr, -1 }; + } + } - distribution_t::value_type get_largest_item(distribution_t const& dist); + using distribution_t = decimal_map_t; + + /* 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; + } template using get_identifier_func_t = std::string_view(T::*)(void) const; @@ -96,7 +127,7 @@ namespace OpenVic { return name; } - bool add_item(storage_type&& item, bool fail_on_duplicate = true) { + bool add_item(storage_type&& item, NodeTools::callback_t duplicate_callback = duplicate_fail_callback) { if (locked) { Logger::error("Cannot add item to the ", name, " registry - locked!"); return false; @@ -105,15 +136,7 @@ namespace OpenVic { const std::string_view new_identifier = (new_item->*get_identifier)(); 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)); @@ -234,9 +257,9 @@ namespace OpenVic { }); } - NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t&&> callback) const { + NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t&&> callback) const { return [this, callback](ast::NodeCPtr node) -> bool { - std::map map; + decimal_map_t 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); @@ -296,7 +319,7 @@ namespace OpenVic { return plural.expect_item_identifier(callback); } \ NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t callback) const { \ return plural.expect_item_dictionary(callback); } \ - NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t&&> callback) const { \ + NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t&&> 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.hpp b/src/openvic-simulation/utility/Logger.hpp index 55e0862..11cada5 100644 --- a/src/openvic-simulation/utility/Logger.hpp +++ b/src/openvic-simulation/utility/Logger.hpp @@ -63,21 +63,21 @@ namespace OpenVic { } }; -#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 \ - struct name { \ - name(Ts&&... ts, source_location const& location = source_location::current()) { \ - log{ name##_func, name##_queue, std::forward(ts)..., location }; \ - } \ - }; \ - template \ +#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 \ + struct name { \ + name(Ts&&... ts, source_location const& location = source_location::current()) { \ + log{ name##_func, name##_queue, std::forward(ts)..., location }; \ + } \ + }; \ + template \ name(Ts&&...) -> name; LOG_FUNC(info) -- cgit v1.2.3-56-ga3b1 From d26f9c2fb5a9666822a0f702d76b764600a390d7 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 13 Oct 2023 22:04:12 +0100 Subject: Further CLI and modifier reading work --- src/headless/main.cpp | 80 +++++----- src/openvic-simulation/Modifier.cpp | 64 ++++++-- src/openvic-simulation/Modifier.hpp | 18 +++ src/openvic-simulation/dataloader/Dataloader.cpp | 4 +- src/openvic-simulation/economy/Building.hpp | 2 +- src/openvic-simulation/map/TerrainType.cpp | 8 +- src/openvic-simulation/map/TerrainType.hpp | 4 +- .../types/IdentifierRegistry.hpp | 162 ++++++++++----------- src/openvic-simulation/utility/Logger.cpp | 16 +- src/openvic-simulation/utility/Logger.hpp | 33 +++-- 10 files changed, 220 insertions(+), 171 deletions(-) (limited to 'src/openvic-simulation') diff --git a/src/headless/main.cpp b/src/headless/main.cpp index e15005b..6cb6661 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -7,36 +7,17 @@ using namespace OpenVic; -static char const* get_program_name(char const* name) { - static constexpr char const* missing_name = ""; - 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(char const* program_name) { - std::cout +static void print_help(std::ostream& stream, char const* program_name) { + stream << "Usage: " << program_name << " [-h] [-t] [-b ] [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 void setup_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; }); -} - static bool headless_load(GameManager& game_manager, Dataloader const& dataloader) { bool ret = true; @@ -63,8 +44,6 @@ static bool headless_load(GameManager& game_manager, Dataloader const& dataloade static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) { bool ret = true; - setup_logger_funcs(); - Dataloader dataloader; if (!dataloader.set_roots(roots)) { Logger::error("Failed to set dataloader roots!"); @@ -93,36 +72,51 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) */ int main(int argc, char const* argv[]) { - char const* program_name = get_program_name(argc > 0 ? argv[0] : nullptr); + Logger::set_logger_funcs(); + char const* program_name = Logger::get_filename(argc > 0 ? argv[0] : nullptr, ""); 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(program_name); + print_help(std::cout, program_name); return 0; } else if (strcmp(arg, "-t") == 0) { run_tests = true; } else if (strcmp(arg, "-b") == 0) { - if (root.empty()) { - if (++argn < argc) { - root = argv[argn]; - if (!root.empty()) { - continue; - } else { - std::cerr << "Empty path after base directory command line argument \"-b\"." << std::endl; - } - } else { - std::cerr << "Missing path after base directory command line argument \"-b\"." << std::endl; - } - } else { - std::cerr << "Duplicate base directory command line argument \"-b\"." << std::endl; + 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; } - print_help(program_name); - return -1; } else { break; } @@ -131,7 +125,7 @@ int main(int argc, char const* argv[]) { root = Dataloader::search_for_game_path(); if (root.empty()) { std::cerr << "Search for base directory path failed!" << std::endl; - print_help(program_name); + print_help(std::cerr, program_name); return -1; } } diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp index 1273fdd..fc5dcaf 100644 --- a/src/openvic-simulation/Modifier.cpp +++ b/src/openvic-simulation/Modifier.cpp @@ -154,38 +154,72 @@ bool ModifierManager::setup_modifier_effects() { 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 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 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 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 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 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 modifier_callback, std::set> 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 modifier_callback, std::set> 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 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 663d359..0801aa5 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { @@ -92,12 +94,20 @@ namespace OpenVic { Date const& get_expiry_date() const; }; + template + concept ModifierEffectValidator = std::predicate; + struct ModifierManager { private: IdentifierRegistry modifier_effects; IdentifierRegistry 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(); @@ -109,9 +119,17 @@ namespace OpenVic { bool setup_modifier_effects(); + NodeTools::node_callback_t expect_validated_modifier_value_and_default(NodeTools::callback_t 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 modifier_callback, + ModifierEffectValidator auto effect_validator) const; + NodeTools::node_callback_t expect_modifier_value_and_default(NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback) const; NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; + NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default(NodeTools::callback_t modifier_callback, std::set> const& whitelist, NodeTools::key_value_callback_t default_callback) const; + NodeTools::node_callback_t expect_whitelisted_modifier_value(NodeTools::callback_t modifier_callback, std::set> const& whitelist) const; + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default(NodeTools::callback_t 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 modifier_callback, NodeTools::key_map_t&& key_map) const; diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 5134054..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 -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) left = lhs.filename().string(); else left = lhs; diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp index cbf5bfd..b56c9a2 100644 --- a/src/openvic-simulation/economy/Building.hpp +++ b/src/openvic-simulation/economy/Building.hpp @@ -32,7 +32,7 @@ namespace OpenVic { private: BuildingType const& type; - ModifierValue modifier; + const ModifierValue modifier; const std::string on_completion; //probably sound played on completion const fixed_point_t completion_size; const level_t max_level; diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index 017b220..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; 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/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index b2f52b2..1a03e75 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -103,11 +103,10 @@ namespace OpenVic { return true; } - template - using get_identifier_func_t = std::string_view(T::*)(void) const; - - template _Type, get_identifier_func_t<_Base> get_identifier, - typename _Storage, _Type* (*get_ptr)(_Storage&), _Type const* (*get_cptr)(_Storage const&)> + /* _GetIdentifier - takes _Type const* and returns std::string_view + * _GetPointer - takes _Storage [const]& and returns T [const]* + */ + template class UniqueKeyRegistry { const std::string name; @@ -116,12 +115,15 @@ namespace OpenVic { bool locked = false; string_map_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; @@ -132,8 +134,7 @@ namespace OpenVic { 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) { return duplicate_callback(name, new_identifier); @@ -178,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 expect_item_identifier(NodeTools::callback_t 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 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; } @@ -217,46 +235,6 @@ namespace OpenVic { return identifiers; } - NodeTools::callback_t expect_item_identifier(NodeTools::callback_t 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 expect_item_identifier(NodeTools::callback_t 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 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 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&&> callback) const { return [this, callback](ast::NodeCPtr node) -> bool { decimal_map_t map; @@ -272,35 +250,47 @@ namespace OpenVic { } }; + /* Standard value storage */ template - [[nodiscard]] inline constexpr T* _addressof(T& v) noexcept { - return std::addressof(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 + using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>>; + + /* std::unique_ptr dynamic storage */ template - const T* _addressof(const T&&) = delete; + struct _uptr_get { + constexpr T* operator()(std::unique_ptr& item) const { + return item.get(); + } + constexpr T const* operator()(std::unique_ptr const& item) const { + return item.get(); + } + }; - template _Type, get_identifier_func_t<_Base> get_identifier> - using ValueRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, _Type, _addressof<_Type>, _addressof>; + template + using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>>; - template - constexpr _Type* get_ptr(std::unique_ptr<_Type>& storage) { - return storage.get(); - } - template - constexpr _Type const* get_cptr(std::unique_ptr<_Type> const& storage) { - return storage.get(); - } - - template _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 T> + struct _get_identifier { + constexpr std::string_view operator()(T const* item) const { + return item->get_identifier(); + } + }; template _Type> - using IdentifierRegistry = ValueRegistry; + using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>>; template _Type> - using IdentifierInstanceRegistry = InstanceRegistry; + using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>>; #define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ void lock_##plural() { plural.lock(); } \ 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 11cada5..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; using log_queue_t = std::queue; @@ -42,39 +42,46 @@ 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 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)), ...); 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; \ + static inline log_channel_t name##_channel{}; \ public: \ - static void set_##name##_func(log_func_t log_func) { \ - name##_func = log_func; \ + static inline void set_##name##_func(log_func_t log_func) { \ + name##_channel.func = log_func; \ } \ template \ struct name { \ name(Ts&&... ts, source_location const& location = source_location::current()) { \ - log{ name##_func, name##_queue, std::forward(ts)..., location }; \ + log{ name##_channel, std::forward(ts)..., location }; \ } \ }; \ template \ -- cgit v1.2.3-56-ga3b1