From c9c198e3b47e84eaea998cd9d2f7a8aa2b50ce73 Mon Sep 17 00:00:00 2001 From: Joel Machens Date: Mon, 16 Oct 2023 21:43:40 -0500 Subject: Country History & Order of Battle Loading --- src/openvic-simulation/history/CountryHistory.cpp | 315 ++++++++++++++++++++++ src/openvic-simulation/history/CountryHistory.hpp | 120 +++++++++ src/openvic-simulation/history/HistoryManager.hpp | 3 + 3 files changed, 438 insertions(+) create mode 100644 src/openvic-simulation/history/CountryHistory.cpp create mode 100644 src/openvic-simulation/history/CountryHistory.hpp (limited to 'src/openvic-simulation/history') diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp new file mode 100644 index 0000000..b590022 --- /dev/null +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -0,0 +1,315 @@ +#include "CountryHistory.hpp" + +#include "openvic-simulation/GameManager.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +CountryHistory::CountryHistory( + Culture const* new_primary_culture, + std::vector&& new_accepted_cultures, + Religion const* new_religion, + CountryParty const* new_ruling_party, + Date new_last_election, + std::map&& 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&& 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 } {} + +Culture const* CountryHistory::get_primary_culture() const { + return primary_culture; +} + +const std::vector& 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& 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& CountryHistory::get_reforms() const { + return reforms; +} + +Deployment const* CountryHistory::get_inital_oob() const { + return inital_oob; +} + +bool CountryHistoryManager::add_country_history_entry( + Country const* country, + Date date, + Culture const* primary_culture, + std::vector&& accepted_cultures, + Religion const* religion, + CountryParty const* ruling_party, + Date last_election, + std::map&& 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&& reforms, + Deployment const* initial_oob, + bool updated_accepted_cultures, + bool updated_upper_house, + bool updated_reforms +) { + 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 + }); + } + return true; +} + +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; +} + +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()); + 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; + } + /* 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, OpenVic::Date date, 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 accepted_cultures; + std::vector reforms; + std::map 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* 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; +} + +bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, std::string_view name, Date start_date, ast::NodeCPtr root) { + if (game_manager.get_country_manager().get_country_by_identifier(name)->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, 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; + + if (entry > game_manager.get_define_manager().get_end_date()) { + Logger::error("History entry ", entry.to_string(), " of country ", name, " defined after defined end date ", game_manager.get_define_manager().get_end_date().to_string()); + return false; + } + + return _load_country_history_entry(game_manager, name, entry, value); + } + )(root); + + return ret; +} diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp new file mode 100644 index 0000000..a59ebea --- /dev/null +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include +#include + +#include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/history/Bookmark.hpp" +#include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/military/Deployment.hpp" +#include "openvic-simulation/politics/Government.hpp" +#include "openvic-simulation/politics/Ideology.hpp" +#include "openvic-simulation/politics/Issue.hpp" +#include "openvic-simulation/politics/NationalValue.hpp" +#include "openvic-simulation/pop/Culture.hpp" +#include "openvic-simulation/pop/Religion.hpp" +#include "openvic-simulation/types/Colour.hpp" +#include "openvic-simulation/types/Date.hpp" + +namespace OpenVic { + struct CountryHistoryManager; + + struct CountryHistory { + friend struct CountryHistoryManager; + + private: + Culture const* primary_culture; + std::vector accepted_cultures; + Religion const* religion; + CountryParty const* ruling_party; + Date last_election; + std::map 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 reforms; + Deployment const* inital_oob; + // TODO: technologies, tech schools, and inventions when PR#51 merged + // TODO: starting foreign investment + + CountryHistory( + Culture const* new_primary_culture, + std::vector&& new_accepted_cultures, + Religion const* new_religion, + CountryParty const* new_ruling_party, + Date new_last_election, + std::map&& 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&& new_reforms, + Deployment const* new_inital_oob + ); + + public: + Culture const* get_primary_culture() const; + const std::vector& get_accepted_cultures() const; + Religion const* get_religion() const; + CountryParty const* get_ruling_party() const; + const Date get_last_election() const; + const std::map& 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& get_reforms() const; + Deployment const* get_inital_oob() const; + }; + + struct CountryHistoryManager { + private: + std::map> country_histories; + bool locked = false; + + inline bool _load_country_history_entry(GameManager& game_manager, std::string_view name, OpenVic::Date date, ast::NodeCPtr root); + + public: + CountryHistoryManager() {} + + bool add_country_history_entry( + Country const* country, + Date date, + Culture const* primary_culture, + std::vector&& accepted_cultures, + Religion const* religion, + CountryParty const* ruling_party, + Date last_election, + std::map&& 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&& reforms, + Deployment const* initial_oob, + bool updated_accepted_cultures, + bool updated_upper_house, + bool updated_reforms + ); + + 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; + + bool load_country_history_file(GameManager& game_manager, std::string_view name, Date start_date, ast::NodeCPtr root); + }; + +} // namespace OpenVic diff --git a/src/openvic-simulation/history/HistoryManager.hpp b/src/openvic-simulation/history/HistoryManager.hpp index bec5359..e0d6877 100644 --- a/src/openvic-simulation/history/HistoryManager.hpp +++ b/src/openvic-simulation/history/HistoryManager.hpp @@ -1,15 +1,18 @@ #pragma once #include "openvic-simulation/history/Bookmark.hpp" +#include "openvic-simulation/history/CountryHistory.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { struct HistoryManager { private: BookmarkManager bookmark_manager; + CountryHistoryManager country_manager; public: REF_GETTERS(bookmark_manager) + REF_GETTERS(country_manager) inline bool load_bookmark_file(ast::NodeCPtr root) { return bookmark_manager.load_bookmark_file(root); -- cgit v1.2.3-56-ga3b1