From 17697f6216159f6a89dd8d64a22de0262dcf2aef Mon Sep 17 00:00:00 2001 From: BrickPi <49528459+BrickPi@users.noreply.github.com> Date: Thu, 26 Oct 2023 14:18:31 -0500 Subject: Implement Province History Loading --- src/openvic-simulation/dataloader/Dataloader.cpp | 27 ++- src/openvic-simulation/history/CountryHistory.cpp | 11 +- src/openvic-simulation/history/CountryHistory.hpp | 4 +- src/openvic-simulation/history/HistoryManager.hpp | 3 + src/openvic-simulation/history/ProvinceHistory.cpp | 263 +++++++++++++++++++++ src/openvic-simulation/history/ProvinceHistory.hpp | 88 +++++++ 6 files changed, 388 insertions(+), 8 deletions(-) create mode 100644 src/openvic-simulation/history/ProvinceHistory.cpp create mode 100644 src/openvic-simulation/history/ProvinceHistory.hpp diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 9c05d28..ad35056 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -529,18 +529,43 @@ bool Dataloader::_load_countries(GameManager& game_manager) const { 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; } - return game_manager.get_history_manager().get_country_manager().load_country_history_file(game_manager, tag, game_manager.get_define_manager().get_start_date(), parse_defines(lookup_file(file)).get_file_node()); + 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.get_history_manager().get_country_manager().lock_country_histories(); + /* Province History */ + for (auto root : roots) { + const fs::path path = root / province_history_directory; + std::error_code ec; + 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(" ")); + + if (!game_manager.get_map().has_province_identifier(province_id)) { + Logger::error("Error loading history for province ", province_id, ": province not defined!"); + return false; + } + + 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.get_history_manager().get_province_manager().lock_province_histories(); + return ret; } diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index b590022..5e91a85 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -185,7 +185,7 @@ inline CountryHistory const* CountryHistoryManager::get_country_history(Country 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) { +inline bool CountryHistoryManager::_load_country_history_entry(GameManager& game_manager, std::string_view name, Date const& date, ast::NodeCPtr root) { Province const* capital = nullptr; Culture const* primary_culture = nullptr; Religion const* religion = nullptr; @@ -291,10 +291,10 @@ inline bool CountryHistoryManager::_load_country_history_entry(GameManager& game return ret; } -bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, std::string_view name, Date start_date, ast::NodeCPtr root) { +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()) 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); + 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 { @@ -302,8 +302,9 @@ bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, 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()); + 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()); return false; } diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index a59ebea..56d04c6 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -79,7 +79,7 @@ namespace OpenVic { 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); + inline bool _load_country_history_entry(GameManager& game_manager, std::string_view name, Date const& date, ast::NodeCPtr root); public: CountryHistoryManager() {} @@ -114,7 +114,7 @@ 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, Date start_date, ast::NodeCPtr root); + bool load_country_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root); }; } // namespace OpenVic diff --git a/src/openvic-simulation/history/HistoryManager.hpp b/src/openvic-simulation/history/HistoryManager.hpp index e0d6877..5782e97 100644 --- a/src/openvic-simulation/history/HistoryManager.hpp +++ b/src/openvic-simulation/history/HistoryManager.hpp @@ -2,6 +2,7 @@ #include "openvic-simulation/history/Bookmark.hpp" #include "openvic-simulation/history/CountryHistory.hpp" +#include "openvic-simulation/history/ProvinceHistory.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { @@ -9,10 +10,12 @@ namespace OpenVic { private: BookmarkManager bookmark_manager; CountryHistoryManager country_manager; + ProvinceHistoryManager province_manager; public: REF_GETTERS(bookmark_manager) REF_GETTERS(country_manager) + REF_GETTERS(province_manager) inline bool load_bookmark_file(ast::NodeCPtr root) { return bookmark_manager.load_bookmark_file(root); diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp new file mode 100644 index 0000000..469bbfd --- /dev/null +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -0,0 +1,263 @@ +#include "ProvinceHistory.hpp" + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/GameManager.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +ProvinceHistory::ProvinceHistory( + Country const* new_owner, + Country const* new_controller, + std::vector&& new_cores, + Good const* new_rgo, + uint8_t new_life_rating, + TerrainType const* new_terrain_type, + std::map&& new_buildings, + std::map&& new_party_loyalties +) : owner { new_owner }, + controller { new_controller }, + 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) } {} + +Country const* ProvinceHistory::get_owner() const { + return owner; +} + +Country const* ProvinceHistory::get_controller() const { + return controller; +} + +const std::vector& ProvinceHistory::get_cores() const { + return cores; +} + +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; +} + +const std::map& ProvinceHistory::get_buildings() const { + return buildings; +} + +const std::map& 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::vector&& cores, + Good const* rgo, + uint8_t life_rating, + TerrainType const* terrain_type, + std::map&& buildings, + std::map&& party_loyalties, + bool updated_cores, + bool updated_buildings, + bool updated_loyalties +) { + if (locked) { + Logger::error("Cannot add new history entry to province history registry: locked!"); + return false; + } + + /* 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 (updated_cores) existing_entry->second.cores = std::move(cores); + if (rgo != nullptr) existing_entry->second.rgo = rgo; + if (life_rating > 0) existing_entry->second.life_rating = life_rating; + if (terrain_type != nullptr) existing_entry->second.terrain_type = terrain_type; + if (updated_buildings) existing_entry->second.buildings = std::move(buildings); + if (updated_loyalties) existing_entry->second.party_loyalties = std::move(party_loyalties); + } else { + province_registry.emplace(date, ProvinceHistory { + owner, + controller, + std::move(cores), + rgo, + life_rating, + terrain_type, + std::move(buildings), + std::move(party_loyalties) + }); + } + return true; +} + +void ProvinceHistoryManager::lock_province_histories() { + for (const auto& entry : province_histories) { + if (entry.second.size() == 0) { + Logger::error("Attempted to lock province histories - province ", entry.first->get_identifier(), " has no history entries!"); + } + } + Logger::info("Locked province history registry after registering ", province_histories.size(), " items"); + locked = true; +} + +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()); + return nullptr; + } + + for (const auto& 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; + /* 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) { + Country const* owner = nullptr; + Country const* controller = nullptr; + std::vector cores; + Good const* rgo; + uint8_t life_rating = 0; + TerrainType const* terrain_type; + std::map buildings; + std::map party_loyalties; + + bool updated_cores = false; + bool updated_buildings = false; + bool updated_loyalties = false; + + bool ret = expect_dictionary_keys_and_default( + [&game_manager, &buildings, &updated_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); + + buildings.emplace(building, level); + updated_buildings = true; + 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, &updated_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); + updated_cores = true; + return ret; + }, + "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(assign_variable_callback(life_rating)), + "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, &updated_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); + party_loyalties.emplace(ideology, amount); + updated_loyalties = true; + return ret; + }, + "state_building", ZERO_OR_MORE, [&game_manager, &buildings, &updated_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); + buildings.emplace(building, level); + updated_buildings = true; + return ret; + } + )(root); + + ret &= add_province_history_entry( + game_manager.get_map().get_province_by_identifier(province), + date, + owner, + controller, + std::move(cores), + rgo, + life_rating, + terrain_type, + std::move(buildings), + std::move(party_loyalties), + updated_cores, + updated_buildings, + updated_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; + } + + return _load_province_history_entry(game_manager, name, entry, value); + } + )(root); + + return ret; +} diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp new file mode 100644 index 0000000..4094403 --- /dev/null +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +#include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/map/TerrainType.hpp" +#include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/economy/Good.hpp" +#include "openvic-simulation/economy/Building.hpp" +#include "openvic-simulation/history/Bookmark.hpp" + +namespace OpenVic { + struct ProvinceHistoryManager; + + struct ProvinceHistory { + friend struct ProvinceHistoryManager; + + private: + Country const* owner; + Country const* controller; + std::vector cores; + Good const* rgo; + uint8_t life_rating; + TerrainType const* terrain_type; + std::map buildings; + std::map party_loyalties; + + ProvinceHistory( + Country const* new_owner, + Country const* new_controller, + std::vector&& new_cores, + Good const* new_rgo, + uint8_t new_life_rating, + TerrainType const* new_terrain_type, + std::map&& new_buildings, + std::map&& new_party_loyalties + ); + + public: + Country const* get_owner() const; + Country const* get_controller() const; + const std::vector& 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; + const std::map& get_buildings() const; + const std::map& get_party_loyalties() const; + }; + + struct ProvinceHistoryManager { + private: + std::map> 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::vector&& cores, + Good const* rgo, + uint8_t life_rating, + TerrainType const* terrain_type, + std::map&& buildings, + std::map&& party_loyalties, + bool updated_cores, + bool updated_buildings, + bool updated_loyalties + ); + + void lock_province_histories(); + 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; + + bool load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root); + }; +} // namespace OpenVic -- cgit v1.2.3-56-ga3b1