diff options
author | hop311 <hop3114@gmail.com> | 2023-10-31 02:11:47 +0100 |
---|---|---|
committer | hop311 <hop3114@gmail.com> | 2023-11-07 19:33:42 +0100 |
commit | c1b7cab254ac14a173477661047ad2492930ff8b (patch) | |
tree | 3fd965559fb97c7a2f2245952ab531afec84bc93 | |
parent | e91ce707b2c0e80591b9fd1b6a5215e6e6989df8 (diff) |
History loading changes + PROPERTY macro
33 files changed, 638 insertions, 562 deletions
diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp index 0d79833..c3b7f6a 100644 --- a/src/openvic-simulation/Modifier.cpp +++ b/src/openvic-simulation/Modifier.cpp @@ -47,7 +47,7 @@ fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* succ } bool ModifierValue::has_effect(ModifierEffect const* effect) const { - return values.find(effect) != values.end(); + return values.contains(effect); } ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { @@ -107,9 +107,9 @@ bool ModifierManager::add_modifier_effect(std::string_view identifier, bool posi Logger::error("Invalid modifier effect identifier - empty!"); return false; } - return modifier_effects.add_item(std::unique_ptr<ModifierEffect> { - new ModifierEffect { identifier, positive_good, format } - }); + return modifier_effects.add_item( + std::make_unique<ModifierEffect>(std::move(identifier), std::move(positive_good), std::move(format)) + ); } bool ModifierManager::add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { @@ -260,7 +260,7 @@ key_value_callback_t ModifierManager::_modifier_effect_callback( ModifierEffect const* effect = get_modifier_effect_by_identifier(key); if (effect != nullptr) { if (effect_validator(*effect)) { - if (modifier.values.find(effect) == modifier.values.end()) { + if (!modifier.values.contains(effect)) { return expect_fixed_point(assign_variable_callback(modifier.values[effect]))(value); } else { Logger::error("Duplicate modifier effect: ", key); diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp index 78f8228..fc37655 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -6,8 +6,6 @@ namespace OpenVic { struct ModifierManager; struct ModifierEffect : HasIdentifier { - friend struct ModifierManager; - enum class format_t { PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */ PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */ @@ -15,6 +13,8 @@ namespace OpenVic { INT /* A discrete quantity, e.g. building count limit */ }; + friend std::unique_ptr<ModifierEffect> std::make_unique<ModifierEffect>(std::string_view&&, bool&&, format_t&&); + private: /* If true, positive values will be green and negative values will be red. * If false, the colours will be switced. diff --git a/src/openvic-simulation/country/Country.cpp b/src/openvic-simulation/country/Country.cpp index b2c4a71..9e244c1 100644 --- a/src/openvic-simulation/country/Country.cpp +++ b/src/openvic-simulation/country/Country.cpp @@ -45,9 +45,9 @@ CountryParty::policy_map_t const& CountryParty::get_policies() const { Country::Country( std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture, - std::vector<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, + IdentifierRegistry<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, government_colour_map_t&& new_alternative_colours -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, graphical_culture { new_graphical_culture }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, graphical_culture { new_graphical_culture }, parties { std::move(new_parties) }, unit_names { std::move(new_unit_names) }, dynamic_tag { new_dynamic_tag }, alternative_colours { std::move(new_alternative_colours) } {} @@ -55,10 +55,6 @@ GraphicalCultureType const& Country::get_graphical_culture() const { return graphical_culture; } -std::vector<CountryParty> const& Country::get_parties() const { - return parties; -} - Country::unit_names_map_t const& Country::get_unit_names() const { return unit_names; } @@ -75,7 +71,7 @@ CountryManager::CountryManager() : countries { "countries" } {} bool CountryManager::add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, - std::vector<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, + IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, Country::government_colour_map_t&& alternative_colours ) { if (identifier.empty()) { @@ -122,7 +118,7 @@ bool CountryManager::load_countries( [this, &game_manager, is_dynamic, &dataloader, &countries_dir, &key](std::string_view filepath) -> bool { if (load_country_data_file( game_manager, key, is_dynamic, - Dataloader::parse_defines(dataloader.lookup_file(countries_dir / filepath)).get_file_node() + Dataloader::parse_defines(dataloader.lookup_file_case_insensitive(countries_dir / filepath)).get_file_node() )) { return true; } @@ -141,7 +137,7 @@ bool CountryManager::load_countries( } node_callback_t CountryManager::load_country_party( - PoliticsManager const& politics_manager, std::vector<CountryParty>& country_parties + PoliticsManager const& politics_manager, IdentifierRegistry<CountryParty>& country_parties ) const { return [&politics_manager, &country_parties](ast::NodeCPtr value) -> bool { std::string_view party_name; @@ -149,7 +145,7 @@ node_callback_t CountryManager::load_country_party( Ideology const* ideology; CountryParty::policy_map_t policies; - const bool ret = expect_dictionary_keys_and_default( + bool ret = expect_dictionary_keys_and_default( [&politics_manager, &policies, &party_name](std::string_view key, ast::NodeCPtr value) -> bool { return politics_manager.get_issue_manager().expect_issue_group_str( [&politics_manager, &policies, value, &party_name](IssueGroup const& group) -> bool { @@ -163,9 +159,10 @@ node_callback_t CountryManager::load_country_party( policies.emplace(&group, &issue); return true; } - Logger::error("Invalid policy ", issue.get_identifier(), ", group is ", + // TODO - change this back to error/false once TGC no longer has this issue + Logger::warning("Invalid policy ", issue.get_identifier(), ", group is ", issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected"); - return false; + return true; } )(value); } @@ -178,7 +175,9 @@ node_callback_t CountryManager::load_country_party( politics_manager.get_ideology_manager().expect_ideology_identifier(assign_variable_callback_pointer(ideology)) )(value); - country_parties.emplace_back(CountryParty { party_name, start_date, end_date, *ideology, std::move(policies) }); + ret &= country_parties.add_item( + { party_name, start_date, end_date, *ideology, std::move(policies) }, duplicate_warning_callback + ); return ret; }; @@ -189,7 +188,7 @@ bool CountryManager::load_country_data_file( ) { colour_t colour; GraphicalCultureType const* graphical_culture; - std::vector<CountryParty> country_parties; + IdentifierRegistry<CountryParty> parties { "country parties" }; Country::unit_names_map_t unit_names; Country::government_colour_map_t alternative_colours; bool ret = expect_dictionary_keys_and_default( @@ -214,7 +213,7 @@ bool CountryManager::load_country_data_file( game_manager.get_pop_manager().get_culture_manager().expect_graphical_culture_type_identifier( assign_variable_callback_pointer(graphical_culture) ), - "party", ZERO_OR_MORE, load_country_party(game_manager.get_politics_manager(), country_parties), + "party", ZERO_OR_MORE, load_country_party(game_manager.get_politics_manager(), parties), "unit_names", ZERO_OR_ONE, game_manager.get_military_manager().get_unit_manager().expect_unit_dictionary( [&unit_names, &name](Unit const& unit, ast::NodeCPtr value) -> bool { @@ -230,7 +229,7 @@ bool CountryManager::load_country_data_file( )(root); ret &= add_country( - name, colour, graphical_culture, std::move(country_parties), std::move(unit_names), is_dynamic, + name, colour, graphical_culture, std::move(parties), std::move(unit_names), is_dynamic, std::move(alternative_colours) ); return ret; diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp index 1ab0e7e..7754a0b 100644 --- a/src/openvic-simulation/country/Country.hpp +++ b/src/openvic-simulation/country/Country.hpp @@ -5,7 +5,6 @@ #include <string> #include <string_view> #include <type_traits> -#include <unordered_map> #include <vector> #include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> @@ -64,22 +63,23 @@ namespace OpenVic { /* Not const to allow elements to be moved, otherwise a copy is forced * which causes a compile error as the copy constructor has been deleted. */ - std::vector<CountryParty> parties; + IdentifierRegistry<CountryParty> parties; const unit_names_map_t unit_names; const bool dynamic_tag; const government_colour_map_t alternative_colours; Country( std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture, - std::vector<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, + IdentifierRegistry<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, government_colour_map_t&& new_alternative_colours ); public: Country(Country&&) = default; + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(party, parties) + GraphicalCultureType const& get_graphical_culture() const; - std::vector<CountryParty> const& get_parties() const; unit_names_map_t const& get_unit_names() const; bool is_dynamic_tag() const; government_colour_map_t const& get_alternative_colours() const; @@ -90,7 +90,7 @@ namespace OpenVic { IdentifierRegistry<Country> countries; NodeTools::node_callback_t load_country_party( - PoliticsManager const& politics_manager, std::vector<CountryParty>& country_parties + PoliticsManager const& politics_manager, IdentifierRegistry<CountryParty>& country_parties ) const; public: @@ -98,10 +98,10 @@ namespace OpenVic { bool add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, - std::vector<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, + IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, Country::government_colour_map_t&& alternative_colours ); - IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(country, countries); + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(country, countries) bool load_countries( GameManager const& game_manager, Dataloader const& dataloader, fs::path const& countries_dir, ast::NodeCPtr root diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 0094253..e98e63b 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -34,13 +34,18 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; using namespace ovdl; -// Windows and Mac by default act like case insensitive filesystems -static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { -#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) + +static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::string_view rhs) { constexpr auto ichar_equals = [](unsigned char l, unsigned char r) { return std::tolower(l) == std::tolower(r); }; return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); +} + +// Windows and Mac by default act like case insensitive filesystems +static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { +#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) + return path_equals_case_insensitive(lhs, rhs); #else return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); #endif @@ -359,14 +364,36 @@ bool Dataloader::set_roots(path_vector_t const& new_roots) { return ret; } -fs::path Dataloader::lookup_file(fs::path const& path) const { +fs::path Dataloader::lookup_file(fs::path const& path, bool print_error) const { for (fs::path const& root : roots) { const fs::path composed = root / path; if (fs::is_regular_file(composed)) { return composed; } } - Logger::error("Lookup for ", path, " failed!"); + if (print_error) { + Logger::error("Lookup for ", path, " failed!"); + } + return {}; +} + +fs::path Dataloader::lookup_file_case_insensitive(fs::path const& path, bool print_error) const { + const std::string filename = path.filename().string(); + for (fs::path const& root : roots) { + const fs::path composed = root / path; + std::error_code ec; + for (fs::directory_entry const& entry : fs::directory_iterator { composed.parent_path(), ec }) { + if (entry.is_regular_file()) { + const fs::path file = entry; + if (path_equals_case_insensitive(file.filename().string(), filename)) { + return file; + } + } + } + } + if (print_error) { + Logger::error("Lookup for ", path, " failed!"); + } return {}; } @@ -398,8 +425,9 @@ Dataloader::path_vector_t Dataloader::lookup_files_in_dir(fs::path const& path, return ret; } -bool Dataloader::apply_to_files_in_dir(fs::path const& path, fs::path const& extension, callback_t<fs::path const&> callback) - const { +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)) { if (!callback(file)) { @@ -498,61 +526,37 @@ bool Dataloader::_load_units(UnitManager& unit_manager, GoodManager const& good_ return ret; } -bool Dataloader::_load_oobs(GameManager& game_manager) const { - static const fs::path oob_directory = "history/units"; - - /* used for countries with no defined initial OOB */ - game_manager.get_military_manager().get_deployment_manager().add_deployment( - "NULL", std::vector<Army>(), std::vector<Navy>(), std::vector<Leader>() - ); - - bool ret = apply_to_files_in_dir(oob_directory, ".txt", [&game_manager](fs::path const& file) -> bool { - if (file.filename() == "v2dd2.txt") { - return true; /* dev diary just stuck in there for no reason whatsoever */ - } - return game_manager.get_military_manager().get_deployment_manager().load_oob_file( - game_manager, file.filename().string(), parse_defines(file).get_file_node() - ); - }); - - /* we also load OOBs in top level subdirectories, for other start dates etc */ - for (auto root : roots) { - const fs::path path = root / oob_directory; - std::error_code ec; - for (fs::directory_entry const& entry : fs::directory_iterator { path, ec }) { - if (entry.is_directory()) { - ret &= apply_to_files_in_dir(entry, ".txt", [&entry, &game_manager](fs::path const& file) -> bool { - return game_manager.get_military_manager().get_deployment_manager().load_oob_file( - game_manager, (entry.path().filename() / file.filename()).string(), parse_defines(file).get_file_node() - ); - }); - } - } - } - - game_manager.get_military_manager().get_deployment_manager().lock_deployments(); - return ret; -} - bool Dataloader::_load_history(GameManager& game_manager) const { static const fs::path country_history_directory = "history/countries"; static const fs::path province_history_directory = "history/provinces"; /* Country History */ bool ret = apply_to_files_in_dir(country_history_directory, ".txt", [this, &game_manager](fs::path const& file) -> bool { - std::string tag = file.filename().string().substr(0, 3); - - if (!game_manager.get_country_manager().has_country_identifier(tag)) { - Logger::error("Error loading history for country ", tag, ": tag not defined!"); - return false; + const std::string filename = file.stem().string(); + // TODO - standardise rules on country idenifiers characters (probably letters + underscore) and enforce them + const size_t len = std::min(std::min(filename.find(" "), filename.find("-")), filename.length()); + const std::string_view country_id { filename.data(), len }; + + Country const* country = game_manager.get_country_manager().get_country_by_identifier(country_id); + if (country == nullptr) { + Logger::warning("Found history file for non-existent country: ", country_id); + return true; } return game_manager.get_history_manager().get_country_manager().load_country_history_file( - game_manager, tag, parse_defines(lookup_file(file)).get_file_node() + game_manager, *this, *country, parse_defines(lookup_file(file)).get_file_node() ); }); game_manager.get_history_manager().get_country_manager().lock_country_histories(); + { + DeploymentManager& deployment_manager = game_manager.get_military_manager().get_deployment_manager(); + deployment_manager.lock_deployments(); + if (deployment_manager.get_missing_oob_file_count() > 0) { + Logger::warning(deployment_manager.get_missing_oob_file_count(), " missing OOB files!"); + } + } + /* Province History */ for (auto root : roots) { const fs::path path = root / province_history_directory; @@ -560,16 +564,18 @@ bool Dataloader::_load_history(GameManager& game_manager) const { for (fs::directory_entry const& entry : fs::directory_iterator { path, ec }) { if (entry.is_directory()) { bool ret = apply_to_files_in_dir(entry, ".txt", [this, &game_manager](fs::path const& file) -> bool { - std::string province_id = file.filename().string(); - province_id = province_id.substr(0, province_id.find(" ")); + const std::string filename = file.stem().string(); + const size_t len = std::min(filename.find(" "), filename.length()); + const std::string_view province_id { filename.data(), len }; - if (!game_manager.get_map().has_province_identifier(province_id)) { - Logger::error("Error loading history for province ", province_id, ": province not defined!"); - return false; + Province const* province = game_manager.get_map().get_province_by_identifier(province_id); + if (province == nullptr) { + Logger::warning("Found history file for non-existent province: ", province_id); + return true; } return game_manager.get_history_manager().get_province_manager().load_province_history_file( - game_manager, province_id, parse_defines(lookup_file(file)).get_file_node() + game_manager, *province, parse_defines(lookup_file(file)).get_file_node() ); }); } @@ -808,10 +814,6 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load bookmarks!"); ret = false; } - if (!_load_oobs(game_manager)) { - Logger::error("Failed to load orders of battle!"); - ret = false; - } if (!game_manager.get_country_manager().load_countries( game_manager, *this, countries_file.parent_path(), parse_defines(lookup_file(countries_file)).get_file_node() )) { @@ -828,10 +830,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 game_manager.get_map() - .expect_province_dictionary([&game_manager](Province& province, ast::NodeCPtr value) -> bool { + 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); - })(parse_defines(file).get_file_node()); + } + )(parse_defines(file).get_file_node()); }); } diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index 508bf13..a8b8bb1 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -26,7 +26,6 @@ namespace OpenVic { bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager) const; bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager) const; bool _load_map_dir(GameManager& game_manager) const; - bool _load_oobs(GameManager& game_manager) const; bool _load_history(GameManager& game_manager) const; public: @@ -64,7 +63,8 @@ namespace OpenVic { /* REQUIREMENTS: * DAT-24 */ - fs::path lookup_file(fs::path const& path) const; + fs::path lookup_file(fs::path const& path, bool print_error = true) const; + fs::path lookup_file_case_insensitive(fs::path const& path, bool print_error = true) const; path_vector_t lookup_files_in_dir(fs::path const& path, fs::path const& extension) const; bool apply_to_files_in_dir( fs::path const& path, fs::path const& extension, NodeTools::callback_t<fs::path const&> callback @@ -74,24 +74,13 @@ namespace OpenVic { bool load_pop_history(GameManager& game_manager, fs::path const& path) const; enum locale_t : size_t { - English, - French, - German, - Polish, - Spanish, - Italian, - Swedish, - Czech, - Hungarian, - Dutch, - Portugese, - Russian, - Finnish, - _LocaleCount + English, French, German, Polish, Spanish, Italian, Swedish, + Czech, Hungarian, Dutch, Portugese, Russian, Finnish, _LocaleCount + }; + static constexpr char const* locale_names[_LocaleCount] = { + "en_GB", "fr_FR", "de_DE", "pl_PL", "es_ES", "it_IT", "sv_SE", + "cs_CZ", "hu_HU", "nl_NL", "pt_PT", "ru_RU", "fi_FI" }; - static constexpr char const* locale_names[_LocaleCount] = { "en_GB", "fr_FR", "de_DE", "pl_PL", "es_ES", - "it_IT", "sv_SE", "cs_CZ", "hu_HU", "nl_NL", - "pt_PT", "ru_RU", "fi_FI" }; /* Args: key, locale, localisation */ using localisation_callback_t = NodeTools::callback_t<std::string_view, locale_t, std::string_view>; diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index 2f93bc2..27d0f95 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -289,7 +289,7 @@ node_callback_t NodeTools::expect_dictionary(key_value_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()) { + if (!key_map.contains(key)) { key_map.emplace(key, dictionary_entry_t { expected_count, callback }); return true; } @@ -318,7 +318,12 @@ key_value_callback_t NodeTools::dictionary_keys_callback(key_map_t& key_map, key Logger::error("Invalid repeat of dictionary key: ", key); return false; } - return entry.callback(value); + if (entry.callback(value)) { + return true; + } else { + Logger::error("Callback failed for dictionary key: ", key); + return false; + } }; } diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 798976f..4d56488 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -66,7 +66,7 @@ namespace OpenVic { } node_callback_t expect_identifier(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_string(callback_t<std::string_view> callback, bool allow_empty = false); node_callback_t expect_identifier_or_string(callback_t<std::string_view> callback, bool allow_empty = false); node_callback_t expect_bool(callback_t<bool> callback); @@ -261,15 +261,8 @@ namespace OpenVic { }; } - template<std::integral T> - callback_t<T> assign_variable_callback_cast(auto& var) { - return [&var](T val) -> bool { - var = val; - return true; - }; - } - - template<std::signed_integral T> + template<typename T> + requires std::is_integral_v<T> || std::is_enum_v<T> callback_t<T> assign_variable_callback_cast(auto& var) { return [&var](T val) -> bool { var = val; diff --git a/src/openvic-simulation/economy/Good.cpp b/src/openvic-simulation/economy/Good.cpp index 11230d2..2b1d694 100644 --- a/src/openvic-simulation/economy/Good.cpp +++ b/src/openvic-simulation/economy/Good.cpp @@ -10,7 +10,7 @@ GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { ne Good::Good( std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, category { new_category }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, category { new_category }, base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable }, money { new_money }, overseas_penalty { new_overseas_penalty } { assert(base_price > NULL_PRICE); diff --git a/src/openvic-simulation/history/Bookmark.hpp b/src/openvic-simulation/history/Bookmark.hpp index e93718f..d5253fe 100644 --- a/src/openvic-simulation/history/Bookmark.hpp +++ b/src/openvic-simulation/history/Bookmark.hpp @@ -42,9 +42,10 @@ namespace OpenVic { BookmarkManager(); bool add_bookmark( - std::string_view name, std::string_view description, Date date, uint32_t initial_camera_x, uint32_t initial_camera_y + std::string_view name, std::string_view description, Date date, uint32_t initial_camera_x, + uint32_t initial_camera_y ); - IDENTIFIER_REGISTRY_ACCESSORS(bookmark); + IDENTIFIER_REGISTRY_ACCESSORS(bookmark) bool load_bookmark_file(ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index ed72f52..cd682bd 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -7,7 +7,7 @@ using namespace OpenVic::NodeTools; CountryHistory::CountryHistory( Culture const* new_primary_culture, std::vector<Culture const*>&& new_accepted_cultures, Religion const* new_religion, - CountryParty const* new_ruling_party, Date new_last_election, std::map<Ideology const*, fixed_point_t>&& new_upper_house, + CountryParty const* new_ruling_party, Date new_last_election, decimal_map_t<Ideology const*>&& new_upper_house, Province const* new_capital, GovernmentType const* new_government_type, fixed_point_t new_plurality, NationalValue const* new_national_value, bool new_civilised, fixed_point_t new_prestige, std::vector<Reform const*>&& new_reforms, Deployment const* new_inital_oob @@ -21,7 +21,7 @@ Culture const* CountryHistory::get_primary_culture() const { return primary_culture; } -const std::vector<Culture const*>& CountryHistory::get_accepted_cultures() const { +std::vector<Culture const*> const& CountryHistory::get_accepted_cultures() const { return accepted_cultures; } @@ -37,7 +37,7 @@ Date CountryHistory::get_last_election() const { return last_election; } -const std::map<Ideology const*, fixed_point_t>& CountryHistory::get_upper_house() const { +decimal_map_t<Ideology const*> const& CountryHistory::get_upper_house() const { return upper_house; } @@ -49,7 +49,7 @@ GovernmentType const* CountryHistory::get_government_type() const { return government_type; } -const fixed_point_t CountryHistory::get_plurality() const { +fixed_point_t CountryHistory::get_plurality() const { return plurality; } @@ -57,15 +57,15 @@ NationalValue const* CountryHistory::get_national_value() const { return national_value; } -const bool CountryHistory::is_civilised() const { +bool CountryHistory::is_civilised() const { return civilised; } -const fixed_point_t CountryHistory::get_prestige() const { +fixed_point_t CountryHistory::get_prestige() const { return prestige; } -const std::vector<Reform const*>& CountryHistory::get_reforms() const { +std::vector<Reform const*> const& CountryHistory::get_reforms() const { return reforms; } @@ -76,9 +76,9 @@ Deployment const* CountryHistory::get_inital_oob() const { bool CountryHistoryManager::add_country_history_entry( Country const* country, Date date, Culture const* primary_culture, std::vector<Culture const*>&& accepted_cultures, Religion const* religion, CountryParty const* ruling_party, Date last_election, - std::map<Ideology const*, fixed_point_t>&& upper_house, Province const* capital, GovernmentType const* government_type, + decimal_map_t<Ideology const*>&& upper_house, Province const* capital, GovernmentType const* government_type, fixed_point_t plurality, NationalValue const* national_value, bool civilised, fixed_point_t prestige, - std::vector<Reform const*>&& reforms, Deployment const* initial_oob, bool updated_accepted_cultures, + std::vector<Reform const*>&& reforms, std::optional<Deployment const*> initial_oob, bool updated_accepted_cultures, bool updated_upper_house, bool updated_reforms ) { if (locked) { @@ -87,8 +87,8 @@ bool CountryHistoryManager::add_country_history_entry( } /* combine duplicate histories, priority to current (defined later) */ - auto& country_registry = country_histories[country]; - const auto existing_entry = country_registry.find(date); + country_history_map_t& country_registry = country_histories[country]; + const country_history_map_t::iterator existing_entry = country_registry.find(date); if (existing_entry != country_registry.end()) { if (primary_culture != nullptr) { @@ -130,15 +130,15 @@ bool CountryHistoryManager::add_country_history_entry( if (updated_reforms) { existing_entry->second.reforms = std::move(reforms); } - if (initial_oob != nullptr) { - existing_entry->second.inital_oob = initial_oob; + if (initial_oob) { + existing_entry->second.inital_oob = *initial_oob; } } else { country_registry.emplace( date, CountryHistory { primary_culture, std::move(accepted_cultures), religion, ruling_party, last_election, std::move(upper_house), capital, government_type, plurality, national_value, civilised, - prestige, std::move(reforms), initial_oob + prestige, std::move(reforms), std::move(*initial_oob) } ); } @@ -195,57 +195,68 @@ inline CountryHistory const* CountryHistoryManager::get_country_history(Country } inline bool CountryHistoryManager::_load_country_history_entry( - GameManager& game_manager, std::string_view name, Date date, ast::NodeCPtr root + GameManager& game_manager, Dataloader const& dataloader, Country const& country, Date date, ast::NodeCPtr root ) { + PoliticsManager const& politics_manager = game_manager.get_politics_manager(); + IssueManager const& issue_manager = politics_manager.get_issue_manager(); + CultureManager const& culture_manager = game_manager.get_pop_manager().get_culture_manager(); + Province const* capital = nullptr; Culture const* primary_culture = nullptr; Religion const* religion = nullptr; GovernmentType const* government_type = nullptr; NationalValue const* national_value = nullptr; CountryParty const* ruling_party = nullptr; - std::vector<Culture const*> accepted_cultures; - std::vector<Reform const*> reforms; - std::map<Ideology const*, fixed_point_t> upper_house; + std::vector<Culture const*> accepted_cultures {}; + std::vector<Reform const*> reforms {}; + decimal_map_t<Ideology const*> upper_house {}; fixed_point_t plurality = -1, prestige = -1; bool civilised = false; Date last_election {}; - Deployment const* initial_oob = nullptr; + std::optional<Deployment const*> initial_oob; bool updated_accepted_cultures = false, updated_upper_house = false, updated_reforms = false; bool ret = expect_dictionary_keys_and_default( - [this, &game_manager, &reforms, &updated_reforms, &name](std::string_view key, ast::NodeCPtr value) -> bool { - if (game_manager.get_politics_manager().get_issue_manager().has_reform_group_identifier(key)) { + [this, &issue_manager, &reforms, &updated_reforms, &country](std::string_view key, ast::NodeCPtr value) -> bool { + ReformGroup const* reform_group = issue_manager.get_reform_group_by_identifier(key); + if (reform_group != nullptr) { updated_reforms = true; - - Reform const* reform; - - bool ret = game_manager.get_politics_manager().get_issue_manager() - .expect_reform_identifier(assign_variable_callback_pointer(reform))(value); - if (std::find(reforms.begin(), reforms.end(), reform) != reforms.end()) { - Logger::error("Redefinition of reform ", reform->get_identifier(), " in history of ", name); - return false; - } - - reforms.push_back(reform); - return ret; + return issue_manager.expect_reform_identifier( + [reform_group, &reforms, &country](Reform const& reform) -> bool { + if (&reform.get_reform_group() != reform_group) { + Logger::warning( + "Listing ", reform.get_identifier(), " as belonging to the reform group ", + reform_group->get_identifier(), " when it actually belongs to ", + reform.get_reform_group().get_identifier() + ); + } + if (std::find(reforms.begin(), reforms.end(), &reform) != reforms.end()) { + Logger::error( + "Redefinition of reform ", reform.get_identifier(), " in history of ", country.get_identifier() + ); + return false; + } + reforms.push_back(&reform); + return true; + } + )(value); } // TODO: technologies & inventions return true; }, /* we have to use a lambda, assign_variable_callback_pointer * apparently doesn't play nice with const & non-const accessors */ + // TODO - fix this issue (cause by provinces having non-const accessors) "capital", ZERO_OR_ONE, game_manager.get_map().expect_province_identifier([&capital](Province const& province) -> bool { capital = &province; return true; }), "primary_culture", ZERO_OR_ONE, - game_manager.get_pop_manager().get_culture_manager().expect_culture_identifier( - assign_variable_callback_pointer(primary_culture) - ), + culture_manager.expect_culture_identifier(assign_variable_callback_pointer(primary_culture)), "culture", ZERO_OR_MORE, - game_manager.get_pop_manager().get_culture_manager().expect_culture_identifier( + culture_manager.expect_culture_identifier( [&game_manager, &accepted_cultures, &updated_accepted_cultures](Culture const& culture) -> bool { updated_accepted_cultures = true; accepted_cultures.push_back(&culture); @@ -257,102 +268,62 @@ inline bool CountryHistoryManager::_load_country_history_entry( assign_variable_callback_pointer(religion) ), "government", ZERO_OR_ONE, - game_manager.get_politics_manager().get_government_type_manager().expect_government_type_identifier( + politics_manager.get_government_type_manager().expect_government_type_identifier( assign_variable_callback_pointer(government_type) ), "plurality", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(plurality)), "nationalvalue", ZERO_OR_ONE, - game_manager.get_politics_manager().get_national_value_manager().expect_national_value_identifier( + politics_manager.get_national_value_manager().expect_national_value_identifier( assign_variable_callback_pointer(national_value) ), "civilized", ZERO_OR_ONE, expect_bool(assign_variable_callback(civilised)), "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(prestige)), - "ruling_party", ZERO_OR_ONE, - expect_identifier([this, &game_manager, &ruling_party, &name, &date](std::string_view identifier) -> bool { - const std::vector<CountryParty>* parties = - &game_manager.get_country_manager().get_country_by_identifier(name)->get_parties(); - for (auto& party : *parties) { - if (party.get_identifier() == identifier) { - if (party.get_start_date() <= date && date <= party.get_end_date()) { - ruling_party = &party; - return true; - } else { - if (party.get_start_date() > date) { - Logger::warning( - "Ruling party ", identifier, " of country ", name, " has invalid start date ", - party.get_start_date(), " for bookmark: ", date.to_string() - ); - } - if (party.get_end_date() < date) { - Logger::warning( - "Ruling party ", identifier, " of country ", name, " has invalid end date ", - party.get_end_date(), " for bookmark: ", date.to_string() - ); - } - ruling_party = &party; - return true; - } - } - } - Logger::error("Ruling party ", identifier, " of country ", name, " is not defined!"); - return false; - }), + "ruling_party", ZERO_OR_ONE, country.expect_party_identifier(assign_variable_callback_pointer(ruling_party)), "last_election", ZERO_OR_ONE, expect_date(assign_variable_callback(last_election)), "upper_house", ZERO_OR_ONE, - game_manager.get_politics_manager().get_ideology_manager().expect_ideology_dictionary( + politics_manager.get_ideology_manager().expect_ideology_dictionary( [&upper_house, &updated_upper_house](Ideology const& ideology, ast::NodeCPtr value) -> bool { - fixed_point_t popularity; - - updated_upper_house = true; - bool ret = expect_fixed_point(assign_variable_callback(popularity))(value); - upper_house.emplace(&ideology, popularity); - return ret; - } - ), - "oob", ZERO_OR_ONE, - [&game_manager, &initial_oob](ast::NodeCPtr node) -> bool { - std::string_view string; - expect_string(assign_variable_callback(string))(node); - - if (string.starts_with('/')) { - if (game_manager.get_military_manager().get_deployment_manager() - .has_deployment_identifier(string.substr(1))) { - initial_oob = game_manager.get_military_manager().get_deployment_manager() - .get_deployment_by_identifier(string.substr(1)); + return expect_fixed_point([&upper_house, &updated_upper_house, &ideology](fixed_point_t val) -> bool { + if (val != 0) { + upper_house[&ideology] += val; + updated_upper_house = true; + } return true; - } - } else { - if (game_manager.get_military_manager().get_deployment_manager().has_deployment_identifier(string)) { - initial_oob = - game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier(string); - } + })(value); } - - initial_oob = - game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier("NULL"); - return true; - }, + ), + "oob", ZERO_OR_ONE, expect_identifier_or_string([&game_manager, &dataloader, &initial_oob](std::string_view path) -> bool { + if(!initial_oob.has_value()) + initial_oob = decltype(initial_oob)::value_type {}; + return game_manager.get_military_manager().get_deployment_manager().load_oob_file( + game_manager, dataloader, path, *initial_oob, false + ); + }), "schools", ZERO_OR_ONE, success_callback, // TODO: technology school "foreign_investment", ZERO_OR_ONE, success_callback // TODO: foreign investment )(root); ret &= add_country_history_entry( - game_manager.get_country_manager().get_country_by_identifier(name), date, primary_culture, + &country, date, primary_culture, std::move(accepted_cultures), religion, ruling_party, last_election, std::move(upper_house), capital, government_type, - plurality, national_value, civilised, prestige, std::move(reforms), initial_oob, updated_accepted_cultures, + plurality, national_value, civilised, prestige, std::move(reforms), std::move(initial_oob), updated_accepted_cultures, updated_upper_house, updated_reforms ); return ret; } -bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root) { - if (game_manager.get_country_manager().get_country_by_identifier(name)->is_dynamic_tag()) { +bool CountryHistoryManager::load_country_history_file( + GameManager& game_manager, Dataloader const& dataloader, Country const& country, ast::NodeCPtr root +) { + if (country.is_dynamic_tag()) { return true; /* as far as I can tell dynamic countries are hardcoded, broken, and unused */ } - bool ret = _load_country_history_entry(game_manager, name, game_manager.get_define_manager().get_start_date(), root); + bool ret = _load_country_history_entry( + game_manager, dataloader, country, game_manager.get_define_manager().get_start_date(), root + ); - ret &= expect_dictionary([this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool { + ret &= expect_dictionary([this, &game_manager, &dataloader, &country](std::string_view key, ast::NodeCPtr value) -> bool { bool is_date = false; Date entry = Date::from_string(key, &is_date, true); if (!is_date) { @@ -362,13 +333,13 @@ bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, Date end_date = game_manager.get_define_manager().get_end_date(); if (entry > end_date) { Logger::error( - "History entry ", entry.to_string(), " of country ", name, " defined after defined end date ", - end_date.to_string() + "History entry ", entry.to_string(), " of country ", country.get_identifier(), + " defined after defined end date ", end_date.to_string() ); return false; } - return _load_country_history_entry(game_manager, name, entry, value); + return _load_country_history_entry(game_manager, dataloader, country, entry, value); })(root); return ret; diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index 0401ec4..3109d4f 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -28,7 +28,7 @@ namespace OpenVic { Religion const* religion; CountryParty const* ruling_party; Date last_election; - std::map<Ideology const*, fixed_point_t> upper_house; + decimal_map_t<Ideology const*> upper_house; Province const* capital; GovernmentType const* government_type; fixed_point_t plurality; @@ -43,7 +43,7 @@ namespace OpenVic { CountryHistory( Culture const* new_primary_culture, std::vector<Culture const*>&& new_accepted_cultures, Religion const* new_religion, CountryParty const* new_ruling_party, Date new_last_election, - std::map<Ideology const*, fixed_point_t>&& new_upper_house, Province const* new_capital, + decimal_map_t<Ideology const*>&& new_upper_house, Province const* new_capital, GovernmentType const* new_government_type, fixed_point_t new_plurality, NationalValue const* new_national_value, bool new_civilised, fixed_point_t new_prestige, std::vector<Reform const*>&& new_reforms, Deployment const* new_inital_oob @@ -51,28 +51,30 @@ namespace OpenVic { public: Culture const* get_primary_culture() const; - const std::vector<Culture const*>& get_accepted_cultures() const; + std::vector<Culture const*> const& get_accepted_cultures() const; Religion const* get_religion() const; CountryParty const* get_ruling_party() const; Date get_last_election() const; - const std::map<Ideology const*, fixed_point_t>& get_upper_house() const; + decimal_map_t<Ideology const*> const& get_upper_house() const; Province const* get_capital() const; GovernmentType const* get_government_type() const; - const fixed_point_t get_plurality() const; + fixed_point_t get_plurality() const; NationalValue const* get_national_value() const; - const bool is_civilised() const; - const fixed_point_t get_prestige() const; - const std::vector<Reform const*>& get_reforms() const; + bool is_civilised() const; + fixed_point_t get_prestige() const; + std::vector<Reform const*> const& get_reforms() const; Deployment const* get_inital_oob() const; }; struct CountryHistoryManager { private: - std::map<Country const*, std::map<Date, CountryHistory>> country_histories; + using country_history_map_t = std::map<Date, CountryHistory>; + std::map<Country const*, country_history_map_t> country_histories; bool locked = false; inline bool _load_country_history_entry( - GameManager& game_manager, std::string_view name, Date date, ast::NodeCPtr root + GameManager& game_manager, Dataloader const& dataloader, Country const& country, Date date, + ast::NodeCPtr root ); public: @@ -81,10 +83,10 @@ namespace OpenVic { bool add_country_history_entry( Country const* country, Date date, Culture const* primary_culture, std::vector<Culture const*>&& accepted_cultures, Religion const* religion, CountryParty const* ruling_party, Date last_election, - std::map<Ideology const*, fixed_point_t>&& upper_house, Province const* capital, - GovernmentType const* government_type, fixed_point_t plurality, NationalValue const* national_value, bool civilised, - fixed_point_t prestige, std::vector<Reform const*>&& reforms, Deployment const* initial_oob, - bool updated_accepted_cultures, bool updated_upper_house, bool updated_reforms + decimal_map_t<Ideology const*>&& upper_house, Province const* capital, GovernmentType const* government_type, + fixed_point_t plurality, NationalValue const* national_value, bool civilised, fixed_point_t prestige, + std::vector<Reform const*>&& reforms, std::optional<Deployment const*> initial_oob, bool updated_accepted_cultures, + bool updated_upper_house, bool updated_reforms ); void lock_country_histories(); @@ -96,7 +98,9 @@ namespace OpenVic { /* Returns history of country at bookmark date. Return can be nullptr if an error occurs. */ inline CountryHistory const* get_country_history(Country const* country, Bookmark const* entry) const; - bool load_country_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root); + bool load_country_history_file( + GameManager& game_manager, Dataloader const& dataloader, Country const& country, ast::NodeCPtr root + ); }; } // namespace OpenVic diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index 6dbf6a4..65e37e1 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -7,9 +7,10 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; ProvinceHistory::ProvinceHistory( - Country const* new_owner, Country const* new_controller, uint8_t new_colonial, bool new_slave, - std::vector<Country const*>&& new_cores, Good const* new_rgo, uint8_t new_life_rating, TerrainType const* new_terrain_type, - std::map<Building const*, uint8_t>&& new_buildings, std::map<Ideology const*, uint8_t>&& new_party_loyalties + Country const* new_owner, Country const* new_controller, Province::colony_status_t new_colonial, bool new_slave, + std::vector<Country const*>&& new_cores, Good const* new_rgo, Province::life_rating_t new_life_rating, + TerrainType const* new_terrain_type, building_level_map_t&& new_buildings, + decimal_map_t<Ideology const*>&& new_party_loyalties ) : owner { new_owner }, controller { new_controller }, colonial { new_colonial }, slave { new_slave }, cores { std::move(new_cores) }, rgo { new_rgo }, life_rating { new_life_rating }, terrain_type { new_terrain_type }, buildings { std::move(new_buildings) }, party_loyalties { std::move(new_party_loyalties) } {} @@ -22,7 +23,7 @@ Country const* ProvinceHistory::get_controller() const { return controller; } -uint8_t ProvinceHistory::get_colony_status() const { +Province::colony_status_t ProvinceHistory::get_colony_status() const { return colonial; } @@ -42,7 +43,7 @@ Good const* ProvinceHistory::get_rgo() const { return rgo; } -uint8_t ProvinceHistory::get_life_rating() const { +Province::life_rating_t ProvinceHistory::get_life_rating() const { return life_rating; } @@ -50,20 +51,20 @@ TerrainType const* ProvinceHistory::get_terrain_type() const { return terrain_type; } -std::map<Building const*, uint8_t> const& ProvinceHistory::get_buildings() const { +ProvinceHistory::building_level_map_t const& ProvinceHistory::get_buildings() const { return buildings; } -std::map<Ideology const*, uint8_t> const& ProvinceHistory::get_party_loyalties() const { +decimal_map_t<Ideology const*> const& ProvinceHistory::get_party_loyalties() const { return party_loyalties; } bool ProvinceHistoryManager::add_province_history_entry( - Province const* province, Date date, Country const* owner, Country const* controller, std::optional<uint8_t>&& colonial, - std::optional<bool>&& slave, std::vector<Country const*>&& cores, std::vector<Country const*>&& remove_cores, - Good const* rgo, std::optional<uint8_t>&& life_rating, TerrainType const* terrain_type, - std::optional<std::map<Building const*, uint8_t>>&& buildings, - std::optional<std::map<Ideology const*, uint8_t>>&& party_loyalties + Province const* province, Date date, Country const* owner, Country const* controller, + std::optional<Province::colony_status_t>&& colonial, std::optional<bool>&& slave, std::vector<Country const*>&& cores, + std::vector<Country const*>&& remove_cores, Good const* rgo, std::optional<Province::life_rating_t>&& life_rating, + TerrainType const* terrain_type, std::optional<ProvinceHistory::building_level_map_t>&& buildings, + std::optional<decimal_map_t<Ideology const*>>&& party_loyalties ) { if (locked) { Logger::error("Cannot add new history entry to province history registry: locked!"); @@ -104,7 +105,7 @@ bool ProvinceHistoryManager::add_province_history_entry( } // province history cores are additive existing_entry->second.cores.insert(existing_entry->second.cores.end(), cores.begin(), cores.end()); - for (const auto which : remove_cores) { + for (Country const* which : remove_cores) { const auto core = std::find(cores.begin(), cores.end(), which); if (core == cores.end()) { Logger::error( @@ -176,114 +177,109 @@ inline ProvinceHistory const* ProvinceHistoryManager::get_province_history( } inline bool ProvinceHistoryManager::_load_province_history_entry( - GameManager& game_manager, std::string_view province, Date date, ast::NodeCPtr root + GameManager const& game_manager, Province const& province, Date date, ast::NodeCPtr root, + bool is_base_entry ) { + BuildingManager const& building_manager = game_manager.get_economy_manager().get_building_manager(); + CountryManager const& country_manager = game_manager.get_country_manager(); + GoodManager const& good_manager = game_manager.get_economy_manager().get_good_manager(); + IdeologyManager const& ideology_manager = game_manager.get_politics_manager().get_ideology_manager(); + TerrainTypeManager const& terrain_type_manager = game_manager.get_map().get_terrain_type_manager(); + Country const* owner = nullptr; Country const* controller = nullptr; - std::vector<Country const*> cores; - std::vector<Country const*> remove_cores; - Good const* rgo; - std::optional<uint8_t> life_rating, colonial; + std::vector<Country const*> cores {}; + std::vector<Country const*> remove_cores {}; + Good const* rgo = nullptr; + std::optional<Province::colony_status_t> colonial; + std::optional<Province::life_rating_t> life_rating; std::optional<bool> slave; - TerrainType const* terrain_type; - std::optional<std::map<Building const*, uint8_t>> buildings; - std::optional<std::map<Ideology const*, uint8_t>> party_loyalties; + TerrainType const* terrain_type = nullptr; + std::optional<ProvinceHistory::building_level_map_t> buildings; + std::optional<decimal_map_t<Ideology const*>> party_loyalties; + + using enum Province::colony_status_t; + static const string_map_t<Province::colony_status_t> colony_status_map { + { "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY } + }; bool ret = expect_dictionary_keys_and_default( - [&game_manager, &buildings](std::string_view key, ast::NodeCPtr value) -> bool { + [&building_manager, &buildings, date, is_base_entry](std::string_view key, ast::NodeCPtr value) -> bool { // used for province buildings like forts or railroads - if (game_manager.get_economy_manager().get_building_manager().has_building_identifier(key)) { - Building const* building; - uint8_t level; - - bool ret = game_manager.get_economy_manager().get_building_manager() - .expect_building_str(assign_variable_callback_pointer(building))(key); - ret &= expect_uint(assign_variable_callback(level))(value); - - if(!buildings.has_value()) - buildings = decltype(buildings)::value_type {}; - buildings->emplace(building, level); - return ret; + Building const* building = building_manager.get_building_by_identifier(key); + if (building != nullptr) { + return expect_uint<Building::level_t>([&buildings, building](Building::level_t level) -> bool { + if(!buildings.has_value()) + buildings = decltype(buildings)::value_type {}; + buildings->emplace(building, level); + return true; + })(value); } - bool is_date; - Date::from_string(key, &is_date, true); + /* Date blocks are skipped here (they get their own invocation of _load_province_history_entry) */ + bool is_date = false; + const Date sub_date { Date::from_string(key, &is_date, true) }; if (is_date) { - return true; + if (is_base_entry) { + return true; + } else { + Logger::error( + "Province history nested multiple levels deep! ", sub_date, " is inside ", date, + " (Any date blocks within a date block are ignored)" + ); + return false; + } } return key_value_invalid_callback(key, value); }, - "owner", ZERO_OR_ONE, game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(owner)), - "controller", ZERO_OR_ONE, game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(controller)), - "add_core", ZERO_OR_MORE, [&game_manager, &cores](ast::NodeCPtr node) -> bool { - Country const* core; - - bool ret = game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(core))(node); - cores.push_back(core); - return ret; - }, - "remove_core", ZERO_OR_MORE, [&game_manager, &remove_cores](ast::NodeCPtr node) -> bool { - Country const* remove; - - bool ret = game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(remove))(node); - remove_cores.push_back(remove); - return ret; - }, - "colonial", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool { - colonial = colony_level; - - return true; - }), - "colony", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool { - colonial = colony_level; - - return true; - }), - "is_slave", ZERO_OR_ONE, expect_bool([&slave](bool is_slave) -> bool { - if (is_slave) { - slave = true; - } else { - slave = false; + "owner", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(owner)), + "controller", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(controller)), + "add_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&cores](Country const& core) -> bool { + cores.push_back(&core); + return true; } - - return true; - }), - "trade_goods", ZERO_OR_ONE, game_manager.get_economy_manager().get_good_manager() - .expect_good_identifier(assign_variable_callback_pointer(rgo)), - "life_rating", ZERO_OR_ONE, expect_uint<uint8_t>([&life_rating](uint8_t rating) -> bool { - life_rating = rating; - - return true; - }), - "terrain", ZERO_OR_ONE, game_manager.get_map().get_terrain_type_manager() - .expect_terrain_type_identifier(assign_variable_callback_pointer(terrain_type)), - "party_loyalty", ZERO_OR_MORE, [&game_manager, &party_loyalties](ast::NodeCPtr node) -> bool { - Ideology const* ideology; - uint8_t amount; // percent I do believe - - bool ret = expect_dictionary_keys( - "ideology", ONE_EXACTLY, game_manager.get_politics_manager().get_ideology_manager() - .expect_ideology_identifier(assign_variable_callback_pointer(ideology)), - "loyalty_value", ONE_EXACTLY, expect_uint(assign_variable_callback(amount)) + ), + "remove_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&remove_cores](Country const& core) -> bool { + remove_cores.push_back(&core); + return true; + } + ), + "colonial", ZERO_OR_ONE, + expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(colonial))), + "colony", ZERO_OR_ONE, expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(colonial))), + "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(slave)), + "trade_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(rgo)), + "life_rating", ZERO_OR_ONE, expect_uint<Province::life_rating_t>(assign_variable_callback(life_rating)), + "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier( + assign_variable_callback_pointer(terrain_type) + ), + "party_loyalty", ZERO_OR_MORE, [&ideology_manager, &party_loyalties](ast::NodeCPtr node) -> bool { + Ideology const* ideology = nullptr; + fixed_point_t amount = 0; // percent I do believe + + const bool ret = expect_dictionary_keys( + "ideology", ONE_EXACTLY, ideology_manager.expect_ideology_identifier( + assign_variable_callback_pointer(ideology) + ), + "loyalty_value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(amount)) )(node); if(!party_loyalties.has_value()) party_loyalties = decltype(party_loyalties)::value_type {}; party_loyalties->emplace(ideology, amount); return ret; }, - "state_building", ZERO_OR_MORE, [&game_manager, &buildings](ast::NodeCPtr node) -> bool { - Building const* building; - uint8_t level; + "state_building", ZERO_OR_MORE, [&building_manager, &buildings](ast::NodeCPtr node) -> bool { + Building const* building = nullptr; + uint8_t level = 0; - bool ret = expect_dictionary_keys( + const bool ret = expect_dictionary_keys( "level", ONE_EXACTLY, expect_uint(assign_variable_callback(level)), - "building", ONE_EXACTLY, game_manager.get_economy_manager().get_building_manager() - .expect_building_identifier(assign_variable_callback_pointer(building)), + "building", ONE_EXACTLY, building_manager.expect_building_identifier( + assign_variable_callback_pointer(building) + ), "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect )(node); if(!buildings.has_value()) @@ -294,34 +290,37 @@ inline bool ProvinceHistoryManager::_load_province_history_entry( )(root); ret &= add_province_history_entry( - game_manager.get_map().get_province_by_identifier(province), date, owner, controller, std::move(colonial), std::move(slave), - std::move(cores), std::move(remove_cores), rgo, std::move(life_rating), terrain_type, std::move(buildings), - std::move(party_loyalties) + &province, date, owner, controller, std::move(colonial), std::move(slave), std::move(cores), std::move(remove_cores), + rgo, std::move(life_rating), terrain_type, std::move(buildings), std::move(party_loyalties) ); return ret; } -bool ProvinceHistoryManager::load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root) { - bool ret = _load_province_history_entry(game_manager, name, game_manager.get_define_manager().get_start_date(), root); +bool ProvinceHistoryManager::load_province_history_file( + GameManager const& game_manager, Province const& province, ast::NodeCPtr root +) { + bool ret = _load_province_history_entry( + game_manager, province, game_manager.get_define_manager().get_start_date(), root, true + ); ret &= expect_dictionary( - [this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool { + [this, &game_manager, &province, end_date = game_manager.get_define_manager().get_end_date()]( + std::string_view key, ast::NodeCPtr value) -> bool { bool is_date = false; - Date entry = Date::from_string(key, &is_date, true); + const Date entry = Date::from_string(key, &is_date, true); if (!is_date) { return true; } - Date end_date = game_manager.get_define_manager().get_end_date(); if (entry > end_date) { Logger::error( - "History entry ", entry.to_string(), " of province ", name, " defined after defined end date ", - end_date.to_string() + "History entry ", entry, " of province ", province.get_identifier(), + " defined after defined end date ", end_date ); return false; } - return _load_province_history_entry(game_manager, name, entry, value); + return _load_province_history_entry(game_manager, province, entry, value, false); } )(root); diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 90c87e2..fb90cc4 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -17,37 +17,39 @@ namespace OpenVic { struct ProvinceHistory { friend struct ProvinceHistoryManager; + using building_level_map_t = std::map<Building const*, Building::level_t>; + private: Country const* owner; Country const* controller; - uint8_t colonial; + Province::colony_status_t colonial; bool slave; std::vector<Country const*> cores; // non-standard, maintains cores between entries Good const* rgo; - uint8_t life_rating; + Province::life_rating_t life_rating; TerrainType const* terrain_type; - std::map<Building const*, uint8_t> buildings; - std::map<Ideology const*, uint8_t> party_loyalties; + building_level_map_t buildings; + decimal_map_t<Ideology const*> party_loyalties; ProvinceHistory( - Country const* new_owner, Country const* new_controller, uint8_t new_colonial, bool new_slave, - std::vector<Country const*>&& new_cores, Good const* new_rgo, uint8_t new_life_rating, - TerrainType const* new_terrain_type, std::map<Building const*, uint8_t>&& new_buildings, - std::map<Ideology const*, uint8_t>&& new_party_loyalties + Country const* new_owner, Country const* new_controller, Province::colony_status_t new_colonial, bool new_slave, + std::vector<Country const*>&& new_cores, Good const* new_rgo, Province::life_rating_t new_life_rating, + TerrainType const* new_terrain_type, building_level_map_t&& new_buildings, + decimal_map_t<Ideology const*>&& new_party_loyalties ); public: Country const* get_owner() const; Country const* get_controller() const; - uint8_t get_colony_status() const; // 0 = state, 1 = protectorate, 2 = colony + Province::colony_status_t get_colony_status() const; // 0 = state, 1 = protectorate, 2 = colony bool is_slave() const; std::vector<Country const*> const& get_cores() const; bool is_core_of(Country const* country) const; Good const* get_rgo() const; - uint8_t get_life_rating() const; + Province::life_rating_t get_life_rating() const; TerrainType const* get_terrain_type() const; - std::map<Building const*, uint8_t> const& get_buildings() const; - std::map<Ideology const*, uint8_t> const& get_party_loyalties() const; + building_level_map_t const& get_buildings() const; + decimal_map_t<Ideology const*> const& get_party_loyalties() const; }; struct ProvinceHistoryManager { @@ -56,7 +58,8 @@ namespace OpenVic { bool locked = false; inline bool _load_province_history_entry( - GameManager& game_manager, std::string_view province, Date date, ast::NodeCPtr root + GameManager const& game_manager, Province const& province, Date date, ast::NodeCPtr root, + bool is_base_entry ); public: @@ -64,12 +67,12 @@ namespace OpenVic { bool add_province_history_entry( Province const* province, Date date, Country const* owner, Country const* controller, - std::optional<uint8_t>&& colonial, std::optional<bool>&& slave, + std::optional<Province::colony_status_t>&& colonial, std::optional<bool>&& slave, std::vector<Country const*>&& cores, // additive to existing entries std::vector<Country const*>&& remove_cores, // existing cores that need to be removed - Good const* rgo, std::optional<uint8_t>&& life_rating, TerrainType const* terrain_type, - std::optional<std::map<Building const*, uint8_t>>&& buildings, - std::optional<std::map<Ideology const*, uint8_t>>&& party_loyalties + Good const* rgo, std::optional<Province::life_rating_t>&& life_rating, TerrainType const* terrain_type, + std::optional<ProvinceHistory::building_level_map_t>&& buildings, + std::optional<decimal_map_t<Ideology const*>>&& party_loyalties ); void lock_province_histories(); @@ -81,6 +84,8 @@ namespace OpenVic { /* Returns history of province at bookmark date. Return can be nullptr if an error occurs. */ inline ProvinceHistory const* get_province_history(Province const* province, Bookmark const* bookmark) const; - bool load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root); + bool load_province_history_file( + GameManager const& game_manager, Province const& province, ast::NodeCPtr root + ); }; } // namespace OpenVic diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 4790853..b1aea2c 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -514,7 +514,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain goto set_terrain; } } - if (unrecognised_province_colours.find(province_colour) == unrecognised_province_colours.end()) { + if (!unrecognised_province_colours.contains(province_colour)) { unrecognised_province_colours.insert(province_colour); if (detailed_errors) { Logger::warning( diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 7b88ebf..66e4daf 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -5,7 +5,7 @@ using namespace OpenVic::NodeTools; Province::Province( std::string_view new_identifier, colour_t new_colour, index_t new_index -) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, index { new_index }, +) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, index { new_index }, buildings { "buildings", false } { assert(index != NULL_INDEX); } @@ -38,6 +38,10 @@ Province::life_rating_t Province::get_life_rating() const { return life_rating; } +Province::colony_status_t Province::get_colony_status() const { + return colony_status; +} + bool Province::load_positions(BuildingManager const& building_manager, ast::NodeCPtr root) { return expect_dictionary_keys( "text_position", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(positions.text)), diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 10f3a9a..6c022b7 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -24,6 +24,8 @@ namespace OpenVic { using distance_t = uint16_t; using flags_t = uint16_t; + enum struct colony_status_t : int8_t { STATE, PROTECTORATE, COLONY }; + struct adjacency_t { friend struct Province; @@ -63,6 +65,7 @@ namespace OpenVic { Region* region = nullptr; bool on_map = false, has_region = false, water = false; life_rating_t life_rating = 0; + colony_status_t colony_status = colony_status_t::STATE; IdentifierRegistry<BuildingInstance> buildings; // TODO - change this into a factory-like structure Good const* rgo = nullptr; @@ -90,6 +93,7 @@ namespace OpenVic { bool get_water() const; TerrainType const* get_terrain_type() const; life_rating_t get_life_rating() const; + colony_status_t get_colony_status() const; bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root); bool add_building(BuildingInstance&& building_instance); diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index 1753246..796089e 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -7,7 +7,7 @@ using namespace OpenVic::NodeTools; TerrainType::TerrainType( std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, modifier { std::move(new_modifier) }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, modifier { std::move(new_modifier) }, is_water { new_is_water } {} ModifierValue const& TerrainType::get_modifier() const { diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp index 5b3aa77..b5d335a 100644 --- a/src/openvic-simulation/military/Deployment.cpp +++ b/src/openvic-simulation/military/Deployment.cpp @@ -5,22 +5,28 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -Deployment::Deployment( - std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies, std::vector<Leader>&& new_leaders -) : HasIdentifier { new_path }, armies { std::move(new_armies) }, navies { std::move(new_navies) }, - leaders { std::move(new_leaders) } {} +Leader::Leader( + std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality, + LeaderTrait const* new_background, fixed_point_t new_prestige +) : name { new_name }, type { new_type }, date { new_date }, personality { new_personality }, background { new_background }, + prestige { new_prestige } {} -const std::vector<Army>& Deployment::get_armies() const { - return armies; -} +Regiment::Regiment(std::string_view new_name, Unit const* new_type, Province const* new_home) + : name { new_name }, type { new_type }, home { new_home } {} -const std::vector<Navy>& Deployment::get_navies() const { - return navies; -} +Ship::Ship(std::string_view new_name, Unit const* new_type) : name { new_name }, type { new_type } {} -const std::vector<Leader>& Deployment::get_leaders() const { - return leaders; -} +Army::Army(std::string_view new_name, Province const* new_location, std::vector<Regiment>&& new_regiments) + : name { new_name }, location { new_location }, regiments { std::move(new_regiments) } {} + +Navy::Navy(std::string_view new_name, Province const* new_location, std::vector<Ship>&& new_ships) + : name { new_name }, location { new_location }, ships { std::move(new_ships) } {} + +Deployment::Deployment( + std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies, + std::vector<Leader>&& new_leaders +) : HasIdentifier { new_path }, armies { std::move(new_armies) }, navies { std::move(new_navies) }, + leaders { std::move(new_leaders) } {} DeploymentManager::DeploymentManager() : deployments { "deployments" } {} @@ -31,117 +37,150 @@ bool DeploymentManager::add_deployment( Logger::error("Attemped to load order of battle with no path! Something is very wrong!"); return false; } - if (armies.empty() && navies.empty() && leaders.empty() && path != "NULL") { + if (armies.empty() && navies.empty() && leaders.empty()) { Logger::warning("Loading redundant empty order of battle at ", path); } - return deployments.add_item({ path, std::move(armies), std::move(navies), std::move(leaders) }); + return deployments.add_item( + std::make_unique<Deployment>(std::move(path), std::move(armies), std::move(navies), std::move(leaders)) + ); } -bool DeploymentManager::load_oob_file(GameManager& game_manager, std::string_view path, ast::NodeCPtr root) { +bool DeploymentManager::load_oob_file( + GameManager const& game_manager, Dataloader const& dataloader, std::string_view history_path, Deployment const*& deployment, + bool fail_on_missing +) { + deployment = get_deployment_by_identifier(history_path); + if (deployment != nullptr) { + return true; + } + if (missing_oob_files.contains(history_path)) { + return !fail_on_missing; + } + static const fs::path oob_directory = "history/units/"; + fs::path full_path = oob_directory; + full_path += history_path; + const fs::path lookedup_path = dataloader.lookup_file(full_path, false); + if (lookedup_path.empty()) { + missing_oob_files.emplace(history_path); + if (fail_on_missing) { + Logger::warning("Could not find OOB file ", full_path, "!"); + return false; + } else { + return true; + } + } std::vector<Army> armies; std::vector<Navy> navies; std::vector<Leader> leaders; - bool ret = expect_dictionary_keys_and_default( key_value_success_callback, // TODO: load SOI information "leader", ZERO_OR_MORE, [&leaders, &game_manager](ast::NodeCPtr node) -> bool { - std::string_view name; - Unit::type_t type; - Date date; - LeaderTrait const* personality = nullptr; - LeaderTrait const* background = nullptr; - fixed_point_t prestige = 0; + std::string_view leader_name {}; + Unit::type_t leader_type = Unit::type_t::LAND; + Date leader_date {}; + LeaderTrait const* leader_personality = nullptr; + LeaderTrait const* leader_background = nullptr; + fixed_point_t leader_prestige = 0; bool ret = expect_dictionary_keys( - "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false), - "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(date))), - "type", ONE_EXACTLY, expect_identifier([&type](std::string_view leader_type) -> bool { - if (leader_type == "land") { - type = Unit::type_t::LAND; - } else { - type = Unit::type_t::NAVAL; - } - return true; - }), + "name", ONE_EXACTLY, expect_string(assign_variable_callback(leader_name)), + "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(leader_date))), + "type", ONE_EXACTLY, expect_identifier(UnitManager::expect_type_str(assign_variable_callback(leader_type))), "personality", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager() - .expect_leader_trait_identifier(assign_variable_callback_pointer(personality)), + .expect_leader_trait_identifier(assign_variable_callback_pointer(leader_personality)), "background", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager() - .expect_leader_trait_identifier(assign_variable_callback_pointer(background)), - "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(prestige)), + .expect_leader_trait_identifier(assign_variable_callback_pointer(leader_background)), + "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(leader_prestige)), "picture", ZERO_OR_ONE, success_callback )(node); - if (!personality->is_personality_trait()) { - Logger::error("Leader ", name, " has personality ", personality->get_identifier(), - " which is not a personality trait!"); - return false; + if (!leader_personality->is_personality_trait()) { + Logger::error( + "Leader ", leader_name, " has personality ", leader_personality->get_identifier(), + " which is not a personality trait!" + ); + ret = false; } - if (!background->is_background_trait()) { - Logger::error("Leader ", name, " has background ", background->get_identifier(), - " which is not a background trait!"); - return false; + if (!leader_background->is_background_trait()) { + Logger::error( + "Leader ", leader_name, " has background ", leader_background->get_identifier(), + " which is not a background trait!" + ); + ret = false; } - - leaders.push_back(Leader{ std::string(name), type, date, personality, background, prestige }); + leaders.emplace_back( + leader_name, leader_type, leader_date, leader_personality, leader_background, leader_prestige + ); return ret; }, "army", ZERO_OR_MORE, [&armies, &game_manager](ast::NodeCPtr node) -> bool { - std::string_view name; - Province const* location = nullptr; - std::vector<Regiment> regiments; + std::string_view army_name {}; + Province const* army_location = nullptr; + std::vector<Regiment> army_regiments {}; - bool ret = expect_dictionary_keys( - /* another paradox gem, tested in game and they don't lead the army or even show up */ - "leader", ZERO_OR_MORE, success_callback, - "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false), + const bool ret = expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(army_name)), "location", ONE_EXACTLY, - game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(location)), - "regiment", ONE_OR_MORE, [&game_manager, ®iments](ast::NodeCPtr node) -> bool { - Regiment regiment; - bool ret = expect_dictionary_keys( - "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(regiment.name), false), + game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(army_location)), + "regiment", ONE_OR_MORE, [&game_manager, &army_regiments](ast::NodeCPtr node) -> bool { + std::string_view regiment_name {}; + Unit const* regiment_type = nullptr; + Province const* regiment_home = nullptr; + const bool ret = expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(regiment_name)), "type", ONE_EXACTLY, game_manager.get_military_manager().get_unit_manager() - .expect_unit_identifier(assign_variable_callback_pointer(regiment.type)), - "home", ONE_EXACTLY, game_manager.get_map() - .expect_province_identifier(assign_variable_callback_pointer(regiment.home)) + .expect_unit_identifier(assign_variable_callback_pointer(regiment_type)), + "home", ZERO_OR_ONE, game_manager.get_map() + .expect_province_identifier(assign_variable_callback_pointer(regiment_home)) )(node); - regiments.push_back(regiment); + if (regiment_home == nullptr) { + Logger::warning("Regiment ", regiment_name, " has no home province!"); + } + army_regiments.emplace_back(regiment_name, regiment_type, regiment_home); return ret; - } + }, + /* another paradox gem, tested in game and they don't lead the army or even show up */ + "leader", ZERO_OR_MORE, success_callback )(node); - armies.push_back(Army{ std::string(name), location, std::move(regiments) }); + armies.emplace_back(army_name, army_location, std::move(army_regiments)); return ret; }, "navy", ZERO_OR_MORE, [&navies, &game_manager](ast::NodeCPtr node) -> bool { - std::string_view name; - Province const* location = nullptr; - std::vector<Ship> ships; + std::string_view navy_name {}; + Province const* navy_location = nullptr; + std::vector<Ship> navy_ships {}; - bool ret = expect_dictionary_keys( - "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false), + const bool ret = expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(navy_name)), "location", ONE_EXACTLY, - game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(location)), - "ship", ONE_OR_MORE, [&game_manager, &ships](ast::NodeCPtr node) -> bool { - Ship ship; - bool ret = expect_dictionary_keys( - "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(ship.name), false), + game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(navy_location)), + "ship", ONE_OR_MORE, [&game_manager, &navy_ships](ast::NodeCPtr node) -> bool { + std::string_view ship_name {}; + Unit const* ship_type = nullptr; + const bool ret = expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(ship_name)), "type", ONE_EXACTLY, game_manager.get_military_manager().get_unit_manager() - .expect_unit_identifier(assign_variable_callback_pointer(ship.type)) + .expect_unit_identifier(assign_variable_callback_pointer(ship_type)) )(node); - ships.push_back(ship); + navy_ships.emplace_back(ship_name, ship_type); return ret; }, + /* another paradox gem, tested in game and they don't lead the army or even show up */ "leader", ZERO_OR_MORE, success_callback )(node); - navies.push_back(Navy{ std::string(name), location, std::move(ships) }); + navies.emplace_back(navy_name, navy_location, std::move(navy_ships)); return ret; } - )(root); - /* need to do this for platform compatibility of identifiers */ - std::string identifier = std::string { path }; - std::replace(identifier.begin(), identifier.end(), '\\', '/'); - ret &= add_deployment(identifier, std::move(armies), std::move(navies), std::move(leaders)); - + )(Dataloader::parse_defines(lookedup_path).get_file_node()); + ret &= add_deployment(history_path, std::move(armies), std::move(navies), std::move(leaders)); + deployment = get_deployment_by_identifier(history_path); + if (deployment == nullptr) { + ret = false; + } return ret; } + +size_t DeploymentManager::get_missing_oob_file_count() const { + return missing_oob_files.size(); +} diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp index 34cf82a..ead324e 100644 --- a/src/openvic-simulation/military/Deployment.hpp +++ b/src/openvic-simulation/military/Deployment.hpp @@ -15,46 +15,69 @@ namespace OpenVic { struct Leader { - std::string name; - const Unit::type_t type; - const Date date; - LeaderTrait const* personality; - LeaderTrait const* background; - fixed_point_t prestige; + private: + std::string PROPERTY(name); + Unit::type_t PROPERTY(type); + Date PROPERTY(date); + LeaderTrait const* PROPERTY(personality); + LeaderTrait const* PROPERTY(background); + fixed_point_t PROPERTY(prestige); + + public: + Leader( + std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality, + LeaderTrait const* new_background, fixed_point_t new_prestige + ); }; struct Regiment { - std::string name; - Unit const* type; - Province const* home; + private: + std::string PROPERTY(name); + Unit const* PROPERTY(type); + Province const* PROPERTY(home); + + public: + Regiment(std::string_view new_name, Unit const* new_type, Province const* new_home); }; struct Ship { - std::string name; - Unit const* type; + private: + std::string PROPERTY(name); + Unit const* PROPERTY(type); + + public: + Ship(std::string_view new_name, Unit const* new_type); }; struct Army { - std::string name; - Province const* location; - std::vector<Regiment> regiments; + private: + std::string PROPERTY(name); + Province const* PROPERTY(location); + std::vector<Regiment> PROPERTY(regiments); + + public: + Army(std::string_view new_name, Province const* new_location, std::vector<Regiment>&& new_regiments); }; struct Navy { - std::string name; - Province const* location; - std::vector<Ship> ships; - }; + private: + std::string PROPERTY(name); + Province const* PROPERTY(location); + std::vector<Ship> PROPERTY(ships); - struct DeploymentManager; + public: + Navy(std::string_view new_name, Province const* new_location, std::vector<Ship>&& new_ships); + }; struct Deployment : HasIdentifier { - friend struct DeploymentManager; + friend std::unique_ptr<Deployment> std::make_unique<Deployment>( + std::string_view&&, std::vector<OpenVic::Army>&&, std::vector<OpenVic::Navy>&&, std::vector<OpenVic::Leader>&& + ); private: - const std::vector<Army> armies; - const std::vector<Navy> navies; - const std::vector<Leader> leaders; + std::vector<Army> PROPERTY(armies); + std::vector<Navy> PROPERTY(navies); + std::vector<Leader> PROPERTY(leaders); Deployment( std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies, @@ -62,14 +85,13 @@ namespace OpenVic { ); public: - const std::vector<Army>& get_armies() const; - const std::vector<Navy>& get_navies() const; - const std::vector<Leader>& get_leaders() const; + Deployment(Deployment&&) = default; }; struct DeploymentManager { private: - IdentifierRegistry<Deployment> deployments; + IdentifierInstanceRegistry<Deployment> deployments; + string_set_t missing_oob_files; public: DeploymentManager(); @@ -77,8 +99,12 @@ namespace OpenVic { bool add_deployment( std::string_view path, std::vector<Army>&& armies, std::vector<Navy>&& navies, std::vector<Leader>&& leaders ); - IDENTIFIER_REGISTRY_ACCESSORS(deployment); + IDENTIFIER_REGISTRY_ACCESSORS(deployment) - bool load_oob_file(GameManager& game_manager, std::string_view path, ast::NodeCPtr root); + bool load_oob_file( + GameManager const& game_manager, Dataloader const& dataloader, std::string_view history_path, + Deployment const*& deployment, bool fail_on_missing + ); + size_t get_missing_oob_file_count() const; }; } // namespace OpenVic diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp index 1b5f2d2..5322a88 100644 --- a/src/openvic-simulation/military/Unit.cpp +++ b/src/openvic-simulation/military/Unit.cpp @@ -244,6 +244,12 @@ bool UnitManager::add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_ return units.add_item(NavalUnit { identifier, UNIT_ARGS, NAVY_ARGS }); } +callback_t<std::string_view> UnitManager::expect_type_str(Callback<Unit::type_t> auto callback) { + using enum Unit::type_t; + static const string_map_t<Unit::type_t> type_map = { { "land", LAND }, { "naval", NAVAL }, { "sea", NAVAL } }; + return expect_mapped_string(type_map, callback); +} + bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root) { return expect_dictionary([this, &good_manager](std::string_view key, ast::NodeCPtr value) -> bool { Unit::type_t type; @@ -256,9 +262,7 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr fixed_point_t weighted_value = 0, supply_consumption = 0; Good::good_map_t build_cost, supply_cost; - using enum Unit::type_t; - static const string_map_t<Unit::type_t> type_map = { { "land", LAND }, { "naval", NAVAL } }; - bool ret = expect_key("type", expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))))(value); + bool ret = expect_key("type", expect_identifier(expect_type_str(assign_variable_callback(type))))(value); if (!ret) { Logger::error("Failed to read type for unit: ", key); @@ -288,9 +292,9 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr ); switch (type) { - case LAND: { + case Unit::type_t::LAND: { bool primary_culture = false; - std::string_view sprite_override, sprite_mount, sprite_mount_attach_node; + std::string_view sprite_override {}, sprite_mount {}, sprite_mount_attach_node {}; fixed_point_t reconnaissance = 0, attack = 0, defence = 0, discipline = 0, support = 0, maneuver = 0, siege = 0; ret &= add_key_map_entries(key_map, @@ -313,7 +317,7 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr return ret; } - case NAVAL: { + case Unit::type_t::NAVAL: { Unit::icon_t naval_icon = 0; bool sail = false, transport = false, capital = false, build_overseas = false; uint32_t min_port_level = 0; diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp index acfc8b8..ab371e8 100644 --- a/src/openvic-simulation/military/Unit.hpp +++ b/src/openvic-simulation/military/Unit.hpp @@ -169,6 +169,8 @@ namespace OpenVic { bool add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_PARAMS); IDENTIFIER_REGISTRY_ACCESSORS(unit) + static NodeTools::callback_t<std::string_view> expect_type_str(NodeTools::Callback<Unit::type_t> auto callback); + bool load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root); }; } diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index 56ce0b0..be71f9d 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -15,8 +15,8 @@ namespace OpenVic { enum class Type : unsigned char { None, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; private: - std::string HASID_PROPERTY(value); - Type HASID_PROPERTY(type); + const std::string PROPERTY(value); + const Type PROPERTY(type); Define(std::string_view new_identifier, std::string&& new_value, Type new_type); @@ -40,7 +40,7 @@ namespace OpenVic { bool add_define(std::string_view name, std::string&& value, Define::Type type); bool add_date_define(std::string_view name, Date date); - IDENTIFIER_REGISTRY_ACCESSORS(define); + IDENTIFIER_REGISTRY_ACCESSORS(define) Date get_start_date() const; Date get_end_date() const; diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp index 823284a..3b0f28d 100644 --- a/src/openvic-simulation/politics/Government.cpp +++ b/src/openvic-simulation/politics/Government.cpp @@ -85,7 +85,7 @@ bool GovernmentTypeManager::load_government_types_file(IdeologyManager const& id [this, &ideology_manager, &ideologies, government_type_identifier]( std::string_view key, ast::NodeCPtr value) -> bool { static const string_set_t reserved_keys = { "election", "duration", "appoint_ruling_party", "flagType" }; - if (reserved_keys.find(key) != reserved_keys.end()) { + if (reserved_keys.contains(key)) { return true; } Ideology const* ideology = ideology_manager.get_ideology_by_identifier(key); diff --git a/src/openvic-simulation/politics/Ideology.cpp b/src/openvic-simulation/politics/Ideology.cpp index 5721a57..148d6ac 100644 --- a/src/openvic-simulation/politics/Ideology.cpp +++ b/src/openvic-simulation/politics/Ideology.cpp @@ -8,7 +8,7 @@ IdeologyGroup::IdeologyGroup(std::string_view new_identifier) : HasIdentifier { Ideology::Ideology( std::string_view new_identifier, colour_t new_colour, IdeologyGroup const& new_group, bool new_uncivilised, bool new_can_reduce_militancy, Date new_spawn_date -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group }, uncivilised { new_uncivilised }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group }, uncivilised { new_uncivilised }, can_reduce_militancy { new_can_reduce_militancy }, spawn_date { new_spawn_date } {} IdeologyGroup const& Ideology::get_group() const { diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp index e386930..9159fe1 100644 --- a/src/openvic-simulation/pop/Culture.cpp +++ b/src/openvic-simulation/pop/Culture.cpp @@ -28,7 +28,7 @@ bool CultureGroup::get_is_overseas() const { Culture::Culture( std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, std::vector<std::string>&& new_first_names, std::vector<std::string>&& new_last_names -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group }, first_names { std::move(new_first_names) }, last_names { std::move(new_last_names) } {} CultureGroup const& Culture::get_group() const { @@ -195,7 +195,7 @@ bool CultureManager::load_culture_file(ast::NodeCPtr root) { CultureGroup const* culture_group = get_culture_group_by_identifier(culture_group_key); return expect_dictionary([this, culture_group](std::string_view key, ast::NodeCPtr value) -> bool { static const string_set_t reserved_keys = { "leader", "unit", "union", "is_overseas" }; - if (reserved_keys.find(key) != reserved_keys.end()) { + if (reserved_keys.contains(key)) { return true; } return _load_culture(culture_group, key, value); diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index f63a704..0b61096 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -52,7 +52,7 @@ PopType::PopType( Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs, rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size, bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_is_slave -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, strata { new_strata }, sprite { new_sprite }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, strata { new_strata }, sprite { new_sprite }, life_needs { std::move(new_life_needs) }, everyday_needs { std::move(new_everyday_needs) }, luxury_needs { std::move(new_luxury_needs) }, rebel_units { std::move(new_rebel_units) }, max_size { new_max_size }, merge_max_size { new_merge_max_size }, state_capital_only { new_state_capital_only }, diff --git a/src/openvic-simulation/pop/Religion.cpp b/src/openvic-simulation/pop/Religion.cpp index 489984d..99915c3 100644 --- a/src/openvic-simulation/pop/Religion.cpp +++ b/src/openvic-simulation/pop/Religion.cpp @@ -9,7 +9,7 @@ ReligionGroup::ReligionGroup(std::string_view new_identifier) : HasIdentifier { Religion::Religion( std::string_view new_identifier, colour_t new_colour, ReligionGroup const& new_group, icon_t new_icon, bool new_pagan -) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group }, icon { new_icon }, +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group }, icon { new_icon }, pagan { new_pagan } { assert(icon > 0); } diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp index c3fee15..b6e693c 100644 --- a/src/openvic-simulation/types/Date.hpp +++ b/src/openvic-simulation/types/Date.hpp @@ -4,9 +4,11 @@ #include <ostream> #include <string> +#include "openvic-simulation/utility/Getters.hpp" + namespace OpenVic { // A relative period between points in time, measured in days - struct Timespan { + struct Timespan : ReturnByValueProperty { using day_t = int64_t; private: @@ -44,7 +46,7 @@ namespace OpenVic { // Represents an in-game date // Note: Current implementation does not account for leap-years, or dates before Year 0 - struct Date { + struct Date : ReturnByValueProperty { using year_t = uint16_t; using month_t = uint8_t; using day_t = uint8_t; diff --git a/src/openvic-simulation/types/IdentifierRegistry.cpp b/src/openvic-simulation/types/IdentifierRegistry.cpp index faddd75..3964b12 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.cpp +++ b/src/openvic-simulation/types/IdentifierRegistry.cpp @@ -8,10 +8,6 @@ HasIdentifier::HasIdentifier(std::string_view new_identifier) : identifier { new assert(!identifier.empty()); } -std::string_view HasIdentifier::get_identifier() const { - return identifier; -} - std::ostream& OpenVic::operator<<(std::ostream& stream, HasIdentifier const& obj) { return stream << obj.get_identifier(); } @@ -20,12 +16,8 @@ std::ostream& OpenVic::operator<<(std::ostream& stream, HasIdentifier const* obj return obj != nullptr ? stream << *obj : stream << "<NULL>"; } -HasColour::HasColour(colour_t const new_colour, bool can_be_null, bool can_have_alpha) : colour(new_colour) { - assert((can_be_null || colour != NULL_COLOUR) && colour <= (!can_have_alpha ? MAX_COLOUR_RGB : MAX_COLOUR_ARGB)); -} - -colour_t HasColour::get_colour() const { - return colour; +HasColour::HasColour(colour_t new_colour, bool cannot_be_null, bool can_have_alpha) : colour(new_colour) { + assert((!cannot_be_null || colour != NULL_COLOUR) && colour <= (!can_have_alpha ? MAX_COLOUR_RGB : MAX_COLOUR_ARGB)); } std::string HasColour::colour_to_hex_string() const { @@ -33,5 +25,5 @@ std::string HasColour::colour_to_hex_string() const { } HasIdentifierAndColour::HasIdentifierAndColour( - std::string_view new_identifier, const colour_t new_colour, bool can_be_null, bool can_have_alpha -) : HasIdentifier { new_identifier }, HasColour { new_colour, can_be_null, can_have_alpha } {} + std::string_view new_identifier, colour_t new_colour, bool cannot_be_null, bool can_have_alpha +) : HasIdentifier { new_identifier }, HasColour { new_colour, cannot_be_null, can_have_alpha } {} diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index ebdedce..e68f2a4 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -6,24 +6,16 @@ #include <vector> #include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/utility/Getters.hpp" #include "openvic-simulation/utility/Logger.hpp" -#define REF_GETTERS(var) \ - constexpr decltype(var)& get_##var() { \ - return var; \ - } \ - constexpr decltype(var) const& get_##var() const { \ - return var; \ - } - namespace OpenVic { /* - * Base class for objects with a non-empty string identifier, - * uniquely named instances of which can be entered into an - * IdentifierRegistry instance. + * Base class for objects with a non-empty string identifier. Uniquely named instances of a type derived from this class + * can be entered into an IdentifierRegistry instance. */ class HasIdentifier { - const std::string identifier; + const std::string PROPERTY(identifier); protected: HasIdentifier(std::string_view new_identifier); @@ -33,29 +25,6 @@ namespace OpenVic { HasIdentifier(HasIdentifier&&) = default; HasIdentifier& operator=(HasIdentifier const&) = delete; HasIdentifier& operator=(HasIdentifier&&) = delete; - - std::string_view get_identifier() const; - - template<typename T> - inline constexpr static decltype(auto) get_property(const T& property) { - if constexpr (std::same_as<T, std::string>) { - return std::string_view(property); - } else if constexpr (sizeof(T) <= sizeof(void*)) { - return T(property); - } else { - return property; - } - } - -#define HASID_PROPERTY(NAME) \ - const NAME; \ -\ -public: \ - auto get_##NAME() const -> decltype(get_property(NAME)) { \ - return get_property(NAME); \ - } \ -\ -private: }; std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj); @@ -65,10 +34,10 @@ private: * Base class for objects with associated colour information. */ class HasColour { - const colour_t colour; + const colour_t PROPERTY(colour); protected: - HasColour(const colour_t new_colour, bool can_be_null, bool can_have_alpha); + HasColour(colour_t new_colour, bool cannot_be_null, bool can_have_alpha); public: HasColour(HasColour const&) = delete; @@ -76,18 +45,16 @@ private: HasColour& operator=(HasColour const&) = delete; HasColour& operator=(HasColour&&) = delete; - colour_t get_colour() const; std::string colour_to_hex_string() const; }; /* - * Base class for objects with a unique string identifier - * and associated colour information. + * Base class for objects with a unique string identifier and associated colour information. */ class HasIdentifierAndColour : public HasIdentifier, public HasColour { protected: HasIdentifierAndColour( - std::string_view new_identifier, const colour_t new_colour, bool can_be_null, bool can_have_alpha + std::string_view new_identifier, colour_t new_colour, bool cannot_be_null, bool can_have_alpha ); public: diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp index 4bf5716..ba6790f 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp @@ -8,6 +8,7 @@ #include <sstream> #include <string_view> +#include "openvic-simulation/utility/Getters.hpp" #include "openvic-simulation/utility/Logger.hpp" #include "openvic-simulation/utility/NumberUtils.hpp" #include "openvic-simulation/utility/StringUtils.hpp" @@ -15,7 +16,7 @@ #include "FixedPointLUT.hpp" namespace OpenVic { - struct fixed_point_t { + struct fixed_point_t : ReturnByValueProperty { static constexpr size_t SIZE = 8; static constexpr int32_t PRECISION = FPLUT::SIN_LUT_PRECISION; diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp new file mode 100644 index 0000000..c8f2193 --- /dev/null +++ b/src/openvic-simulation/utility/Getters.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include <concepts> +#include <string> +#include <string_view> + +#define REF_GETTERS(var) \ + constexpr decltype(var)& get_##var() { \ + return var; \ + } \ + constexpr decltype(var) const& get_##var() const { \ + return var; \ + } + +namespace OpenVic { + struct ReturnByValueProperty {}; + + /* + * Template function used to choose the return type and provide the implementation for the + * for variable getters created using the PROPERTY macro. + */ + template<typename decl, typename T> + inline constexpr decltype(auto) _get_property(const T& property) { + if constexpr(std::is_reference_v<decl>) { + /* Return const reference */ + return property; + } else if constexpr (std::same_as<T, std::string>) { + /* Return std::string_view looking at std::string */ + return std::string_view { property }; + } else if constexpr ( + std::integral<T> || std::floating_point<T> || std::is_enum<T>::value || std::derived_from<T, ReturnByValueProperty> + ) { + /* Return value */ + return T { property }; + } else if constexpr(std::is_pointer<T>::value) { + /* Return const pointer */ + return static_cast<std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>>(property); + } else { + /* Return const reference */ + return property; + } + } + +/* + * Use this on a variable delcaration to generate a getter function. It assumes the variable is private and so + * sets the accessibility modifier state back to private after declaring the getter as public. + * Examples: + * int PROPERTY(x); // int x; int get_x() const; + * const std::string PROPERTY(name); // const std::string name; std::string_view get_name() const; + * std::vector<int> PROPERTY(sizes); // std::vector<int> sizes; std::vector<int> const& get_sizes() const; + * uint8_t const* PROPERTY(data); // uint8_t const* data; uint8_t const* get_data() const; + * colour_t* PROPERTY(pixels); // colour_t* pixels; colour_t const* get_pixels() const; + * CultureGroup const& PROPERTY(group);// CultureGroup const& group; CultureGroup const& get_group() const; + * Province& PROPERTY(province); // Province& province; Province const& get_province() const; + */ +#define PROPERTY(NAME) \ + NAME; \ +\ +public: \ + auto get_##NAME() const -> decltype(OpenVic::_get_property<decltype(NAME)>(NAME)) { \ + return OpenVic::_get_property<decltype(NAME)>(NAME); \ + } \ +\ +private: + +} |