diff options
author | hop311 <hop3114@gmail.com> | 2023-10-12 21:19:00 +0200 |
---|---|---|
committer | hop311 <hop3114@gmail.com> | 2023-10-12 21:19:00 +0200 |
commit | e50c67eb1aaa54f5fb31425f81616bea4e6b880a (patch) | |
tree | c4fbc6ee494f8ad33a8de36be5fc300165ce05fc | |
parent | bb22324da1225a0ac458c1d69893bb3bd28bd6b7 (diff) |
Lots of accumulated changes
36 files changed, 634 insertions, 491 deletions
diff --git a/deps/openvic-dataloader b/deps/openvic-dataloader -Subproject 92961412af3ae908633b4ef7b8453091448ffd4 +Subproject 4009e1d576ad177aff59c8fce0339963303fc6e diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp index 3acfa56..5aadd79 100644 --- a/src/openvic-simulation/Modifier.cpp +++ b/src/openvic-simulation/Modifier.cpp @@ -157,7 +157,7 @@ node_callback_t ModifierManager::expect_modifier_value(callback_t<ModifierValue& node_callback_t ModifierManager::_expect_modifier_value_and_keys(callback_t<ModifierValue&&> modifier_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( - modifier_callback, dictionary_keys_callback(key_map, false) + modifier_callback, dictionary_keys_callback(key_map, key_value_invalid_callback) )(node); ret &= check_key_map_counts(key_map); return ret; diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp index f88102b..0c4e636 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -107,10 +107,10 @@ namespace OpenVic { ModifierManager(); bool add_modifier_effect(std::string_view identifier, bool province_good); - IDENTIFIER_REGISTRY_ACCESSORS(ModifierEffect, modifier_effect) + IDENTIFIER_REGISTRY_ACCESSORS(modifier_effect) bool add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon); - IDENTIFIER_REGISTRY_ACCESSORS(Modifier, modifier) + IDENTIFIER_REGISTRY_ACCESSORS(modifier) bool setup_modifier_effects(); diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 70164c3..bd634ce 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -381,7 +381,10 @@ Dataloader::path_vector_t Dataloader::lookup_files_in_dir(fs::path const& path, bool Dataloader::apply_to_files_in_dir(fs::path const& path, fs::path const& extension, callback_t<fs::path const&> callback) const { bool ret = true; for (fs::path const& file : lookup_files_in_dir(path, extension)) { - ret &= callback(file); + if (!callback(file)) { + Logger::error("Callback failed for file: ", file); + ret = false; + } } return ret; } @@ -441,12 +444,6 @@ csv::Windows1252Parser Dataloader::parse_csv(fs::path const& path) { return _run_ovdl_parser<csv::Windows1252Parser, &_csv_parse>(path); } -static callback_t<fs::path const&> _parse_defines_callback(node_callback_t callback) { - return [callback](fs::path const& path) -> bool { - return callback(Dataloader::parse_defines(path).get_file_node()); - }; -} - bool Dataloader::_load_pop_types(PopManager& pop_manager, fs::path const& pop_type_directory) const { const bool ret = apply_to_files_in_dir(pop_type_directory, ".txt", [&pop_manager](fs::path const& file) -> bool { @@ -457,13 +454,13 @@ bool Dataloader::_load_pop_types(PopManager& pop_manager, fs::path const& pop_ty return ret; } -bool Dataloader::_load_units(GameManager& game_manager, fs::path const& units_directory) const { +bool Dataloader::_load_units(UnitManager& unit_manager, GoodManager const& good_manager, fs::path const& units_directory) const { const bool ret = apply_to_files_in_dir(units_directory, ".txt", - [&game_manager](fs::path const& file) -> bool { - return game_manager.get_unit_manager().load_unit_file(game_manager.get_good_manager(), parse_defines(file).get_file_node()); + [&unit_manager, &good_manager](fs::path const& file) -> bool { + return unit_manager.load_unit_file(good_manager, parse_defines(file).get_file_node()); } ); - game_manager.get_unit_manager().lock_units(); + unit_manager.lock_units(); return ret; } @@ -499,15 +496,8 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di bool ret = expect_dictionary_keys( "max_provinces", ONE_EXACTLY, - expect_uint( - [&map](uint64_t val) -> bool { - if (Province::NULL_INDEX < val && val <= Province::MAX_INDEX) { - return map.set_max_provinces(val); - } - Logger::error("Invalid max province count ", val, " (out of valid range ", - Province::NULL_INDEX, " < max_provinces <= ", Province::MAX_INDEX, ")"); - return false; - } + expect_uint<Province::index_t>( + std::bind(&Map::set_max_provinces, &map, std::placeholders::_1) ), "sea_starts", ONE_EXACTLY, expect_list_reserve_length( @@ -556,7 +546,6 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di Logger::error("Failed to set water provinces!"); ret = false; } - map.lock_water_provinces(); if (!map.get_terrain_type_manager().load_terrain_types(game_manager.get_modifier_manager(), parse_defines(lookup_file(map_directory / terrain_definition)).get_file_node())) { Logger::error("Failed to load terrain types!"); @@ -648,7 +637,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load map!"); ret = false; } - if (!_load_units(game_manager, units_directory)) { + if (!_load_units(game_manager.get_unit_manager(), game_manager.get_good_manager(), units_directory)) { Logger::error("Failed to load units!"); ret = false; } @@ -659,11 +648,11 @@ bool Dataloader::load_defines(GameManager& game_manager) const { bool Dataloader::load_pop_history(GameManager& game_manager, fs::path const& path) const { return apply_to_files_in_dir(path, ".txt", [&game_manager](fs::path const& file) -> bool { - return _parse_defines_callback(game_manager.get_map().expect_province_dictionary( + return game_manager.get_map().expect_province_dictionary( [&game_manager](Province& province, ast::NodeCPtr value) -> bool { return province.load_pop_list(game_manager.get_pop_manager(), value); } - ))(file); + )(parse_defines(file).get_file_node()); } ); } diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index 705da00..30eed6e 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -13,7 +13,8 @@ namespace OpenVic { struct GameManager; struct PopManager; - struct Map; + struct UnitManager; + struct GoodManager; class Dataloader { public: @@ -23,7 +24,7 @@ namespace OpenVic { path_vector_t roots; bool _load_pop_types(PopManager& pop_manager, fs::path const& pop_type_directory) const; - bool _load_units(GameManager& unit_manager, fs::path const& units_directory) const; + bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager, fs::path const& units_directory) const; bool _load_map_dir(GameManager& game_manager, fs::path const& map_directory) const; public: @@ -89,5 +90,3 @@ namespace OpenVic { inline static std::unordered_map<hint_path_t, game_path_t, fshash> _cached_paths; }; } - - diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index 5ef09d1..391ffb6 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -19,20 +19,28 @@ static node_callback_t _expect_type(callback_t<T const&> callback) { }; } -template<typename T> -requires(std::derived_from<T, ast::AbstractStringNode>) -static callback_t<T const&> _abstract_string_node_callback(callback_t<std::string_view> callback) { - return [callback](T const& node) -> bool { - return callback(node._name); +template<std::derived_from<ast::AbstractStringNode> T> +static callback_t<T const&> _abstract_string_node_callback(callback_t<std::string_view> callback, bool allow_empty) { + return [callback, allow_empty](T const& node) -> bool { + if (allow_empty) { + return callback(node._name); + } else { + if (!node._name.empty()) { + return callback(node._name); + } else { + Logger::error("Invalid string value - empty!"); + return false; + } + } }; } node_callback_t NodeTools::expect_identifier(callback_t<std::string_view> callback) { - return _expect_type<ast::IdentifierNode>(_abstract_string_node_callback<ast::IdentifierNode>(callback)); + return _expect_type<ast::IdentifierNode>(_abstract_string_node_callback<ast::IdentifierNode>(callback, false)); } -node_callback_t NodeTools::expect_string(callback_t<std::string_view> callback) { - return _expect_type<ast::StringNode>(_abstract_string_node_callback<ast::StringNode>(callback)); +node_callback_t NodeTools::expect_string(callback_t<std::string_view> callback, bool allow_empty) { + return _expect_type<ast::StringNode>(_abstract_string_node_callback<ast::StringNode>(callback, allow_empty)); } node_callback_t NodeTools::expect_identifier_or_string(callback_t<std::string_view> callback) { @@ -43,7 +51,7 @@ node_callback_t NodeTools::expect_identifier_or_string(callback_t<std::string_vi cast_node = node->cast_to<ast::StringNode>(); } if (cast_node != nullptr) { - return _abstract_string_node_callback<ast::AbstractStringNode>(callback)(*cast_node); + return _abstract_string_node_callback<ast::AbstractStringNode>(callback, false)(*cast_node); } Logger::error("Invalid node type ", node->get_type(), " when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static()); } else { @@ -54,20 +62,20 @@ node_callback_t NodeTools::expect_identifier_or_string(callback_t<std::string_vi } node_callback_t NodeTools::expect_bool(callback_t<bool> callback) { - return expect_identifier( - [callback](std::string_view identifier) -> bool { - if (identifier == "yes") { - return callback(true); - } else if (identifier == "no") { - return callback(false); - } - Logger::error("Invalid bool identifier text: ", identifier); - return false; - } - ); + static const string_map_t<bool> bool_map = { + { "yes", true }, { "no", false } + }; + return expect_identifier(expect_mapped_string(bool_map, callback)); +} + +node_callback_t NodeTools::expect_int_bool(callback_t<bool> callback) { + static const string_map_t<bool> bool_map = { + { "1", true }, { "0", false } + }; + return expect_identifier(expect_mapped_string(bool_map, callback)); } -node_callback_t NodeTools::expect_int(callback_t<int64_t> callback) { +node_callback_t NodeTools::expect_int64(callback_t<int64_t> callback) { return expect_identifier( [callback](std::string_view identifier) -> bool { bool successful = false; @@ -81,7 +89,7 @@ node_callback_t NodeTools::expect_int(callback_t<int64_t> callback) { ); } -node_callback_t NodeTools::expect_uint(callback_t<uint64_t> callback) { +node_callback_t NodeTools::expect_uint64(callback_t<uint64_t> callback) { return expect_identifier( [callback](std::string_view identifier) -> bool { bool successful = false; @@ -134,10 +142,6 @@ node_callback_t NodeTools::expect_colour(callback_t<colour_t> callback) { }; } -node_callback_t NodeTools::expect_timespan(callback_t<Timespan> callback) { - return expect_int(callback); -} - node_callback_t NodeTools::expect_date(callback_t<Date> callback) { return expect_identifier( [callback](std::string_view identifier) -> bool { @@ -152,6 +156,24 @@ node_callback_t NodeTools::expect_date(callback_t<Date> callback) { ); } +node_callback_t NodeTools::expect_years(callback_t<Timespan> callback) { + return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return callback(Timespan::fromYears(val)); + }); +} + +node_callback_t NodeTools::expect_months(callback_t<Timespan> callback) { + return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return callback(Timespan::fromMonths(val)); + }); +} + +node_callback_t NodeTools::expect_days(callback_t<Timespan> callback) { + return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return callback(Timespan::fromDays(val)); + }); +} + template<typename T, node_callback_t (*expect_func)(callback_t<T>)> node_callback_t _expect_vec2(callback_t<vec2_t<T>> callback) { return [callback](ast::NodeCPtr node) -> bool { @@ -166,7 +188,7 @@ node_callback_t _expect_vec2(callback_t<vec2_t<T>> callback) { } node_callback_t NodeTools::expect_ivec2(callback_t<ivec2_t> callback) { - return _expect_vec2<int64_t, expect_int>(callback); + return _expect_vec2<int32_t, expect_int>(callback); } node_callback_t NodeTools::expect_fvec2(callback_t<fvec2_t> callback) { @@ -238,17 +260,24 @@ node_callback_t NodeTools::expect_length(callback_t<size_t> callback) { }; } -node_callback_t NodeTools::expect_key(std::string_view key, node_callback_t callback) { +node_callback_t NodeTools::expect_key(std::string_view key, node_callback_t callback, bool* key_found) { return _expect_type<ast::AbstractListNode>( - [key, callback](ast::AbstractListNode const& list_node) -> bool { + [key, callback, key_found](ast::AbstractListNode const& list_node) -> bool { std::vector<ast::NodeUPtr> const& list = list_node._statements; for (ast::NodeUPtr const& sub_node : list_node._statements) { ast::AssignNode const* assign_node = sub_node->cast_to<ast::AssignNode>(); if (assign_node != nullptr && assign_node->_name == key) { + if (key_found != nullptr) { + *key_found = true; + } return callback(&*assign_node->_initializer); } } - Logger::error("Failed to find expected key: ", key); + if (key_found != nullptr) { + *key_found = false; + } else { + Logger::error("Failed to find expected key: ", key); + } return false; } ); @@ -262,21 +291,30 @@ node_callback_t NodeTools::expect_dictionary(key_value_callback_t callback) { return expect_dictionary_and_length(default_length_callback, callback); } -void NodeTools::add_key_map_entry(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback) { +bool NodeTools::add_key_map_entry(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback) { if (key_map.find(key) == key_map.end()) { key_map.emplace(key, dictionary_entry_t { expected_count, callback }); - } else { - Logger::error("Duplicate expected dictionary key: ", key); + return true; + } + Logger::error("Duplicate expected dictionary key: ", key); + return false; +} + +bool NodeTools::remove_key_map_entry(key_map_t& key_map, std::string_view key) { + const key_map_t::const_iterator it = key_map.find(key); + if (it != key_map.end()) { + key_map.erase(it); + return true; } + Logger::error("Failed to find dictionary key to remove: ", key); + return false; } -key_value_callback_t NodeTools::dictionary_keys_callback(key_map_t& key_map, bool allow_other_keys) { - return [&key_map, allow_other_keys](std::string_view key, ast::NodeCPtr value) -> bool { +key_value_callback_t NodeTools::dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback) { + return [&key_map, default_callback](std::string_view key, ast::NodeCPtr value) -> bool { const key_map_t::iterator it = key_map.find(key); if (it == key_map.end()) { - if (allow_other_keys) return true; - Logger::error("Invalid dictionary key: ", key); - return false; + return default_callback(key, value); } dictionary_entry_t& entry = it->second; if (++entry.count > 1 && !entry.can_repeat()) { @@ -300,16 +338,28 @@ bool NodeTools::check_key_map_counts(key_map_t& key_map) { return ret; } -node_callback_t NodeTools::_expect_dictionary_keys_and_length(length_callback_t length_callback, bool allow_other_keys, key_map_t&& key_map) { - return [length_callback, allow_other_keys, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { +node_callback_t NodeTools::expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback) { + return [length_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { bool ret = expect_dictionary_and_length( - length_callback, dictionary_keys_callback(key_map, allow_other_keys) + length_callback, dictionary_keys_callback(key_map, default_callback) )(node); ret &= check_key_map_counts(key_map); return ret; }; } +node_callback_t NodeTools::expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback) { + return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, key_value_invalid_callback); +} + +node_callback_t NodeTools::expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback) { + return expect_dictionary_key_map_and_length_and_default(std::move(key_map), default_length_callback, default_callback); +} + +node_callback_t NodeTools::expect_dictionary_key_map(key_map_t key_map) { + return expect_dictionary_key_map_and_length_and_default(std::move(key_map), default_length_callback, key_value_invalid_callback); +} + node_callback_t NodeTools::name_list_callback(std::vector<std::string>& list) { return expect_list_reserve_length( list, @@ -325,3 +375,7 @@ node_callback_t NodeTools::name_list_callback(std::vector<std::string>& list) { ) ); } + +callback_t<std::string_view> NodeTools::assign_variable_callback_string(std::string& var) { + return assign_variable_callback_cast<std::string_view>(var); +} diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 5ba9d63..44ac271 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -11,6 +11,11 @@ namespace OpenVic { namespace ast = ovdl::v2script::ast; + /* Template for map from strings to Ts, in which string_views can be + * searched for without needing to be copied into a string, */ + template<typename T> + using string_map_t = std::map<std::string, T, std::less<void>>; + namespace NodeTools { template<typename... Args> @@ -21,17 +26,55 @@ namespace OpenVic { using key_value_callback_t = callback_t<std::string_view, ast::NodeCPtr>; constexpr bool key_value_success_callback(std::string_view, ast::NodeCPtr) { return true; } + inline bool key_value_invalid_callback(std::string_view key, ast::NodeCPtr) { + Logger::error("Invalid dictionary key: ", key); + return false; + } node_callback_t expect_identifier(callback_t<std::string_view> callback); - node_callback_t expect_string(callback_t<std::string_view> callback); + node_callback_t expect_string(callback_t<std::string_view> callback, bool allow_empty = true); node_callback_t expect_identifier_or_string(callback_t<std::string_view> callback); + node_callback_t expect_bool(callback_t<bool> callback); - node_callback_t expect_int(callback_t<int64_t> callback); - node_callback_t expect_uint(callback_t<uint64_t> callback); + node_callback_t expect_int_bool(callback_t<bool> callback); + + node_callback_t expect_int64(callback_t<int64_t> callback); + node_callback_t expect_uint64(callback_t<uint64_t> callback); + + template<std::signed_integral T> + node_callback_t expect_int(callback_t<T> callback) { + return expect_int64([callback](int64_t val) -> bool { + if (static_cast<int64_t>(std::numeric_limits<T>::lowest()) <= val && + val <= static_cast<int64_t>(std::numeric_limits<T>::max())) { + return callback(val); + } + Logger::error("Invalid int: ", val, " (valid range: [", + static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ", + static_cast<int64_t>(std::numeric_limits<T>::max()), "])"); + return false; + }); + } + + template<std::integral T> + node_callback_t expect_uint(callback_t<T> callback) { + return expect_uint64([callback](uint64_t val) -> bool { + if (val <= static_cast<uint64_t>(std::numeric_limits<T>::max())) { + return callback(val); + } + Logger::error("Invalid uint: ", val, " (valid range: [0, ", + static_cast<uint64_t>(std::numeric_limits<T>::max()), "])"); + return false; + }); + } + node_callback_t expect_fixed_point(callback_t<fixed_point_t> callback); node_callback_t expect_colour(callback_t<colour_t> callback); - node_callback_t expect_timespan(callback_t<Timespan> callback); + node_callback_t expect_date(callback_t<Date> callback); + node_callback_t expect_years(callback_t<Timespan> callback); + node_callback_t expect_months(callback_t<Timespan> callback); + node_callback_t expect_days(callback_t<Timespan> callback); + node_callback_t expect_ivec2(callback_t<ivec2_t> callback); node_callback_t expect_fvec2(callback_t<fvec2_t> callback); node_callback_t expect_assign(key_value_callback_t callback); @@ -44,7 +87,7 @@ namespace OpenVic { node_callback_t expect_list(node_callback_t callback); node_callback_t expect_length(callback_t<size_t> callback); - node_callback_t expect_key(std::string_view key, node_callback_t callback); + node_callback_t expect_key(std::string_view key, node_callback_t callback, bool* key_found = nullptr); node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback); node_callback_t expect_dictionary(key_value_callback_t callback); @@ -73,41 +116,45 @@ namespace OpenVic { } }; using enum dictionary_entry_t::expected_count_t; - using key_map_t = std::map<std::string, dictionary_entry_t, std::less<void>>; + using key_map_t = string_map_t<dictionary_entry_t>; - void add_key_map_entry(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback); - key_value_callback_t dictionary_keys_callback(key_map_t& key_map, bool allow_other_keys); + bool add_key_map_entry(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback); + bool remove_key_map_entry(key_map_t& key_map, std::string_view key); + 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 struct allow_other_keys_t {} ALLOW_OTHER_KEYS; - - node_callback_t _expect_dictionary_keys_and_length(length_callback_t length_callback, bool allow_other_keys, key_map_t&& key_map); + node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback); + node_callback_t expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback); + node_callback_t expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback); + node_callback_t expect_dictionary_key_map(key_map_t key_map); template<typename... Args> - node_callback_t _expect_dictionary_keys_and_length(length_callback_t length_callback, - bool allow_other_keys, key_map_t&& key_map, + 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) { + // 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_keys_and_length(length_callback, allow_other_keys, std::move(key_map), args...); + return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback, args...); } template<typename... Args> - node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback, - std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback, - Args... args) { - return _expect_dictionary_keys_and_length(length_callback, false, {}, key, expected_count, callback, args...); + node_callback_t expect_dictionary_keys_and_length_and_default(length_callback_t length_callback, key_value_callback_t default_callback, Args... args) { + return expect_dictionary_key_map_and_length_and_default({}, length_callback, default_callback, args...); } template<typename... Args> - node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback, - allow_other_keys_t, Args... args) { - return _expect_dictionary_keys_and_length(length_callback, true, {}, args...); + node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback, Args... args) { + return expect_dictionary_key_map_and_length_and_default({}, length_callback, key_value_invalid_callback, args...); + } + + template<typename... Args> + node_callback_t expect_dictionary_keys_and_default(key_value_callback_t default_callback, Args... args) { + return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, default_callback, args...); } template<typename... Args> node_callback_t expect_dictionary_keys(Args... args) { - return expect_dictionary_keys_and_length(default_length_callback, args...); + return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, key_value_invalid_callback, args...); } template<typename T> @@ -133,7 +180,19 @@ namespace OpenVic { node_callback_t name_list_callback(std::vector<std::string>& list); template<typename T> - callback_t<T> assign_variable_callback(T& var) { + callback_t<std::string_view> expect_mapped_string(string_map_t<T> const& map, callback_t<T> callback) { + return [&map, callback](std::string_view string) -> bool { + const typename string_map_t<T>::const_iterator it = map.find(string); + if (it != map.end()) { + return callback(it->second); + } + Logger::error("String not found in map: ", string); + return false; + }; + } + + template<typename T, typename U> + callback_t<T> assign_variable_callback_cast(U& var) { return [&var](T val) -> bool { var = val; return true; @@ -141,6 +200,13 @@ namespace OpenVic { } template<typename T> + callback_t<T> assign_variable_callback(T& var) { + return assign_variable_callback_cast<T, T>(var); + } + + callback_t<std::string_view> assign_variable_callback_string(std::string& var); + + template<typename T> callback_t<T&&> move_variable_callback(T& var) { return [&var](T&& val) -> bool { var = std::move(val); @@ -161,41 +227,12 @@ namespace OpenVic { template<typename T> requires requires(T& t) { - t--; - } - node_callback_t decrement_callback(T& var, node_callback_t callback) { - return [&var, callback](ast::NodeCPtr node) -> bool { - var--; - return callback(node); - }; - } - - template<typename T> - requires(std::integral<T>) - callback_t<uint64_t> assign_variable_callback_uint(T& var) { - return [&var](uint64_t val) -> bool { - if (val <= static_cast<uint64_t>(std::numeric_limits<T>::max())) { - var = val; - return true; - } - Logger::error("Invalid uint: ", val, " (valid range: [0, ", - static_cast<uint64_t>(std::numeric_limits<T>::max()), "])"); - return false; - }; + t++; } - - template<typename T> - requires(std::signed_integral<T>) - callback_t<int64_t> assign_variable_callback_int(T& var) { - return [&var](int64_t val) -> bool { - if (static_cast<int64_t>(std::numeric_limits<T>::lowest()) <= val && val <= static_cast<int64_t>(std::numeric_limits<T>::max())) { - var = val; - return true; - } - Logger::error("Invalid int: ", val, " (valid range: [", - static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ", - static_cast<int64_t>(std::numeric_limits<T>::max()), "])"); - return false; + key_value_callback_t increment_callback(T& var) { + return [&var](std::string_view, ast::NodeCPtr) -> bool { + var++; + return true; }; } diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp index 7f020fe..1dce41f 100644 --- a/src/openvic-simulation/economy/Good.hpp +++ b/src/openvic-simulation/economy/Good.hpp @@ -66,11 +66,11 @@ namespace OpenVic { GoodManager(); bool add_good_category(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(GoodCategory, good_category, good_categories) + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(good_category, good_categories) bool add_good(std::string_view identifier, colour_t colour, GoodCategory const* category, Good::price_t base_price, bool available_from_start, bool tradeable, bool money, bool overseas_penalty); - IDENTIFIER_REGISTRY_ACCESSORS(Good, good) + IDENTIFIER_REGISTRY_ACCESSORS(good) void reset_to_defaults(); bool load_goods_file(ast::NodeCPtr root); diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp index 2c7c431..b2d94c3 100644 --- a/src/openvic-simulation/economy/ProductionType.cpp +++ b/src/openvic-simulation/economy/ProductionType.cpp @@ -82,16 +82,22 @@ bool ProductionType::is_mine() const { ProductionTypeManager::ProductionTypeManager() : production_types { "production types" } {} -node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager, +node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager, callback_t<EmployedPop> cb) { return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool { - std::string_view pop_type, effect; + std::string_view pop_type; + EmployedPop::effect_t effect; fixed_point_t effect_multiplier = 1, amount = 1; + using enum EmployedPop::effect_t; + static const string_map_t<EmployedPop::effect_t> effect_map = { + { "input", INPUT }, { "output", OUTPUT }, { "throughput", THROUGHPUT } + }; + bool res = expect_dictionary_keys( "poptype", ONE_EXACTLY, expect_identifier(assign_variable_callback(pop_type)), - "effect", ONE_EXACTLY, expect_identifier(assign_variable_callback(effect)), + "effect", ONE_EXACTLY, expect_identifier(expect_mapped_string(effect_map, assign_variable_callback(effect))), "effect_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(effect_multiplier)), "amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(amount)) )(node); @@ -107,20 +113,11 @@ node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager& good_ma } } - EmployedPop::effect_t found_effect; - if (effect == "input") found_effect = EmployedPop::effect_t::INPUT; - else if (effect == "output") found_effect = EmployedPop::effect_t::OUTPUT; - else if (effect == "throughput") found_effect = EmployedPop::effect_t::THROUGHPUT; - else { - Logger::error("Found invalid effect ", effect, " while parsing production types!"); - return false; - } - - return res & cb(EmployedPop { found_pop_type, artisan, found_effect, effect_multiplier, amount }); + return res & cb(EmployedPop { found_pop_type, artisan, effect, effect_multiplier, amount }); }; } -node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager, +node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager, callback_t<std::vector<EmployedPop>> cb) { return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool { @@ -174,19 +171,20 @@ bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManage }); } -#define PARSE_NODE(target_node) expect_dictionary_keys(ALLOW_OTHER_KEYS, \ +#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(assign_variable_callback(type)), \ - "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(workforce)), \ + "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, good_manager.expect_good_identifier(assign_variable_callback_pointer(output_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)) \ - )(target_node) + ) bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root) { size_t expected_types = 0; @@ -196,25 +194,27 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager std::map<std::string_view, std::string_view> template_target_map; bool ret = expect_dictionary( [this, &expected_types, &templates, &template_target_map](std::string_view key, ast::NodeCPtr value) -> bool { - std::string_view template_id = ""; - bool ret = expect_dictionary_keys(ALLOW_OTHER_KEYS, - "template", ZERO_OR_ONE, expect_identifier(assign_variable_callback(template_id)) - )(value); - - if (!template_id.empty()) { - templates.emplace(template_id); - template_target_map.emplace(key, template_id); - } - expected_types++; - return ret; + std::string_view template_id = ""; + bool found_template = false; + const bool ret = expect_key("template", expect_identifier(assign_variable_callback(template_id)), &found_template)(value); + if (found_template) { + if (ret) { + templates.emplace(template_id); + template_target_map.emplace(key, template_id); + } else { + Logger::error("Failed get template identifier for ", key); + return false; + } + } + return true; } )(root); // pass 2: create and populate the template map std::map<std::string_view, ast::NodeCPtr> template_node_map; - expect_dictionary( + ret &= expect_dictionary( [this, &expected_types, &templates, &template_node_map](std::string_view key, ast::NodeCPtr value) -> bool { if (templates.contains(key)) { template_node_map.emplace(key, value); @@ -233,7 +233,7 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager EmployedPop owner; std::vector<EmployedPop> employees; - std::string_view type; + ProductionType::type_t type; Good const* output_goods = nullptr; Pop::pop_size_t workforce = 0; // 0 is a meaningless value -> unset std::map<Good const*, fixed_point_t> input_goods, efficiency; @@ -243,6 +243,11 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager bool ret = true; + using enum ProductionType::type_t; + static const string_map_t<ProductionType::type_t> type_map = { + { "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN } + }; + // apply template first if (template_target_map.contains(key)) { std::string_view template_id = template_target_map[key]; @@ -254,17 +259,8 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager ret &= PARSE_NODE(node); - ProductionType::type_t type_enum; - if (type == "factory") type_enum = ProductionType::type_t::FACTORY; - else if (type == "rgo") type_enum = ProductionType::type_t::RGO; - else if (type == "artisan") type_enum = ProductionType::type_t::ARTISAN; - else { - Logger::error("Invalid production type for ", key, ": ", type); - ret = false; - } - ret &= add_production_type( - key, owner, employees, type_enum, workforce, input_goods, output_goods, value, + key, owner, employees, type, workforce, input_goods, output_goods, value, bonuses, 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 755eda8..fdb0010 100644 --- a/src/openvic-simulation/economy/ProductionType.hpp +++ b/src/openvic-simulation/economy/ProductionType.hpp @@ -95,16 +95,16 @@ namespace OpenVic { private: IdentifierRegistry<ProductionType> production_types; - NodeTools::node_callback_t _expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager, + NodeTools::node_callback_t _expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<EmployedPop> cb); - NodeTools::node_callback_t _expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager, + NodeTools::node_callback_t _expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<std::vector<EmployedPop>> cb); public: ProductionTypeManager(); bool add_production_type(PRODUCTION_TYPE_ARGS, GoodManager& good_manager); - IDENTIFIER_REGISTRY_ACCESSORS(ProductionType, production_type) + IDENTIFIER_REGISTRY_ACCESSORS(production_type) bool load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/map/Building.cpp b/src/openvic-simulation/map/Building.cpp index 6f4c099..d27c91a 100644 --- a/src/openvic-simulation/map/Building.cpp +++ b/src/openvic-simulation/map/Building.cpp @@ -229,22 +229,22 @@ bool BuildingManager::load_buildings_file(GoodManager const& good_manager, Produ ModifierValue modifiers; bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifiers), - "type", ONE_EXACTLY, expect_building_type_identifier(assign_variable_callback_pointer(type)), + "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)), - "max_level", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(max_level)), + "max_level", ONE_EXACTLY, expect_uint(assign_variable_callback(max_level)), "goods_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(goods_cost)), "cost", ZERO_OR_MORE, expect_fixed_point(assign_variable_callback(cost)), - "time", ONE_EXACTLY, expect_timespan(assign_variable_callback(build_time)), + "time", ONE_EXACTLY, expect_days(assign_variable_callback(build_time)), "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, 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)), - "fort_level", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(fort_level)), - "naval_capacity", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(naval_capacity)), + "fort_level", ZERO_OR_ONE, expect_uint(assign_variable_callback(fort_level)), + "naval_capacity", ZERO_OR_ONE, expect_uint(assign_variable_callback(naval_capacity)), "colonial_points", ZERO_OR_ONE, expect_list(expect_fixed_point([&colonial_points](fixed_point_t points) -> bool { colonial_points.push_back(points); return true; diff --git a/src/openvic-simulation/map/Building.hpp b/src/openvic-simulation/map/Building.hpp index 9b445bf..3f74c3d 100644 --- a/src/openvic-simulation/map/Building.hpp +++ b/src/openvic-simulation/map/Building.hpp @@ -27,7 +27,7 @@ namespace OpenVic { struct Building : HasIdentifier, ModifierValue { friend struct BuildingManager; - using level_t = int8_t; + using level_t = int16_t; private: BuildingType const& type; @@ -162,10 +162,10 @@ namespace OpenVic { BuildingManager(); bool add_building_type(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(BuildingType, building_type) + IDENTIFIER_REGISTRY_ACCESSORS(building_type) bool add_building(std::string_view identifier, BuildingType const* type, ARGS); - IDENTIFIER_REGISTRY_ACCESSORS(Building, building) + IDENTIFIER_REGISTRY_ACCESSORS(building) bool load_buildings_file(GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 386e7be..8362ff4 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -78,11 +78,16 @@ bool Map::set_water_province(std::string_view identifier) { } bool Map::set_water_province_list(std::vector<std::string_view> const& list) { + if (water_provinces.is_locked()) { + Logger::error("The map's water provinces have already been locked!"); + return false; + } bool ret = true; water_provinces.reserve(water_provinces.size() + list.size()); for (std::string_view const& identifier : list) { ret &= set_water_province(identifier); } + lock_water_provinces(); return ret; } diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index 9c97960..a959158 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -70,8 +70,8 @@ namespace OpenVic { Map(); bool add_province(std::string_view identifier, colour_t colour); - IDENTIFIER_REGISTRY_ACCESSORS(Province, province) - IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Province, province) + IDENTIFIER_REGISTRY_ACCESSORS(province) + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(province) bool set_water_province(std::string_view identifier); bool set_water_province_list(std::vector<std::string_view> const& list); @@ -93,11 +93,11 @@ namespace OpenVic { TerrainTypeManager const& get_terrain_type_manager() const; bool add_region(std::string_view identifier, std::vector<std::string_view> const& province_identifiers); - IDENTIFIER_REGISTRY_ACCESSORS(Region, region) - IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Region, region) + IDENTIFIER_REGISTRY_ACCESSORS(region) + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(region) bool add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func); - IDENTIFIER_REGISTRY_ACCESSORS(Mapmode, mapmode) + IDENTIFIER_REGISTRY_ACCESSORS(mapmode) Mapmode const* get_mapmode_by_index(size_t index) const; static constexpr size_t MAPMODE_COLOUR_SIZE = 4; bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 31b5d4c..c9b29ea 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -93,7 +93,7 @@ namespace OpenVic { bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root); bool add_building(BuildingInstance&& building_instance); - IDENTIFIER_REGISTRY_ACCESSORS(BuildingInstance, building) + IDENTIFIER_REGISTRY_ACCESSORS(building) void reset_buildings(); bool expand_building(std::string_view building_type_identifier); Good const* get_rgo() const; diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index 2438df6..ce0b7e7 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -49,7 +49,7 @@ bool TerrainTypeManager::add_terrain_type(std::string_view identifier, colour_t bool TerrainTypeManager::add_terrain_type_mapping(std::string_view identifier, TerrainType const* type, std::vector<TerrainTypeMapping::index_t>&& terrain_indicies, TerrainTypeMapping::index_t priority, bool has_texture) { - if (!terrain_types.is_locked()) { + if (!terrain_types_are_locked()) { Logger::error("Cannot register terrain type mappings until terrain types are locked!"); return false; } @@ -76,48 +76,53 @@ bool TerrainTypeManager::add_terrain_type_mapping(std::string_view identifier, T return ret; } -bool TerrainTypeManager::_load_terrain_type_categories(ModifierManager const& modifier_manager, ast::NodeCPtr root) { - const bool ret = expect_dictionary_reserve_length(terrain_types, - [this, &modifier_manager](std::string_view type_key, ast::NodeCPtr type_node) -> bool { - ModifierValue values; - colour_t colour = NULL_COLOUR; - bool is_water = false; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), - "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), - "is_water", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_water)) - )(type_node); - ret &= add_terrain_type(type_key, colour, std::move(values), is_water); - return ret; - } - )(root); - terrain_types.lock(); - return ret; +node_callback_t TerrainTypeManager::_load_terrain_type_categories(ModifierManager const& modifier_manager) { + return [this, &modifier_manager](ast::NodeCPtr root) -> bool { + const bool ret = expect_dictionary_reserve_length(terrain_types, + [this, &modifier_manager](std::string_view type_key, ast::NodeCPtr type_node) -> bool { + ModifierValue values; + colour_t colour = NULL_COLOUR; + bool is_water = false; + bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), + "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), + "is_water", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_water)) + )(type_node); + ret &= add_terrain_type(type_key, colour, std::move(values), is_water); + return ret; + } + )(root); + lock_terrain_types(); + return ret; + }; } bool TerrainTypeManager::_load_terrain_type_mapping(std::string_view mapping_key, ast::NodeCPtr mapping_value) { + if (terrain_texture_limit <= 0) { + Logger::error("Cannot define terrain type mapping before terrain texture limit: ", mapping_key); + return false; + } + if (!terrain_types_are_locked()) { + Logger::error("Cannot define terrain type mapping before categories: ", mapping_key); + return false; + } TerrainType const* type = nullptr; std::vector<TerrainTypeMapping::index_t> terrain_indicies; TerrainTypeMapping::index_t priority = 0; bool has_texture = true; bool ret = expect_dictionary_keys( - "type", ONE_EXACTLY, expect_terrain_type_identifier(assign_variable_callback_pointer(type)), - "color", ONE_EXACTLY, expect_list_reserve_length(terrain_indicies, expect_uint( - [&terrain_indicies](uint64_t val) -> bool { - if (val <= std::numeric_limits<TerrainTypeMapping::index_t>::max()) { - TerrainTypeMapping::index_t index = val; - if (std::find(terrain_indicies.begin(), terrain_indicies.end(), index) == terrain_indicies.end()) { - terrain_indicies.push_back(val); - return true; - } - Logger::error("Repeat terrain type mapping index: ", val); - return false; + "type", ONE_EXACTLY, expect_identifier(expect_terrain_type_identifier(assign_variable_callback_pointer(type))), + "color", ONE_EXACTLY, expect_list_reserve_length(terrain_indicies, expect_uint<TerrainTypeMapping::index_t>( + [&terrain_indicies](TerrainTypeMapping::index_t val) -> bool { + if (std::find(terrain_indicies.begin(), terrain_indicies.end(), val) == terrain_indicies.end()) { + terrain_indicies.push_back(val); + return true; } - Logger::error("Index too big for terrain type mapping index: ", val); + Logger::error("Repeat terrain type mapping index: ", val); return false; } )), - "priority", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(priority)), + "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) { @@ -143,45 +148,15 @@ TerrainTypeMapping::index_t TerrainTypeManager::get_terrain_texture_limit() cons } bool TerrainTypeManager::load_terrain_types(ModifierManager const& modifier_manager, ast::NodeCPtr root) { - bool terrain = false, categories = false; - bool ret = expect_dictionary_and_length( + const bool ret = expect_dictionary_keys_and_length_and_default( [this](size_t size) -> size_t { terrain_type_mappings.reserve(size - 2); return size; }, - [this, &terrain, &categories, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool { - if (key == "terrain") { - if (!terrain) { - terrain = true; - return expect_uint(assign_variable_callback_uint(terrain_texture_limit))(value); - } else { - Logger::error("Duplicate terrain key!"); - return false; - } - } else if (key == "categories") { - if (!categories) { - categories = true; - return _load_terrain_type_categories(modifier_manager, value); - } else { - Logger::error("Duplicate categories key!"); - return false; - } - } else if (terrain && categories) { - return _load_terrain_type_mapping(key, value); - } else { - Logger::error("Cannot define terrain type mapping before terrain and categories keys: ", key); - return false; - } - } + std::bind(&TerrainTypeManager::_load_terrain_type_mapping, this, std::placeholders::_1, std::placeholders::_2), + "terrain", ONE_EXACTLY, expect_uint(assign_variable_callback(terrain_texture_limit)), + "categories", ONE_EXACTLY, _load_terrain_type_categories(modifier_manager) )(root); - if (!terrain) { - Logger::error("Missing expected key: \"terrain\""); - ret = false; - } - if (!categories) { - Logger::error("Missing expected key: \"categories\""); - ret = false; - } - terrain_type_mappings.lock(); + lock_terrain_type_mappings(); return ret; } diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp index 3b491ae..1353130 100644 --- a/src/openvic-simulation/map/TerrainType.hpp +++ b/src/openvic-simulation/map/TerrainType.hpp @@ -50,18 +50,18 @@ namespace OpenVic { TerrainTypeMapping::index_t terrain_texture_limit = 0, terrain_texture_count = 0; - bool _load_terrain_type_categories(ModifierManager const& modifier_manager, ast::NodeCPtr root); + NodeTools::node_callback_t _load_terrain_type_categories(ModifierManager const& modifier_manager); bool _load_terrain_type_mapping(std::string_view key, ast::NodeCPtr value); public: TerrainTypeManager(); bool add_terrain_type(std::string_view identifier, colour_t colour, ModifierValue&& values, bool is_water); - IDENTIFIER_REGISTRY_ACCESSORS(TerrainType, terrain_type) + IDENTIFIER_REGISTRY_ACCESSORS(terrain_type) bool add_terrain_type_mapping(std::string_view identifier, TerrainType const* type, std::vector<TerrainTypeMapping::index_t>&& terrain_indicies, TerrainTypeMapping::index_t priority, bool has_texture); - IDENTIFIER_REGISTRY_ACCESSORS(TerrainTypeMapping, terrain_type_mapping) + IDENTIFIER_REGISTRY_ACCESSORS(terrain_type_mapping) TerrainTypeMapping const* get_terrain_type_mapping_for(TerrainTypeMapping::index_t idx) const; diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp index 869ac3d..1a48806 100644 --- a/src/openvic-simulation/politics/Government.cpp +++ b/src/openvic-simulation/politics/Government.cpp @@ -2,98 +2,110 @@ #include <set> -#include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/GameManager.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; -GovernmentType::GovernmentType(std::string_view new_identifier, std::vector<Ideology const*> new_ideologies, bool new_elections, bool new_appoint_ruling_party, Timespan new_election_duration, std::string_view new_flag_type_identifier) - : HasIdentifier { new_identifier }, ideologies { new_ideologies }, elections { new_elections }, appoint_ruling_party { new_appoint_ruling_party }, election_duration { new_election_duration }, flag_type_identifier { new_flag_type_identifier } {} +GovernmentType::GovernmentType(std::string_view new_identifier, std::vector<Ideology const*>&& new_ideologies, bool new_elections, bool new_appoint_ruling_party, Timespan new_term_duration, std::string_view new_flag_type_identifier) + : HasIdentifier { new_identifier }, ideologies { std::move(new_ideologies) }, elections { new_elections }, appoint_ruling_party { new_appoint_ruling_party }, term_duration { new_term_duration }, flag_type_identifier { new_flag_type_identifier } {} bool GovernmentType::is_ideology_compatible(Ideology const* ideology) const { - return std::find(ideologies.begin(), ideologies.end(), ideology) != ideologies.end(); + return std::find(ideologies.begin(), ideologies.end(), ideology) != ideologies.end(); } std::vector<Ideology const*> const& GovernmentType::get_ideologies() const { - return ideologies; + return ideologies; } bool GovernmentType::holds_elections() const { - return elections; + return elections; } bool GovernmentType::can_appoint_ruling_party() const { - return appoint_ruling_party; + return appoint_ruling_party; } -Timespan GovernmentType::get_election_duration() const { - return election_duration; +Timespan GovernmentType::get_term_duration() const { + return term_duration; } -std::string_view GovernmentType::get_flag_type() const { - return flag_type_identifier; +std::string const& GovernmentType::get_flag_type() const { + return flag_type_identifier; } GovernmentTypeManager::GovernmentTypeManager() : government_types { "government types" } {} -bool GovernmentTypeManager::add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan election_duration, std::string_view flag_type) { - if (identifier.empty()) { - Logger::error("Invalid government type identifier - empty!"); - return false; - } +bool GovernmentTypeManager::add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type) { + if (identifier.empty()) { + Logger::error("Invalid government type identifier - empty!"); + return false; + } - if (ideologies.empty()) { - Logger::error("No compatible ideologies defined for government type ", identifier); - return false; - } + if (ideologies.empty()) { + Logger::error("No compatible ideologies defined for government type ", identifier); + return false; + } - if (elections && election_duration == 0) { - Logger::error("No or invalid election duration for government type ", identifier); - return false; - } + if (elections && term_duration < 0) { + Logger::error("No or invalid term duration for government type ", identifier); + return false; + } - return government_types.add_item({ identifier, ideologies, elections, appoint_ruling_party, election_duration, flag_type }); + return government_types.add_item({ identifier, std::move(ideologies), elections, appoint_ruling_party, term_duration, flag_type }); } /* REQUIREMENTS: FS-525, SIM-27 */ bool GovernmentTypeManager::load_government_types_file(IdeologyManager const& ideology_manager, ast::NodeCPtr root) { - bool ret = expect_dictionary( - [this, &ideology_manager](std::string_view government_type_identifier, ast::NodeCPtr value) -> bool { - std::vector<Ideology const*> ideologies; - bool elections = false, appoint_ruling_party = false; - uint16_t election_duration = 0; /* in months */ - std::string_view flag_type_identifier = "republic"; - - bool ret = expect_dictionary_keys( - ALLOW_OTHER_KEYS, - "election", ONE_EXACTLY, expect_bool(assign_variable_callback(elections)), - "duration", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(election_duration)), - "appoint_ruling_party", ONE_EXACTLY, expect_bool(assign_variable_callback(appoint_ruling_party)), - "flagType", ZERO_OR_ONE, expect_identifier(assign_variable_callback(flag_type_identifier)) - )(value); - - ret &= expect_dictionary( - [this, &ideology_manager, &ideologies, government_type_identifier](std::string_view key, ast::NodeCPtr value) -> bool { - static const std::set<std::string, std::less<void>> reserved_keys = { + bool ret = expect_dictionary_reserve_length( + government_types, + [this, &ideology_manager](std::string_view government_type_identifier, ast::NodeCPtr government_type_value) -> bool { + std::vector<Ideology const*> ideologies; + bool elections = false, appoint_ruling_party = false; + Timespan term_duration = 0; + std::string_view flag_type_identifier = "republic"; + + size_t total_expected_ideologies = 0; + bool ret = expect_dictionary_keys_and_default( + increment_callback(total_expected_ideologies), + "election", ONE_EXACTLY, expect_bool(assign_variable_callback(elections)), + "duration", ZERO_OR_ONE, expect_months(assign_variable_callback(term_duration)), + "appoint_ruling_party", ONE_EXACTLY, expect_bool(assign_variable_callback(appoint_ruling_party)), + "flagType", ZERO_OR_ONE, expect_identifier(assign_variable_callback(flag_type_identifier)) + )(government_type_value); + ideologies.reserve(total_expected_ideologies); + + ret &= expect_dictionary( + [this, &ideology_manager, &ideologies, government_type_identifier](std::string_view key, ast::NodeCPtr value) -> bool { + static const std::set<std::string, std::less<void>> reserved_keys = { "election", "duration", "appoint_ruling_party", "flagType" }; - if (reserved_keys.find(key) != reserved_keys.end()) return true; - Ideology const* ideology = ideology_manager.get_ideology_by_identifier(key); - if (ideology == nullptr) { - Logger::error("When loading government type ", government_type_identifier, ", specified ideology ", key, " is invalid!"); - return false; - } - ideologies.push_back(ideology); - return true; - } - )(value); - - ret &= add_government_type(government_type_identifier, ideologies, elections, appoint_ruling_party, Timespan(election_duration * 30), flag_type_identifier); - return ret; - } - )(root); - lock_government_types(); - - return ret; + if (reserved_keys.find(key) != reserved_keys.end()) return true; + Ideology const* ideology = ideology_manager.get_ideology_by_identifier(key); + if (ideology == nullptr) { + Logger::error("When loading government type ", government_type_identifier, ", specified ideology ", key, " is invalid!"); + return false; + } + return expect_bool([&ideologies, ideology, government_type_identifier](bool val) -> bool { + if (val) { + if (std::find(ideologies.begin(), ideologies.end(), ideology) == ideologies.end()) { + ideologies.push_back(ideology); + return true; + } + Logger::error("Government type ", government_type_identifier, " marked as supporting ideology ", ideology->get_identifier()); + return false; + } + Logger::error("Government type ", government_type_identifier, " redundantly marked as not supporting ideology ", ideology->get_identifier(), " multiple times"); + return false; + })(value); + } + )(government_type_value); + + ret &= add_government_type(government_type_identifier, std::move(ideologies), elections, appoint_ruling_party, term_duration, flag_type_identifier); + return ret; + } + )(root); + lock_government_types(); + + return ret; }
\ No newline at end of file diff --git a/src/openvic-simulation/politics/Government.hpp b/src/openvic-simulation/politics/Government.hpp index a8fc00f..3bc754c 100644 --- a/src/openvic-simulation/politics/Government.hpp +++ b/src/openvic-simulation/politics/Government.hpp @@ -1,43 +1,42 @@ #pragma once -#include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/politics/Ideology.hpp" namespace OpenVic { - struct GovernmentTypeManager; + struct GovernmentTypeManager; - struct GovernmentType : HasIdentifier { - friend struct GovernmentTypeManager; + struct GovernmentType : HasIdentifier { + friend struct GovernmentTypeManager; - private: - std::vector<Ideology const*> ideologies; - const bool elections, appoint_ruling_party; - const Timespan election_duration; - const std::string flag_type_identifier; + private: + const std::vector<Ideology const*> ideologies; + const bool elections, appoint_ruling_party; + const Timespan term_duration; + const std::string flag_type_identifier; - GovernmentType(std::string_view new_identifier, std::vector<Ideology const*> new_ideologies, bool new_elections, bool new_appoint_ruling_party, Timespan new_election_duration, std::string_view new_flag_type_identifier); + GovernmentType(std::string_view new_identifier, std::vector<Ideology const*>&& new_ideologies, bool new_elections, bool new_appoint_ruling_party, Timespan new_term_duration, std::string_view new_flag_type_identifier); - public: - GovernmentType(GovernmentType&&) = default; + public: + GovernmentType(GovernmentType&&) = default; - bool is_ideology_compatible(Ideology const* ideology) const; - std::vector<Ideology const*> const& get_ideologies() const; - bool holds_elections() const; - bool can_appoint_ruling_party() const; - Timespan get_election_duration() const; - std::string_view get_flag_type() const; - }; + bool is_ideology_compatible(Ideology const* ideology) const; + std::vector<Ideology const*> const& get_ideologies() const; + bool holds_elections() const; + bool can_appoint_ruling_party() const; + Timespan get_term_duration() const; + std::string const& get_flag_type() const; + }; - struct GovernmentTypeManager { - private: - IdentifierRegistry<GovernmentType> government_types; + struct GovernmentTypeManager { + private: + IdentifierRegistry<GovernmentType> government_types; - public: - GovernmentTypeManager(); + public: + GovernmentTypeManager(); - bool add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan election_duration, std::string_view flag_type); - IDENTIFIER_REGISTRY_ACCESSORS(GovernmentType, government_type) + bool add_government_type(std::string_view identifier, std::vector<Ideology const*> ideologies, bool elections, bool appoint_ruling_party, Timespan term_duration, std::string_view flag_type); + IDENTIFIER_REGISTRY_ACCESSORS(government_type) - bool load_government_types_file(IdeologyManager const& ideology_manager, ast::NodeCPtr root); - }; + bool load_government_types_file(IdeologyManager const& ideology_manager, ast::NodeCPtr root); + }; } // namespace OpenVic diff --git a/src/openvic-simulation/politics/Ideology.hpp b/src/openvic-simulation/politics/Ideology.hpp index ab761b1..557333e 100644 --- a/src/openvic-simulation/politics/Ideology.hpp +++ b/src/openvic-simulation/politics/Ideology.hpp @@ -45,10 +45,10 @@ namespace OpenVic { IdeologyManager(); bool add_ideology_group(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(IdeologyGroup, ideology_group) + IDENTIFIER_REGISTRY_ACCESSORS(ideology_group) bool add_ideology(std::string_view identifier, colour_t colour, IdeologyGroup const* group, bool uncivilised, bool can_reduce_militancy, Date spawn_date); - IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(Ideology, ideology, ideologies) + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(ideology, ideologies) bool load_ideology_file(ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp index 73978ee..3f2fd10 100644 --- a/src/openvic-simulation/politics/Issue.cpp +++ b/src/openvic-simulation/politics/Issue.cpp @@ -122,13 +122,10 @@ bool IssueManager::_load_issue(std::string_view identifier, IssueGroup const* gr bool IssueManager::_load_reform_group(size_t& expected_reforms, std::string_view identifier, ReformType const* type, ast::NodeCPtr node) { bool ordered = false, administrative = false; - bool ret = expect_dictionary_keys_and_length( - [&expected_reforms](size_t size) -> size_t { - expected_reforms += size; - return size; - }, ALLOW_OTHER_KEYS, - "next_step_only", ZERO_OR_ONE, decrement_callback(expected_reforms, expect_bool(assign_variable_callback(ordered))), - "administrative", ZERO_OR_ONE, decrement_callback(expected_reforms, expect_bool(assign_variable_callback(administrative))) + bool ret = expect_dictionary_keys_and_default( + increment_callback(expected_reforms), + "next_step_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(ordered)), + "administrative", ZERO_OR_ONE, expect_bool(assign_variable_callback(administrative)) )(node); ret &= add_reform_group(identifier, type, ordered, administrative); return ret; diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp index ddd6295..9d72334 100644 --- a/src/openvic-simulation/politics/Issue.hpp +++ b/src/openvic-simulation/politics/Issue.hpp @@ -107,19 +107,19 @@ namespace OpenVic { IssueManager(); bool add_issue_group(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(IssueGroup, issue_group) + IDENTIFIER_REGISTRY_ACCESSORS(issue_group) bool add_issue(std::string_view identifier, IssueGroup const* group); - IDENTIFIER_REGISTRY_ACCESSORS(Issue, issue) + IDENTIFIER_REGISTRY_ACCESSORS(issue) bool add_reform_type(std::string_view identifier, bool uncivilised); - IDENTIFIER_REGISTRY_ACCESSORS(ReformType, reform_type) + IDENTIFIER_REGISTRY_ACCESSORS(reform_type) bool add_reform_group(std::string_view identifier, ReformType const* type, bool ordered, bool administrative); - IDENTIFIER_REGISTRY_ACCESSORS(ReformGroup, reform_group) + IDENTIFIER_REGISTRY_ACCESSORS(reform_group) bool add_reform(std::string_view identifier, ReformGroup const* group, size_t ordinal); - IDENTIFIER_REGISTRY_ACCESSORS(Reform, reform) + IDENTIFIER_REGISTRY_ACCESSORS(reform) bool load_issues_file(ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp index 6285305..261ad4c 100644 --- a/src/openvic-simulation/pop/Culture.cpp +++ b/src/openvic-simulation/pop/Culture.cpp @@ -118,16 +118,12 @@ bool CultureManager::_load_culture_group(size_t& total_expected_cultures, GraphicalCultureType const* unit_graphical_culture_type = default_unit_graphical_culture_type; bool is_overseas = true; - bool ret = expect_dictionary_keys_and_length( - [&total_expected_cultures](size_t size) -> size_t { - total_expected_cultures += size; - return size; - }, - ALLOW_OTHER_KEYS, - "leader", ONE_EXACTLY, decrement_callback(total_expected_cultures, expect_identifier(assign_variable_callback(leader))), - "unit", ZERO_OR_ONE, decrement_callback(total_expected_cultures, expect_graphical_culture_type_identifier(assign_variable_callback_pointer(unit_graphical_culture_type))), - "union", ZERO_OR_ONE, decrement_callback(total_expected_cultures, success_callback), - "is_overseas", ZERO_OR_ONE, decrement_callback(total_expected_cultures, expect_bool(assign_variable_callback(is_overseas))) + bool ret = expect_dictionary_keys_and_default( + increment_callback(total_expected_cultures), + "leader", ONE_EXACTLY, expect_identifier(assign_variable_callback(leader)), + "unit", ZERO_OR_ONE, expect_identifier(expect_graphical_culture_type_identifier(assign_variable_callback_pointer(unit_graphical_culture_type))), + "union", ZERO_OR_ONE, success_callback, + "is_overseas", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_overseas)) )(culture_group_node); ret &= add_culture_group(culture_group_key, leader, unit_graphical_culture_type, is_overseas); return ret; diff --git a/src/openvic-simulation/pop/Culture.hpp b/src/openvic-simulation/pop/Culture.hpp index becc289..b6b4952 100644 --- a/src/openvic-simulation/pop/Culture.hpp +++ b/src/openvic-simulation/pop/Culture.hpp @@ -69,13 +69,13 @@ namespace OpenVic { CultureManager(); bool add_graphical_culture_type(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(GraphicalCultureType, graphical_culture_type) + IDENTIFIER_REGISTRY_ACCESSORS(graphical_culture_type) bool add_culture_group(std::string_view identifier, std::string_view leader, GraphicalCultureType const* new_graphical_culture_type, bool is_overseas); - IDENTIFIER_REGISTRY_ACCESSORS(CultureGroup, culture_group) + IDENTIFIER_REGISTRY_ACCESSORS(culture_group) bool add_culture(std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector<std::string> const& first_names, std::vector<std::string> const& last_names); - IDENTIFIER_REGISTRY_ACCESSORS(Culture, culture) + IDENTIFIER_REGISTRY_ACCESSORS(culture) bool load_graphical_culture_type_file(ast::NodeCPtr root); bool load_culture_file(ast::NodeCPtr root); diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 38cd883..14c2a41 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -146,34 +146,24 @@ bool PopManager::add_pop_type(std::string_view identifier, colour_t colour, PopT * POP-3, POP-4, POP-5, POP-6, POP-7, POP-8, POP-9, POP-10, POP-11, POP-12, POP-13, POP-14 */ bool PopManager::load_pop_type_file(std::string_view filestem, ast::NodeCPtr root) { + static const string_map_t<PopType::strata_t> strata_map = { + { "poor", PopType::strata_t::POOR }, + { "middle", PopType::strata_t::MIDDLE }, + { "rich", PopType::strata_t::RICH } + }; + colour_t colour = NULL_COLOUR; PopType::strata_t strata = PopType::strata_t::POOR; PopType::sprite_t sprite = 0; bool state_capital_only = false, is_artisan = false, is_slave = false, demote_migrant = false; Pop::pop_size_t max_size = 0, merge_max_size = 0; bool ret = expect_dictionary_keys( - "sprite", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(sprite)), + "sprite", ONE_EXACTLY, expect_uint(assign_variable_callback(sprite)), "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), "is_artisan", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_artisan)), - "max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(max_size)), - "merge_max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(merge_max_size)), - "strata", ONE_EXACTLY, expect_identifier( - [&strata](std::string_view identifier) -> bool { - using strata_map_t = std::map<std::string, PopType::strata_t, std::less<void>>; - static const strata_map_t strata_map = { - { "poor", PopType::strata_t::POOR }, - { "middle", PopType::strata_t::MIDDLE }, - { "rich", PopType::strata_t::RICH } - }; - const strata_map_t::const_iterator it = strata_map.find(identifier); - if (it != strata_map.end()) { - strata = it->second; - return true; - } - Logger::error("Invalid pop type strata: ", identifier); - return false; - } - ), + "max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback(max_size)), + "merge_max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback(merge_max_size)), + "strata", ONE_EXACTLY, expect_identifier(expect_mapped_string(strata_map, assign_variable_callback(strata))), "state_capital_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(state_capital_only)), "research_points", ZERO_OR_ONE, success_callback, "research_optimum", ZERO_OR_ONE, success_callback, @@ -216,9 +206,9 @@ bool PopManager::load_pop_into_province(Province& province, std::string_view pop Religion const* religion = nullptr; Pop::pop_size_t size = 0; bool ret = expect_dictionary_keys( - "culture", ONE_EXACTLY, culture_manager.expect_culture_identifier(assign_variable_callback_pointer(culture)), - "religion", ONE_EXACTLY, religion_manager.expect_religion_identifier(assign_variable_callback_pointer(religion)), - "size", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(size)), + "culture", ONE_EXACTLY, expect_identifier(culture_manager.expect_culture_identifier(assign_variable_callback_pointer(culture))), + "religion", ONE_EXACTLY, expect_identifier(religion_manager.expect_religion_identifier(assign_variable_callback_pointer(religion))), + "size", ONE_EXACTLY, expect_uint(assign_variable_callback(size)), "militancy", ZERO_OR_ONE, success_callback, "rebel_type", ZERO_OR_ONE, success_callback )(pop_node); diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index 0ab3d06..e299468 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -96,7 +96,7 @@ namespace OpenVic { bool add_pop_type(std::string_view identifier, colour_t new_colour, PopType::strata_t strata, PopType::sprite_t sprite, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, bool demote_migrant, bool is_artisan, bool is_slave); - IDENTIFIER_REGISTRY_ACCESSORS(PopType, pop_type) + IDENTIFIER_REGISTRY_ACCESSORS(pop_type) bool load_pop_type_file(std::string_view filestem, ast::NodeCPtr root); bool load_pop_into_province(Province& province, std::string_view pop_type_identifier, ast::NodeCPtr pop_node) const; diff --git a/src/openvic-simulation/pop/Religion.cpp b/src/openvic-simulation/pop/Religion.cpp index 32a3219..1152ae5 100644 --- a/src/openvic-simulation/pop/Religion.cpp +++ b/src/openvic-simulation/pop/Religion.cpp @@ -91,7 +91,7 @@ bool ReligionManager::load_religion_file(ast::NodeCPtr root) { bool pagan = false; bool ret = expect_dictionary_keys( - "icon", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(icon)), + "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)), "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), "pagan", ZERO_OR_ONE, expect_bool(assign_variable_callback(pagan)) )(value); diff --git a/src/openvic-simulation/pop/Religion.hpp b/src/openvic-simulation/pop/Religion.hpp index 6d1c205..6b17266 100644 --- a/src/openvic-simulation/pop/Religion.hpp +++ b/src/openvic-simulation/pop/Religion.hpp @@ -46,10 +46,10 @@ namespace OpenVic { ReligionManager(); bool add_religion_group(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(ReligionGroup, religion_group) + IDENTIFIER_REGISTRY_ACCESSORS(religion_group) bool add_religion(std::string_view identifier, colour_t colour, ReligionGroup const* group, Religion::icon_t icon, bool pagan); - IDENTIFIER_REGISTRY_ACCESSORS(Religion, religion) + IDENTIFIER_REGISTRY_ACCESSORS(religion) bool load_religion_file(ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/types/Date.cpp b/src/openvic-simulation/types/Date.cpp index 27d554c..f167b7b 100644 --- a/src/openvic-simulation/types/Date.cpp +++ b/src/openvic-simulation/types/Date.cpp @@ -64,6 +64,19 @@ Timespan::operator std::string() const { return to_string(); } +Timespan Timespan::fromYears(day_t num) { + return num * Date::DAYS_IN_YEAR; +} + +Timespan Timespan::fromMonths(day_t num) { + return (num / Date::MONTHS_IN_YEAR) * Date::DAYS_IN_YEAR + + Date::DAYS_UP_TO_MONTH[num % Date::MONTHS_IN_YEAR]; +} + +Timespan Timespan::fromDays(day_t num) { + return num; +} + std::ostream& OpenVic::operator<<(std::ostream& out, Timespan const& timespan) { return out << timespan.to_string(); } diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp index b2df666..718de80 100644 --- a/src/openvic-simulation/types/Date.hpp +++ b/src/openvic-simulation/types/Date.hpp @@ -35,6 +35,10 @@ namespace OpenVic { explicit operator double() const; std::string to_string() const; explicit operator std::string() const; + + static Timespan fromYears(day_t num); + static Timespan fromMonths(day_t num); + static Timespan fromDays(day_t num); }; std::ostream& operator<<(std::ostream& out, Timespan const& timespan); diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index 7fe2656..4e13813 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -68,42 +68,50 @@ namespace OpenVic { distribution_t::value_type get_largest_item(distribution_t const& dist); - /* - * Template for a list of objects with unique string identifiers that can - * be locked to prevent any further additions. The template argument T is - * the type of object that the registry will store, and the second part ensures - * that HasIdentifier is a base class of T. - */ template<typename T> - requires(std::derived_from<T, HasIdentifier>) - class IdentifierRegistry { - using identifier_index_map_t = std::map<std::string, size_t, std::less<void>>; + using get_identifier_func_t = std::string const&(T::*)(void) const; + + template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier, + typename _Storage, _Type* (*get_ptr)(_Storage&), _Type const* (*get_cptr)(_Storage const&)> + class UniqueKeyRegistry { const std::string name; const bool log_lock; - std::vector<T> items; + std::vector<_Storage> items; bool locked = false; - identifier_index_map_t identifier_index_map; + string_map_t<size_t> identifier_index_map; public: - IdentifierRegistry(std::string_view new_name, bool new_log_lock = true) + 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 } {} std::string const& get_name() const { return name; } - bool add_item(T&& item) { + bool add_item(storage_type&& item, bool fail_on_duplicate = true) { if (locked) { Logger::error("Cannot add item to the ", name, " registry - locked!"); return false; } - T const* old_item = get_item_by_identifier(item.get_identifier()); + value_type const* new_item = (*get_cptr)(item); + std::string const& new_identifier = (new_item->*get_identifier)(); + value_type const* old_item = get_item_by_identifier(new_identifier); if (old_item != nullptr) { - Logger::error("Cannot add item to the ", name, " registry - an item with the identifier \"", item.get_identifier(), "\" already exists!"); - return false; +#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 } - identifier_index_map[item.get_identifier()] = items.size(); + identifier_index_map[new_identifier] = items.size(); items.push_back(std::move(item)); return true; } @@ -143,15 +151,15 @@ namespace OpenVic { } } - T* get_item_by_identifier(std::string_view identifier) { - const identifier_index_map_t::const_iterator it = identifier_index_map.find(identifier); - if (it != identifier_index_map.end()) return &items[it->second]; + 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; } - T const* get_item_by_identifier(std::string_view identifier) const { - const identifier_index_map_t::const_iterator it = identifier_index_map.find(identifier); - if (it != identifier_index_map.end()) return &items[it->second]; + 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; } @@ -159,11 +167,11 @@ namespace OpenVic { return get_item_by_identifier(identifier) != nullptr; } - T* get_item_by_index(size_t index) { + value_type* get_item_by_index(size_t index) { return index < items.size() ? &items[index] : nullptr; } - T const* get_item_by_index(size_t index) const { + value_type const* get_item_by_index(size_t index) const { return index < items.size() ? &items[index] : nullptr; } @@ -171,48 +179,44 @@ namespace OpenVic { return get_item_by_index(index) != nullptr; } - std::vector<T>& get_items() { + std::vector<storage_type>& get_items() { return items; } - std::vector<T> const& get_items() const { + std::vector<storage_type> const& get_items() const { return items; } std::vector<std::string_view> get_item_identifiers() const { std::vector<std::string_view> identifiers; identifiers.reserve(items.size()); - for (identifier_index_map_t::value_type const& entry : identifier_index_map) { + for (typename decltype(identifier_index_map)::value_type const& entry : identifier_index_map) { identifiers.push_back(entry.first); } return identifiers; } - NodeTools::node_callback_t expect_item_identifier(NodeTools::callback_t<T&> callback) { - return NodeTools::expect_identifier( - [this, callback](std::string_view identifier) -> bool { - T* item = get_item_by_identifier(identifier); - if (item != nullptr) return callback(*item); - Logger::error("Invalid ", name, ": ", identifier); - return false; - } - ); + NodeTools::callback_t<std::string_view> expect_item_identifier(NodeTools::callback_t<value_type&> 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::node_callback_t expect_item_identifier(NodeTools::callback_t<T const&> callback) const { - return NodeTools::expect_identifier( - [this, callback](std::string_view identifier) -> bool { - T const* item = get_item_by_identifier(identifier); - if (item != nullptr) return callback(*item); - Logger::error("Invalid ", name, ": ", identifier); - return false; - } - ); + NodeTools::callback_t<std::string_view> expect_item_identifier(NodeTools::callback_t<value_type const&> callback) const { + return [this, callback](std::string_view identifier) -> bool { + value_type const* item = get_item_by_identifier(identifier); + if (item != nullptr) return callback(*item); + Logger::error("Invalid ", name, ": ", identifier); + return false; + }; } - NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<T&, ast::NodeCPtr> callback) { + NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<value_type&, ast::NodeCPtr> callback) { return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { - T* item = get_item_by_identifier(key); + value_type* item = get_item_by_identifier(key); if (item != nullptr) { return callback(*item, value); } @@ -221,9 +225,9 @@ namespace OpenVic { }); } - NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<T const&, ast::NodeCPtr> callback) const { + NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t<value_type const&, ast::NodeCPtr> callback) const { return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { - T const* item = get_item_by_identifier(key); + value_type const* item = get_item_by_identifier(key); if (item != nullptr) { return callback(*item, value); } @@ -232,10 +236,10 @@ namespace OpenVic { }); } - NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t<std::map<T const*, fixed_point_t>&&> callback) const { + NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t<std::map<value_type const*, fixed_point_t>&&> callback) const { return [this, callback](ast::NodeCPtr node) -> bool { - std::map<T const*, fixed_point_t> map; - bool ret = expect_item_dictionary([&map](T const& key, ast::NodeCPtr value) -> bool { + std::map<value_type const*, fixed_point_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); map.emplace(&key, val); @@ -247,34 +251,56 @@ namespace OpenVic { } }; -#define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(type, singular, plural) \ + template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier> + using ValueRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, _Type, std::addressof<_Type>, std::addressof<const _Type>>; + + template<typename _Type> + constexpr _Type* get_ptr(std::unique_ptr<_Type>& storage) { + return storage.get(); + } + template<typename _Type> + constexpr _Type const* get_cptr(std::unique_ptr<_Type> const& storage) { + return storage.get(); + } + + template<typename _Base, std::derived_from<_Base> _Type, get_identifier_func_t<_Base> get_identifier> + using InstanceRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, std::unique_ptr<_Type>, + get_ptr<_Type>, get_cptr<_Type>>; + + template<std::derived_from<HasIdentifier> _Type> + using IdentifierRegistry = ValueRegistry<HasIdentifier, _Type, &HasIdentifier::get_identifier>; + + template<std::derived_from<HasIdentifier> _Type> + using IdentifierInstanceRegistry = InstanceRegistry<HasIdentifier, _Type, &HasIdentifier::get_identifier>; + +#define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ void lock_##plural() { plural.lock(); } \ bool plural##_are_locked() const { return plural.is_locked(); } \ - type const* get_##singular##_by_identifier(std::string_view identifier) const { \ + decltype(plural)::value_type const* get_##singular##_by_identifier(std::string_view identifier) const { \ return plural.get_item_by_identifier(identifier); } \ bool has_##singular##_identifier(std::string_view identifier) const { \ return plural.has_identifier(identifier); } \ size_t get_##singular##_count() const { \ return plural.size(); } \ - std::vector<type> const& get_##plural() const { \ + std::vector<decltype(plural)::storage_type> const& get_##plural() const { \ return plural.get_items(); } \ std::vector<std::string_view> get_##singular##_identifiers() const { \ return plural.get_item_identifiers(); } \ - NodeTools::node_callback_t expect_##singular##_identifier(NodeTools::callback_t<type const&> callback) const { \ + NodeTools::callback_t<std::string_view> expect_##singular##_identifier(NodeTools::callback_t<decltype(plural)::value_type const&> callback) const { \ return plural.expect_item_identifier(callback); } \ - NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t<type const&, ast::NodeCPtr> callback) const { \ + NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t<decltype(plural)::value_type const&, ast::NodeCPtr> callback) const { \ return plural.expect_item_dictionary(callback); } \ - NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t<std::map<type const*, fixed_point_t>&&> callback) const { \ + NodeTools::node_callback_t expect_##singular##_decimal_map(NodeTools::callback_t<std::map<decltype(plural)::value_type const*, fixed_point_t>&&> callback) const { \ return plural.expect_item_decimal_map(callback); } -#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(type, singular, plural) \ - type* get_##singular##_by_identifier(std::string_view identifier) { \ +#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ + decltype(plural)::value_type* get_##singular##_by_identifier(std::string_view identifier) { \ return plural.get_item_by_identifier(identifier); } \ - NodeTools::node_callback_t expect_##singular##_identifier(NodeTools::callback_t<type&> callback) { \ + NodeTools::callback_t<std::string_view> expect_##singular##_identifier(NodeTools::callback_t<decltype(plural)::value_type&> callback) { \ return plural.expect_item_identifier(callback); } \ - NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t<type&, ast::NodeCPtr> callback) { \ + NodeTools::node_callback_t expect_##singular##_dictionary(NodeTools::callback_t<decltype(plural)::value_type&, ast::NodeCPtr> callback) { \ return plural.expect_item_dictionary(callback); } -#define IDENTIFIER_REGISTRY_ACCESSORS(type, name) IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(type, name, name##s) -#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(type, name) IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(type, name, name##s) +#define IDENTIFIER_REGISTRY_ACCESSORS(name) IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(name, name##s) +#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(name) IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(name, name##s) } diff --git a/src/openvic-simulation/types/Vector.cpp b/src/openvic-simulation/types/Vector.cpp index aa44710..10d2dd2 100644 --- a/src/openvic-simulation/types/Vector.cpp +++ b/src/openvic-simulation/types/Vector.cpp @@ -76,5 +76,5 @@ constexpr std::ostream& operator<<(std::ostream& stream, vec2_t<T> const& value) template struct OpenVic::vec2_t<int64_t>; template struct OpenVic::vec2_t<fixed_point_t>; -static_assert(sizeof(ivec2_t) == 2 * sizeof(int64_t), "ivec2_t size does not equal the sum of its parts' sizes"); -static_assert(sizeof(fvec2_t) == 2 * sizeof(fixed_point_t), "fvec2_t size does not equal the sum of its parts' sizes"); +static_assert(sizeof(ivec2_t) == 2 * sizeof(ivec2_t::type), "ivec2_t size does not equal the sum of its parts' sizes"); +static_assert(sizeof(fvec2_t) == 2 * sizeof(fvec2_t::type), "fvec2_t size does not equal the sum of its parts' sizes"); diff --git a/src/openvic-simulation/types/Vector.hpp b/src/openvic-simulation/types/Vector.hpp index eecd738..9f576d7 100644 --- a/src/openvic-simulation/types/Vector.hpp +++ b/src/openvic-simulation/types/Vector.hpp @@ -6,6 +6,8 @@ namespace OpenVic { template<typename T> struct vec2_t { + using type = T; + T x, y; constexpr vec2_t() = default; @@ -21,21 +23,21 @@ namespace OpenVic { constexpr T& operator[](size_t index); constexpr T const& operator[](size_t index) const; - template <typename S> + template<typename S> constexpr friend vec2_t<S> operator+(vec2_t<S> const& left, vec2_t<S> const& right); constexpr vec2_t& operator+=(vec2_t const& right); - template <typename S> + template<typename S> constexpr friend vec2_t<S> operator-(vec2_t<S> const& arg); - template <typename S> + template<typename S> constexpr friend vec2_t<S> operator-(vec2_t<S> const& left, vec2_t<S> const& right); constexpr vec2_t& operator-=(vec2_t const& right); - template <typename S> + template<typename S> constexpr friend std::ostream& operator<<(std::ostream& stream, vec2_t<S> const& value); }; - using ivec2_t = vec2_t<int64_t>; + using ivec2_t = vec2_t<int32_t>; using fvec2_t = vec2_t<fixed_point_t>; } diff --git a/src/openvic-simulation/units/Unit.cpp b/src/openvic-simulation/units/Unit.cpp index 8d519f1..3da24da 100644 --- a/src/openvic-simulation/units/Unit.cpp +++ b/src/openvic-simulation/units/Unit.cpp @@ -1,9 +1,12 @@ #include "Unit.hpp" +#include <set> + #define UNIT_ARGS icon, sprite, active, unit_type, floating_flag, priority, max_strength, \ default_organisation, maximum_speed, weighted_value, build_time, build_cost, supply_consumption, \ supply_cost -#define LAND_ARGS reconnaissance, attack, defence, discipline, support, maneuver, siege +#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 @@ -76,9 +79,26 @@ std::map<Good const*, fixed_point_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 }, - reconnaissance { reconnaissance }, attack { attack }, defence { defence }, discipline { discipline }, support { support }, - maneuver { maneuver }, siege { siege } {} +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 } {} + +bool LandUnit::get_primary_culture() const { + return primary_culture; +} + +std::string const& LandUnit::get_sprite_override() const { + return sprite_override; +} + +std::string const& LandUnit::get_sprite_mount() const { + return sprite_mount; +} + +std::string const& LandUnit::get_sprite_mount_attach_node() const { + return sprite_mount_attach_node; +} fixed_point_t LandUnit::get_reconnaissance() const { return reconnaissance; @@ -215,6 +235,17 @@ bool UnitManager::add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_ return units.add_item(NavalUnit { identifier, UNIT_ARGS, NAVY_ARGS }); } +static bool shared_keys_callback(std::string_view key, ast::NodeCPtr) { + static const std::set<std::string, std::less<void>> reserved_keys = { + "icon", "type", "sprite", "active", "unit_type", "floating_flag", "priority", + "max_strength", "default_organisation", "maximum_speed", "weighted_value", + "build_time", "build_cost", "supply_consumption", "supply_cost" + }; + if (reserved_keys.contains(key)) return true; + Logger::error("Invalid key: ", key); + return false; +}; + bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root) { return expect_dictionary([this, &good_manager](std::string_view key, ast::NodeCPtr value) -> bool { Unit::icon_t icon = 0; @@ -226,28 +257,36 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr std::map<Good const*, fixed_point_t> build_cost, supply_cost; //shared - bool ret = expect_dictionary_keys(ALLOW_OTHER_KEYS, - "icon", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(icon)), + bool ret = expect_dictionary_keys_and_default( + key_value_success_callback, + "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)), "type", ONE_EXACTLY, expect_identifier(assign_variable_callback(type)), "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)), "floating_flag", ONE_EXACTLY, expect_bool(assign_variable_callback(floating_flag)), - "priority", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(priority)), + "priority", ONE_EXACTLY, expect_uint(assign_variable_callback(priority)), "max_strength", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_strength)), "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)), - "build_time", ONE_EXACTLY, expect_timespan(assign_variable_callback(build_time)), + "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(ALLOW_OTHER_KEYS, + 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)), @@ -268,8 +307,9 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr 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(ALLOW_OTHER_KEYS, - "naval_icon", ONE_EXACTLY, expect_uint(assign_variable_callback_uint(naval_icon)), + 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)), @@ -277,8 +317,8 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr "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_uint(min_port_level)), - "limit_per_port", ONE_EXACTLY, expect_int(assign_variable_callback_int(limit_per_port)), + "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)), diff --git a/src/openvic-simulation/units/Unit.hpp b/src/openvic-simulation/units/Unit.hpp index 3555cce..65e6259 100644 --- a/src/openvic-simulation/units/Unit.hpp +++ b/src/openvic-simulation/units/Unit.hpp @@ -14,8 +14,9 @@ fixed_point_t maximum_speed, fixed_point_t weighted_value, Timespan build_time, \ std::map<Good const*, fixed_point_t> build_cost, fixed_point_t supply_consumption, \ std::map<Good const*, fixed_point_t> supply_cost -#define LAND_PARAMS 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 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, \ @@ -77,6 +78,8 @@ namespace OpenVic { friend struct UnitManager; private: + const bool primary_culture; + const std::string sprite_override, sprite_mount, sprite_mount_attach_node; const fixed_point_t reconnaissance; const fixed_point_t attack; const fixed_point_t defence; @@ -90,6 +93,11 @@ namespace OpenVic { public: LandUnit(LandUnit&&) = default; + bool get_primary_culture() const; + std::string const& get_sprite_override() const; + std::string const& get_sprite_mount() const; + std::string const& get_sprite_mount_attach_node() const; + fixed_point_t get_reconnaissance() const; fixed_point_t get_attack() const; fixed_point_t get_defence() const; @@ -156,7 +164,7 @@ namespace OpenVic { bool add_land_unit(std::string_view identifier, UNIT_PARAMS, LAND_PARAMS); bool add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_PARAMS); - IDENTIFIER_REGISTRY_ACCESSORS(Unit, unit) + IDENTIFIER_REGISTRY_ACCESSORS(unit) bool load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/utility/Logger.hpp b/src/openvic-simulation/utility/Logger.hpp index c7b8c51..55e0862 100644 --- a/src/openvic-simulation/utility/Logger.hpp +++ b/src/openvic-simulation/utility/Logger.hpp @@ -49,7 +49,8 @@ namespace OpenVic { log(log_func_t log_func, log_queue_t& log_queue, Ts&&... ts, source_location const& location) { std::stringstream stream; stream << "\n" << get_filename(location.file_name()) << "(" - << location.line() << ") `" << location.function_name() << "`: "; + //<< location.line() << ") `" << location.function_name() << "`: "; + << location.line() << "): "; ((stream << std::forward<Ts>(ts)), ...); stream << std::endl; log_queue.push(stream.str()); |