diff options
Diffstat (limited to 'src/openvic-simulation/history')
-rw-r--r-- | src/openvic-simulation/history/Bookmark.cpp | 2 | ||||
-rw-r--r-- | src/openvic-simulation/history/Bookmark.hpp | 7 | ||||
-rw-r--r-- | src/openvic-simulation/history/CountryHistory.cpp | 456 | ||||
-rw-r--r-- | src/openvic-simulation/history/CountryHistory.hpp | 105 | ||||
-rw-r--r-- | src/openvic-simulation/history/HistoryMap.cpp | 15 | ||||
-rw-r--r-- | src/openvic-simulation/history/HistoryMap.hpp | 110 | ||||
-rw-r--r-- | src/openvic-simulation/history/ProvinceHistory.cpp | 420 | ||||
-rw-r--r-- | src/openvic-simulation/history/ProvinceHistory.hpp | 93 |
8 files changed, 464 insertions, 744 deletions
diff --git a/src/openvic-simulation/history/Bookmark.cpp b/src/openvic-simulation/history/Bookmark.cpp index edfa064..92d8de5 100644 --- a/src/openvic-simulation/history/Bookmark.cpp +++ b/src/openvic-simulation/history/Bookmark.cpp @@ -25,7 +25,7 @@ std::string_view Bookmark::get_description() const { return description; } -Date const& Bookmark::get_date() const { +Date Bookmark::get_date() const { return date; } diff --git a/src/openvic-simulation/history/Bookmark.hpp b/src/openvic-simulation/history/Bookmark.hpp index 8f0075f..d5253fe 100644 --- a/src/openvic-simulation/history/Bookmark.hpp +++ b/src/openvic-simulation/history/Bookmark.hpp @@ -29,7 +29,7 @@ namespace OpenVic { std::string_view get_name() const; std::string_view get_description() const; - Date const& get_date() const; + Date get_date() const; uint32_t get_initial_camera_x() const; uint32_t get_initial_camera_y() const; }; @@ -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 2dfc171..04a5e09 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -5,154 +5,103 @@ using namespace OpenVic; 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, - 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 -) : primary_culture { new_primary_culture }, accepted_cultures { std::move(new_accepted_cultures) }, - religion { new_religion }, ruling_party { new_ruling_party }, last_election { new_last_election }, - upper_house { std::move(new_upper_house) }, capital { new_capital }, government_type { new_government_type }, - plurality { new_plurality }, national_value { new_national_value }, civilised { new_civilised }, - prestige { new_prestige }, reforms { std::move(new_reforms) }, inital_oob { new_inital_oob } {} +CountryHistoryEntry::CountryHistoryEntry(Country const& new_country, Date new_date) + : HistoryEntry { new_date }, country { new_country } {} -Culture const* CountryHistory::get_primary_culture() const { - return primary_culture; -} - -const std::vector<Culture const*>& CountryHistory::get_accepted_cultures() const { - return accepted_cultures; -} - -Religion const* CountryHistory::get_religion() const { - return religion; -} - -CountryParty const* CountryHistory::get_ruling_party() const { - return ruling_party; -} - -const Date CountryHistory::get_last_election() const { - return last_election; -} - -const std::map<Ideology const*, fixed_point_t>& CountryHistory::get_upper_house() const { - return upper_house; -} - -Province const* CountryHistory::get_capital() const { - return capital; -} - -GovernmentType const* CountryHistory::get_government_type() const { - return government_type; -} - -const fixed_point_t CountryHistory::get_plurality() const { - return plurality; -} - -NationalValue const* CountryHistory::get_national_value() const { - return national_value; -} - -const bool CountryHistory::is_civilised() const { - return civilised; -} - -const fixed_point_t CountryHistory::get_prestige() const { - return prestige; -} - -const std::vector<Reform const*>& CountryHistory::get_reforms() const { - return reforms; -} +CountryHistoryMap::CountryHistoryMap(Country const& new_country) : country { new_country } {} -Deployment const* CountryHistory::get_inital_oob() const { - return inital_oob; +std::unique_ptr<CountryHistoryEntry> CountryHistoryMap::_make_entry(Date date) const { + return std::unique_ptr<CountryHistoryEntry> { new CountryHistoryEntry { country, date } }; } -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, - 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 +bool CountryHistoryMap::_load_history_entry( + GameManager const& game_manager, Dataloader const& dataloader, DeploymentManager& deployment_manager, + CountryHistoryEntry& entry, ast::NodeCPtr root ) { - if (locked) { - Logger::error("Cannot add new history entry to country history registry: locked!"); - return false; - } - - /* combine duplicate histories, priority to current (defined later) */ - auto& country_registry = country_histories[country]; - const auto existing_entry = country_registry.find(date); - - if (existing_entry != country_registry.end()) { - if (primary_culture != nullptr) { - existing_entry->second.primary_culture = primary_culture; - } - if (updated_accepted_cultures) { - existing_entry->second.accepted_cultures = std::move(accepted_cultures); - } - if (religion != nullptr) { - existing_entry->second.religion = religion; - } - if (ruling_party != nullptr) { - existing_entry->second.ruling_party = ruling_party; - } - if (last_election != Date(0)) { - existing_entry->second.last_election = last_election; - } - if (updated_upper_house) { - existing_entry->second.upper_house = std::move(upper_house); - } - if (capital != nullptr) { - existing_entry->second.capital = capital; - } - if (government_type != nullptr) { - existing_entry->second.government_type = government_type; - } - if (plurality >= 0) { - existing_entry->second.plurality = plurality; - } - if (national_value != nullptr) { - existing_entry->second.national_value = national_value; - } - if (civilised) { - existing_entry->second.civilised = true; - } - if (prestige >= 0) { - existing_entry->second.prestige = prestige; - } - if (updated_reforms) { - existing_entry->second.reforms = std::move(reforms); - } - if (initial_oob != nullptr) { - 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 + 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(); + + return expect_dictionary_keys_and_default( + [this, &game_manager, &dataloader, &deployment_manager, &issue_manager, &entry]( + std::string_view key, ast::NodeCPtr value) -> bool { + ReformGroup const* reform_group = issue_manager.get_reform_group_by_identifier(key); + if (reform_group != nullptr) { + return issue_manager.expect_reform_identifier([&entry, reform_group](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(), " in history of ", entry.get_country().get_identifier() + ); + } + if (std::find(entry.reforms.begin(), entry.reforms.end(), &reform) != entry.reforms.end()) { + Logger::error( + "Redefinition of reform ", reform.get_identifier(), " in history of ", + entry.get_country().get_identifier() + ); + return false; + } + entry.reforms.push_back(&reform); + return true; + })(value); } - ); - } - return true; + // TODO: technologies & inventions + return _load_history_sub_entry_callback( + game_manager, dataloader, deployment_manager, entry.get_date(), value, key, value, key_value_success_callback + ); + }, + /* 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(assign_variable_callback_pointer(entry.capital)), + "primary_culture", ZERO_OR_ONE, + culture_manager.expect_culture_identifier(assign_variable_callback_pointer(entry.primary_culture)), + "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier( + [&entry](Culture const& culture) -> bool { + entry.accepted_cultures.push_back(&culture); + return true; + } + ), + "religion", ZERO_OR_ONE, game_manager.get_pop_manager().get_religion_manager().expect_religion_identifier( + assign_variable_callback_pointer(entry.religion) + ), + "government", ZERO_OR_ONE, politics_manager.get_government_type_manager().expect_government_type_identifier( + assign_variable_callback_pointer(entry.government_type) + ), + "plurality", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.plurality)), + "nationalvalue", ZERO_OR_ONE, politics_manager.get_national_value_manager().expect_national_value_identifier( + assign_variable_callback_pointer(entry.national_value) + ), + "civilized", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.civilised)), + "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.prestige)), + "ruling_party", ZERO_OR_ONE, country.expect_party_identifier(assign_variable_callback_pointer(entry.ruling_party)), + "last_election", ZERO_OR_ONE, expect_date(assign_variable_callback(entry.last_election)), + "upper_house", ZERO_OR_ONE, politics_manager.get_ideology_manager().expect_ideology_dictionary( + [&entry](Ideology const& ideology, ast::NodeCPtr value) -> bool { + return expect_fixed_point([&entry, &ideology](fixed_point_t val) -> bool { + entry.upper_house[&ideology] = val; + return true; + })(value); + } + ), + "oob", ZERO_OR_ONE, expect_identifier_or_string( + [&game_manager, &deployment_manager, &dataloader, &entry](std::string_view path) -> bool { + Deployment const* deployment = nullptr; + const bool ret = deployment_manager.load_oob_file(game_manager, dataloader, path, deployment, false); + if (deployment != nullptr) { + entry.inital_oob = deployment; + } + return ret; + } + ), + "schools", ZERO_OR_ONE, success_callback, // TODO: technology school + "foreign_investment", ZERO_OR_ONE, success_callback // TODO: foreign investment + )(root); } void CountryHistoryManager::lock_country_histories() { - for (const auto& entry : country_histories) { - if (entry.second.size() == 0) { - Logger::error( - "Attempted to lock country histories - country ", entry.first->get_identifier(), " has no history entries!" - ); - } - } Logger::info("Locked country history registry after registering ", country_histories.size(), " items"); locked = true; } @@ -161,214 +110,49 @@ bool CountryHistoryManager::is_locked() const { return locked; } -CountryHistory const* CountryHistoryManager::get_country_history(Country const* country, Date entry) const { - Date closest_entry; - auto country_registry = country_histories.find(country); - - if (country_registry == country_histories.end()) { - Logger::error("Attempted to access history of undefined country ", country->get_identifier()); +CountryHistoryMap const* CountryHistoryManager::get_country_history(Country const* country) const { + if (country == nullptr) { + Logger::error("Attempted to access history of null country"); return nullptr; } - - for (const auto& current : country_registry->second) { - if (current.first == entry) { - return ¤t.second; - } - if (current.first > entry) { - continue; - } - if (current.first > closest_entry && current.first < entry) { - closest_entry = current.first; - } - } - - auto entry_registry = country_registry->second.find(closest_entry); - if (entry_registry != country_registry->second.end()) { - return &entry_registry->second; + decltype(country_histories)::const_iterator country_registry = country_histories.find(country); + if (country_registry != country_histories.end()) { + return &country_registry->second; + } else { + Logger::error("Attempted to access history of country ", country->get_identifier(), " but none has been defined!"); + return nullptr; } - /* warned about lack of entries earlier, return nullptr */ - return nullptr; } -inline CountryHistory const* CountryHistoryManager::get_country_history(Country const* country, Bookmark const* entry) const { - return get_country_history(country, entry->get_date()); -} - -inline bool CountryHistoryManager::_load_country_history_entry( - GameManager& game_manager, std::string_view name, Date const& date, ast::NodeCPtr root +bool CountryHistoryManager::load_country_history_file( + GameManager& game_manager, Dataloader const& dataloader, Country const& country, ast::NodeCPtr root ) { - 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; - fixed_point_t plurality = -1, prestige = -1; - bool civilised = false; - Date last_election = Date(0); - Deployment const* initial_oob = nullptr; - - 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)) { - 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; - } - // 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 */ - "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", ZERO_OR_MORE, - game_manager.get_pop_manager().get_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); - return true; - } - ), - "religion", ZERO_OR_ONE, - game_manager.get_pop_manager().get_religion_manager().expect_religion_identifier( - assign_variable_callback_pointer(religion) - ), - "government", ZERO_OR_ONE, - game_manager.get_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( - 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_name() == 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; - }), - "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( - [&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 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); - } - } - - initial_oob = - game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier("NULL"); - return true; - }, - "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, 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, updated_upper_house, updated_reforms - ); - return ret; -} + if (locked) { + Logger::error( + "Attempted to load country history file for ", country.get_identifier(), + " after country history registry was locked!" + ); + return false; + } -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()) { + 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); - - ret &= expect_dictionary([this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool { - bool is_date = false; - Date entry = Date().from_string(key, &is_date, true); - if (!is_date) { - return true; - } - - Date const& 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() - ); + decltype(country_histories)::iterator it = country_histories.find(&country); + if (it == country_histories.end()) { + const std::pair<decltype(country_histories)::iterator, bool> result = + country_histories.emplace(&country, CountryHistoryMap { country }); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create country history map for country ", country.get_identifier()); return false; } + } + CountryHistoryMap& country_history = it->second; - return _load_country_history_entry(game_manager, name, entry, value); - })(root); - - return ret; + return country_history._load_history_file( + game_manager, dataloader, game_manager.get_military_manager().get_deployment_manager(), root + ); } diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index 52d99df..ffb44c0 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -5,6 +5,7 @@ #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/history/Bookmark.hpp" +#include "openvic-simulation/history/HistoryMap.hpp" #include "openvic-simulation/map/Province.hpp" #include "openvic-simulation/military/Deployment.hpp" #include "openvic-simulation/politics/Government.hpp" @@ -17,86 +18,68 @@ #include "openvic-simulation/types/Date.hpp" namespace OpenVic { - struct CountryHistoryManager; + struct CountryHistoryMap; - struct CountryHistory { - friend struct CountryHistoryManager; + struct CountryHistoryEntry : HistoryEntry { + friend struct CountryHistoryMap; private: - 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* inital_oob; + Country const& PROPERTY(country); + + std::optional<Culture const*> PROPERTY(primary_culture); + std::vector<Culture const*> PROPERTY(accepted_cultures); + std::optional<Religion const*> PROPERTY(religion); + std::optional<CountryParty const*> PROPERTY(ruling_party); + std::optional<Date> PROPERTY(last_election); + decimal_map_t<Ideology const*> PROPERTY(upper_house); + std::optional<Province const*> PROPERTY(capital); + std::optional<GovernmentType const*> PROPERTY(government_type); + std::optional<fixed_point_t> PROPERTY(plurality); + std::optional<NationalValue const*> PROPERTY(national_value); + std::optional<bool> PROPERTY(civilised); + std::optional<fixed_point_t> PROPERTY(prestige); + std::vector<Reform const*> PROPERTY(reforms); + std::optional<Deployment const*> PROPERTY(inital_oob); // TODO: technologies, tech schools, and inventions when PR#51 merged // TODO: starting foreign investment - 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, - 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 - ); + CountryHistoryEntry(Country const& new_country, Date new_date); + }; - public: - Culture const* get_primary_culture() const; - const std::vector<Culture const*>& get_accepted_cultures() const; - Religion const* get_religion() const; - CountryParty const* get_ruling_party() const; - const Date get_last_election() const; - const std::map<Ideology const*, fixed_point_t>& get_upper_house() const; - Province const* get_capital() const; - GovernmentType const* get_government_type() const; - 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; - Deployment const* get_inital_oob() const; + struct CountryHistoryManager; + + struct CountryHistoryMap : HistoryMap<CountryHistoryEntry, Dataloader const&, DeploymentManager&> { + friend struct CountryHistoryManager; + + private: + Country const& PROPERTY(country); + + protected: + CountryHistoryMap(Country const& new_country); + + std::unique_ptr<CountryHistoryEntry> _make_entry(Date date) const override; + bool _load_history_entry( + GameManager const& game_manager, Dataloader const& dataloader, DeploymentManager& deployment_manager, + CountryHistoryEntry& entry, ast::NodeCPtr root + ) override; }; struct CountryHistoryManager { private: - std::map<Country const*, std::map<Date, CountryHistory>> country_histories; + std::map<Country const*, CountryHistoryMap> country_histories; bool locked = false; - inline bool _load_country_history_entry( - GameManager& game_manager, std::string_view name, Date const& date, ast::NodeCPtr root - ); - public: - CountryHistoryManager() {} - - 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 - ); + CountryHistoryManager() = default; void lock_country_histories(); bool is_locked() const; - /* Returns history of country at date, if date doesn't have an entry returns - * closest entry before date. Return can be nullptr if an error occurs. */ - CountryHistory const* get_country_history(Country const* country, Date entry) const; - /* 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; + CountryHistoryMap const* get_country_history(Country const* country) 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/HistoryMap.cpp b/src/openvic-simulation/history/HistoryMap.cpp new file mode 100644 index 0000000..b669208 --- /dev/null +++ b/src/openvic-simulation/history/HistoryMap.cpp @@ -0,0 +1,15 @@ +#include "HistoryMap.hpp" + +#include "openvic-simulation/GameManager.hpp" + +using namespace OpenVic; + +HistoryEntry::HistoryEntry(Date new_date) : date { new_date } {} + +Date OpenVic::_get_start_date(GameManager const& game_manager) { + return game_manager.get_define_manager().get_start_date(); +} + +Date OpenVic::_get_end_date(GameManager const& game_manager) { + return game_manager.get_define_manager().get_end_date(); +} diff --git a/src/openvic-simulation/history/HistoryMap.hpp b/src/openvic-simulation/history/HistoryMap.hpp new file mode 100644 index 0000000..64d886d --- /dev/null +++ b/src/openvic-simulation/history/HistoryMap.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include <map> +#include <memory> + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/Date.hpp" + +namespace OpenVic { + + struct HistoryEntry { + private: + Date PROPERTY(date); + + protected: + HistoryEntry(Date new_date); + }; + + struct GameManager; + + /* Helper functions to avoid cyclic dependency issues */ + Date _get_start_date(GameManager const& game_manager); + Date _get_end_date(GameManager const& game_manager); + + template<std::derived_from<HistoryEntry> _Entry, typename... Args> + struct HistoryMap { + using entry_type = _Entry; + + private: + std::map<Date, std::unique_ptr<entry_type>> PROPERTY(entries); + + bool _try_load_history_entry(GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root) { + typename decltype(entries)::iterator it = entries.find(date); + if (it == entries.end()) { + const std::pair<typename decltype(entries)::iterator, bool> result = entries.emplace(date, _make_entry(date)); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create history entry at date ", date); + return false; + } + } + return _load_history_entry(game_manager, args..., *it->second, root); + } + + protected: + HistoryMap() = default; + + virtual std::unique_ptr<entry_type> _make_entry(Date date) const = 0; + + virtual bool _load_history_entry( + GameManager const& game_manager, Args... args, entry_type& entry, ast::NodeCPtr root + ) = 0; + + bool _load_history_file(GameManager const& game_manager, Args... args, ast::NodeCPtr root) { + return _try_load_history_entry(game_manager, args..., _get_start_date(game_manager), root); + } + + bool _load_history_sub_entry_callback( + GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root, std::string_view key, + ast::NodeCPtr value, NodeTools::key_value_callback_t default_callback = NodeTools::key_value_invalid_callback + ) { + /* Date blocks (loaded into the corresponding HistoryEntry) */ + bool is_date = false; + const Date sub_date { Date::from_string(key, &is_date, true) }; + if (is_date) { + if (sub_date <= date) { + Logger::error("History entry ", sub_date, " defined before parent entry date ", date); + return false; + } + const Date end_date = _get_end_date(game_manager); + if (sub_date > end_date) { + Logger::error("History entry ", sub_date, " defined after end date ", end_date); + return false; + } + if (_try_load_history_entry(game_manager, args..., sub_date, value)) { + return true; + } else { + Logger::error("Failed to load history entry at date ", sub_date); + return false; + } + } + + return default_callback(key, value); + } + + public: + /* Returns history entry at specific date, if date doesn't have an entry returns nullptr. */ + entry_type const* get_entry(Date date) const { + typename decltype(entries)::const_iterator it = entries.find(date); + if (it != entries.end()) { + return it->second.get(); + } + return nullptr; + } + /* Returns history entries up to date as an ordered list of entries. */ + std::vector<entry_type const*> get_entries(Date end) const { + std::vector<entry_type const*> ret; + for (typename decltype(entries)::value_type const& entry : entries) { + if (entry.first <= end) { + ret.push_back(entry.second.get()); + } + } + std::sort(ret.begin(), ret.end(), [](entry_type const* lhs, entry_type const* rhs) -> bool { + return lhs->get_date() < rhs->get_date(); + }); + return ret; + } + }; +} diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index c2d5451..141d256 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -6,132 +6,121 @@ 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 -) : 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) } {} +ProvinceHistoryEntry::ProvinceHistoryEntry(Province const& new_province, Date new_date) + : HistoryEntry { new_date }, province { new_province } {} -Country const* ProvinceHistory::get_owner() const { - return owner; -} - -Country const* ProvinceHistory::get_controller() const { - return controller; -} - -uint8_t ProvinceHistory::get_colony_status() const { - return colonial; -} - -bool ProvinceHistory::is_slave() const { - return slave; -} +ProvinceHistoryMap::ProvinceHistoryMap(Province const& new_province) : province { new_province } {} -std::vector<Country const*> const& ProvinceHistory::get_cores() const { - return cores; +std::unique_ptr<ProvinceHistoryEntry> ProvinceHistoryMap::_make_entry(Date date) const { + return std::unique_ptr<ProvinceHistoryEntry> { new ProvinceHistoryEntry { province, date } }; } -bool ProvinceHistory::is_core_of(Country const* country) const { - return std::find(cores.begin(), cores.end(), country) != cores.end(); -} - -Good const* ProvinceHistory::get_rgo() const { - return rgo; -} - -uint8_t ProvinceHistory::get_life_rating() const { - return life_rating; -} - -TerrainType const* ProvinceHistory::get_terrain_type() const { - return terrain_type; -} +bool ProvinceHistoryMap::_load_history_entry( + GameManager const& game_manager, ProvinceHistoryEntry& entry, ast::NodeCPtr root +) { + 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(); + + using enum Province::colony_status_t; + static const string_map_t<Province::colony_status_t> colony_status_map { + { "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY } + }; + + return expect_dictionary_keys_and_default( + [this, &game_manager, &building_manager, &entry]( + std::string_view key, ast::NodeCPtr value) -> bool { + // used for province buildings like forts or railroads + Building const* building = building_manager.get_building_by_identifier(key); + if (building != nullptr) { + return expect_uint<Building::level_t>([&entry, building](Building::level_t level) -> bool { + entry.buildings[building] = level; + return true; + })(value); + } -std::map<Building const*, uint8_t> const& ProvinceHistory::get_buildings() const { - return buildings; -} + return _load_history_sub_entry_callback(game_manager, entry.get_date(), value, key, value); + }, + "owner", ZERO_OR_ONE, + country_manager.expect_country_identifier(assign_variable_callback_pointer(entry.owner)), + "controller", ZERO_OR_ONE, + country_manager.expect_country_identifier(assign_variable_callback_pointer(entry.controller)), + "add_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&entry](Country const& core) -> bool { + entry.add_cores.push_back(&core); + return true; + } + ), + "remove_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&entry](Country const& core) -> bool { + entry.remove_cores.push_back(&core); + return true; + } + ), + "colonial", ZERO_OR_ONE, + expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), + "colony", ZERO_OR_ONE, + expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), + "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.slave)), + "trade_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(entry.rgo)), + "life_rating", ZERO_OR_ONE, expect_uint<Province::life_rating_t>(assign_variable_callback(entry.life_rating)), + "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier( + assign_variable_callback_pointer(entry.terrain_type) + ), + "party_loyalty", ZERO_OR_MORE, [&ideology_manager, &entry](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); + entry.party_loyalties[ideology] = amount; + return ret; + }, + "state_building", ZERO_OR_MORE, [&building_manager, &entry](ast::NodeCPtr node) -> bool { + Building const* building = nullptr; + uint8_t level = 0; -std::map<Ideology const*, uint8_t> const& ProvinceHistory::get_party_loyalties() const { - return party_loyalties; + const bool ret = expect_dictionary_keys( + "level", ONE_EXACTLY, expect_uint(assign_variable_callback(level)), + "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); + entry.buildings[building] = level; + return ret; + } + )(root); } -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 -) { - if (locked) { - Logger::error("Cannot add new history entry to province history registry: locked!"); - return false; +void ProvinceHistoryManager::lock_province_histories(Map const& map, bool detailed_errors) { + std::vector<bool> province_checklist(map.get_province_count()); + for (decltype(province_histories)::value_type const& entry : province_histories) { + province_checklist[entry.first->get_index() - 1] = true; } - /* combine duplicate histories, priority to current (defined later) */ - auto& province_registry = province_histories[province]; - const auto existing_entry = province_registry.find(date); - - if (existing_entry != province_registry.end()) { - if (owner != nullptr) { - existing_entry->second.owner = owner; - } - if (controller != nullptr) { - existing_entry->second.controller = controller; - } - if (rgo != nullptr) { - existing_entry->second.rgo = rgo; - } - if (terrain_type != nullptr) { - existing_entry->second.terrain_type = terrain_type; - } - if (colonial) { - existing_entry->second.colonial = *colonial; - } - if (slave) { - existing_entry->second.slave = *slave; - } - if (life_rating) { - existing_entry->second.life_rating = *life_rating; - } - if (buildings) { - existing_entry->second.buildings = std::move(*buildings); - } - if (party_loyalties) { - existing_entry->second.party_loyalties = std::move(*party_loyalties); - } - // 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) { - const auto core = std::find(cores.begin(), cores.end(), which); - if (core == cores.end()) { - Logger::error( - "In history of province ", province->get_identifier(), " tried to remove nonexistant core of country: ", - which->get_identifier(), " at date ", date.to_string() - ); - return false; + size_t missing = 0; + for (size_t idx = 0; idx < province_checklist.size(); ++idx) { + if (!province_checklist[idx]) { + Province const& province = *map.get_province_by_index(idx + 1); + if (!province.get_water()) { + if (detailed_errors) { + Logger::warning("Province history missing for province: ", province.get_identifier()); + } + missing++; } - existing_entry->second.cores.erase(core); } - } else { - province_registry.emplace(date, ProvinceHistory { - owner, controller, *colonial, *slave, std::move(cores), rgo, *life_rating, - terrain_type, std::move(*buildings), std::move(*party_loyalties) - }); } - return true; -} - -void ProvinceHistoryManager::lock_province_histories() { - for (auto const& entry : province_histories) { - if (entry.second.size() == 0) { - Logger::error( - "Attempted to lock province histories - province ", entry.first->get_identifier(), " has no history entries!" - ); - } + if (missing > 0) { + Logger::warning("Province history is missing for ", missing, " provinces"); } + Logger::info("Locked province history registry after registering ", province_histories.size(), " items"); locked = true; } @@ -140,190 +129,43 @@ bool ProvinceHistoryManager::is_locked() const { return locked; } -ProvinceHistory const* ProvinceHistoryManager::get_province_history(Province const* province, Date entry) const { - Date closest_entry; - auto province_registry = province_histories.find(province); - - if (province_registry == province_histories.end()) { - Logger::error("Attempted to access history of undefined province ", province->get_identifier()); +ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(Province const* province) const { + if (province == nullptr) { + Logger::error("Attempted to access history of null province"); return nullptr; } - - for (auto const& current : province_registry->second) { - if (current.first == entry) { - return ¤t.second; - } - if (current.first > entry) { - continue; - } - if (current.first > closest_entry && current.first < entry) { - closest_entry = current.first; - } - } - - auto entry_registry = province_registry->second.find(closest_entry); - if (entry_registry != province_registry->second.end()) { - return &entry_registry->second; + decltype(province_histories)::const_iterator province_registry = province_histories.find(province); + if (province_registry != province_histories.end()) { + return &province_registry->second; + } else { + Logger::error("Attempted to access history of province ", province->get_identifier(), " but none has been defined!"); + return nullptr; } - /* warned about lack of entries earlier, return nullptr */ - return nullptr; -} - -inline ProvinceHistory const* ProvinceHistoryManager::get_province_history( - Province const* province, Bookmark const* bookmark -) const { - return get_province_history(province, bookmark->get_date()); } -inline bool ProvinceHistoryManager::_load_province_history_entry( - GameManager& game_manager, std::string_view province, Date const& date, ast::NodeCPtr root +bool ProvinceHistoryManager::load_province_history_file( + GameManager const& game_manager, Province const& province, ast::NodeCPtr root ) { - 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::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; - - bool ret = expect_dictionary_keys_and_default( - [&game_manager, &buildings](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; - } - - bool is_date; - Date().from_string(key, &is_date, true); - if (is_date) { - return true; - } - - 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; - } - - 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)) - )(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; - - 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)), - "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect - )(node); - if(!buildings.has_value()) - buildings = decltype(buildings)::value_type {}; - buildings->emplace(building, level); - return ret; - } - )(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) - ); - 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); - - ret &= expect_dictionary( - [this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool { - bool is_date = false; - Date entry = Date().from_string(key, &is_date, true); - if (!is_date) { - return true; - } - - Date const& 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() - ); - return false; - } + if (locked) { + Logger::error( + "Attempted to load province history file for ", province.get_identifier(), + " after province history registry was locked!" + ); + return false; + } - return _load_province_history_entry(game_manager, name, entry, value); + decltype(province_histories)::iterator it = province_histories.find(&province); + if (it == province_histories.end()) { + const std::pair<decltype(province_histories)::iterator, bool> result = + province_histories.emplace(&province, ProvinceHistoryMap { province }); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create province history map for province ", province.get_identifier()); + return false; } - )(root); + } + ProvinceHistoryMap& province_history = it->second; - return ret; + return province_history._load_history_file(game_manager, root); } diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 42dacbf..5a18723 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -8,79 +8,64 @@ #include "openvic-simulation/economy/Building.hpp" #include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/history/Bookmark.hpp" +#include "openvic-simulation/history/HistoryMap.hpp" #include "openvic-simulation/map/Province.hpp" #include "openvic-simulation/map/TerrainType.hpp" namespace OpenVic { + struct ProvinceHistoryMap; + + struct ProvinceHistoryEntry : HistoryEntry { + friend struct ProvinceHistoryMap; + + using building_level_map_t = std::map<Building const*, Building::level_t>; + + private: + Province const& PROPERTY(province); + + std::optional<Country const*> PROPERTY(owner); + std::optional<Country const*> PROPERTY(controller); + std::optional<Province::colony_status_t> PROPERTY(colonial); + std::optional<bool> PROPERTY(slave); + std::vector<Country const*> PROPERTY(add_cores); + std::vector<Country const*> PROPERTY(remove_cores); + std::optional<Good const*> PROPERTY(rgo); + std::optional<Province::life_rating_t> PROPERTY(life_rating); + std::optional<TerrainType const*> PROPERTY(terrain_type); + building_level_map_t PROPERTY(buildings); + decimal_map_t<Ideology const*> PROPERTY(party_loyalties); + + ProvinceHistoryEntry(Province const& new_province, Date new_date); + }; + struct ProvinceHistoryManager; - struct ProvinceHistory { + struct ProvinceHistoryMap : HistoryMap<ProvinceHistoryEntry> { friend struct ProvinceHistoryManager; private: - Country const* owner; - Country const* controller; - uint8_t colonial; - bool slave; - std::vector<Country const*> cores; // non-standard, maintains cores between entries - Good const* rgo; - uint8_t life_rating; - TerrainType const* terrain_type; - std::map<Building const*, uint8_t> buildings; - std::map<Ideology const*, uint8_t> 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 - ); + Province const& PROPERTY(province); - public: - Country const* get_owner() const; - Country const* get_controller() const; - uint8_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; - 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; + protected: + ProvinceHistoryMap(Province const& new_province); + + std::unique_ptr<ProvinceHistoryEntry> _make_entry(Date date) const override; + bool _load_history_entry(GameManager const& game_manager, ProvinceHistoryEntry& entry, ast::NodeCPtr root) override; }; struct ProvinceHistoryManager { private: - std::map<Province const*, std::map<Date, ProvinceHistory>> province_histories; + std::map<Province const*, ProvinceHistoryMap> PROPERTY(province_histories); bool locked = false; - inline bool _load_province_history_entry( - GameManager& game_manager, std::string_view province, Date const& date, ast::NodeCPtr root - ); - public: - ProvinceHistoryManager() {} - - 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::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 - ); - - void lock_province_histories(); + ProvinceHistoryManager() = default; + + void lock_province_histories(Map const& map, bool detailed_errors); bool is_locked() const; - /* Returns history of province at date, if date doesn't have an entry returns closest entry before date. - * Return can be nullptr if an error occurs. */ - ProvinceHistory const* get_province_history(Province const* province, Date entry) const; - /* 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; + ProvinceHistoryMap const* get_province_history(Province const* province) 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 |