diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index 022406351..47e86fccf 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -1,8 +1,10 @@ #include "InstanceManager.hpp" +#include "country/SharedCountryValuesDeps.hpp" #include "openvic-simulation/DefinitionManager.hpp" #include "openvic-simulation/console/ConsoleInstance.hpp" #include "openvic-simulation/core/stl/containers/TypedSpan.hpp" +#include "openvic-simulation/country/SharedCountryValuesDeps.hpp" #include "openvic-simulation/misc/GameAction.hpp" #include "openvic-simulation/utility/Logger.hpp" #include "openvic-simulation/utility/ThreadDeps.hpp" @@ -32,7 +34,6 @@ InstanceManager::InstanceManager( new_definition_manager.get_modifier_manager().get_modifier_effect_cache() }, country_instance_deps { - new_definition_manager.get_economy_manager().get_building_type_manager().get_building_types(), new_definition_manager.get_define_manager().get_country_defines(), country_relation_manager, new_definition_manager.get_crime_manager().get_crime_modifiers(), @@ -65,12 +66,9 @@ InstanceManager::InstanceManager( new_definition_manager.get_pop_manager().get_strata_count() ) }, - new_definition_manager.get_pop_manager().get_pop_types(), new_definition_manager.get_politics_manager().get_issue_manager().get_reform_groups(), - new_definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(), new_definition_manager.get_military_manager().get_unit_type_manager().get_ship_types(), new_definition_manager.get_pop_manager().get_stratas(), - new_definition_manager.get_research_manager().get_technology_manager().get_technologies(), new_definition_manager.get_military_manager().get_unit_type_manager() }, pops_aggregate_deps { @@ -112,10 +110,16 @@ InstanceManager::InstanceManager( new_definition_manager.get_define_manager().get_country_defines(), new_definition_manager.get_country_definition_manager(), country_instance_deps, - good_instance_manager, - new_definition_manager.get_define_manager().get_pops_defines(), - new_definition_manager.get_pop_manager().get_pop_types(), - new_definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(), + SharedCountryValuesDeps { + good_instance_manager, + new_definition_manager.get_define_manager().get_pops_defines(), + new_definition_manager.get_economy_manager().get_building_type_manager().get_building_types(), + new_definition_manager.get_research_manager().get_invention_manager().get_inventions(), + new_definition_manager.get_pop_manager().get_pop_types(), + new_definition_manager.get_politics_manager().get_issue_manager().get_reforms(), + new_definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(), + new_definition_manager.get_research_manager().get_technology_manager().get_technologies() + }, thread_pool }, unit_instance_manager { diff --git a/src/openvic-simulation/core/stl/containers/TypedSpan.hpp b/src/openvic-simulation/core/stl/containers/TypedSpan.hpp index ec76bc582..fee471318 100644 --- a/src/openvic-simulation/core/stl/containers/TypedSpan.hpp +++ b/src/openvic-simulation/core/stl/containers/TypedSpan.hpp @@ -18,6 +18,8 @@ namespace OpenVic { public: using forwardable_span::forwardable_span; + constexpr TypedSpan() {} + template constexpr TypedSpan(OtherT& other) : forwardable_span( diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 5bdc3df4e..2f557309a 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -12,6 +12,8 @@ #include "openvic-simulation/core/error/ErrorMacros.hpp" #include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/country/CountryDefinition.hpp" +#include "openvic-simulation/country/CountryInstanceDeps.hpp" +#include "openvic-simulation/country/CountryInstanceManager.hpp" #include "openvic-simulation/country/SharedCountryValues.hpp" #include "openvic-simulation/defines/CountryDefines.hpp" #include "openvic-simulation/defines/DiplomacyDefines.hpp" @@ -52,14 +54,10 @@ #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/types/fixed_point/Math.hpp" -#include "openvic-simulation/types/IndexedFlatMap.hpp" #include "openvic-simulation/types/TypedIndices.hpp" #include "openvic-simulation/types/UnitBranchType.hpp" #include "openvic-simulation/utility/Logger.hpp" -#include "CountryInstanceDeps.hpp" -#include "CountryInstanceManager.hpp" - using namespace OpenVic; using enum CountryInstance::country_status_t; @@ -94,79 +92,92 @@ CountryInstance::CountryInstance( colour { ERROR_COLOUR }, /* Production */ - building_type_unlock_levels { country_instance_deps.building_types }, + building_type_unlock_levels { new_shared_country_values.building_types.size(), building_level_t(0) }, /* Budget */ balance_history{DAYS_OF_BALANCE_HISTORY}, - taxable_income_by_pop_type { country_instance_deps.pop_types }, + taxable_income_by_pop_type { new_shared_country_values.pop_types.size(), fixed_point_t::_0 }, effective_tax_rate_by_strata { - country_instance_deps.stratas, - [this](Strata const& strata)->auto { - return [this,&strata](DependencyTracker& tracker)->fixed_point_t { - return tax_efficiency.get(tracker) * tax_rate_slider_value_by_strata.at(strata).get_value(tracker); + country_instance_deps.stratas.size(), + [this](strata_index_t strata_index)->auto { + return [this, strata_index](DependencyTracker& tracker)->fixed_point_t { + return tax_efficiency.get(tracker) * tax_rate_slider_value_by_strata[strata_index].get_value(tracker); }; } }, administration_salary_base_by_pop_type{ - country_instance_deps.pop_types, - [this](PopType const& pop_type)->auto { - return [this,&pop_type](DependencyTracker& tracker)->fixed_point_t { + new_shared_country_values.pop_types.size(), + [this](pop_type_index_t pop_type_index)->auto { + return [this, pop_type_index](DependencyTracker& tracker)->fixed_point_t { return corruption_cost_multiplier.get(tracker) - * shared_country_values.get_shared_pop_type_values(pop_type) + * shared_country_values.shared_pop_type_values[pop_type_index] .get_administration_salary_base(tracker); }; } }, education_salary_base_by_pop_type{ - country_instance_deps.pop_types, - [this](PopType const& pop_type)->auto { - return [this,&pop_type](DependencyTracker& tracker)->fixed_point_t { + new_shared_country_values.pop_types.size(), + [this](pop_type_index_t pop_type_index)->auto { + return [this, pop_type_index](DependencyTracker& tracker)->fixed_point_t { return corruption_cost_multiplier.get(tracker) - * shared_country_values.get_shared_pop_type_values(pop_type) + * shared_country_values.shared_pop_type_values[pop_type_index] .get_education_salary_base(tracker); }; } }, military_salary_base_by_pop_type{ - country_instance_deps.pop_types, - [this](PopType const& pop_type)->auto { - return [this,&pop_type](DependencyTracker& tracker)->fixed_point_t { + new_shared_country_values.pop_types.size(), + [this](pop_type_index_t pop_type_index)->auto { + return [this, pop_type_index](DependencyTracker& tracker)->fixed_point_t { return corruption_cost_multiplier.get(tracker) - * shared_country_values.get_shared_pop_type_values(pop_type) + * shared_country_values.shared_pop_type_values[pop_type_index] .get_military_salary_base(tracker); }; } }, social_income_variant_base_by_pop_type{ - country_instance_deps.pop_types, - [this](PopType const& pop_type)->auto { - return [this,&pop_type](DependencyTracker& tracker)->fixed_point_t { + new_shared_country_values.pop_types.size(), + [this](pop_type_index_t pop_type_index)->auto { + return [this, pop_type_index](DependencyTracker& tracker)->fixed_point_t { return corruption_cost_multiplier.get(tracker) - * shared_country_values.get_shared_pop_type_values(pop_type) + * shared_country_values.shared_pop_type_values[pop_type_index] .get_social_income_variant_base(tracker); }; } }, - tax_rate_slider_value_by_strata { country_instance_deps.stratas }, + tax_rate_slider_value_by_strata { + country_instance_deps.stratas.size(), + [this](strata_index_t strata_index)->std::tuple{ + // Some sliders need to have their max range limits temporarily set to 1 so they can start with a value of 0.5 or 1.0. + // The range limits will be corrected on the first gamestate update, and the values will go to the closest valid point. + // min, max, new value + return { 0, 1, fixed_point_t::_0_50 }; + } + }, /* Technology */ - technology_unlock_levels { country_instance_deps.technologies }, - invention_unlock_levels { country_instance_deps.inventions }, + technology_unlock_levels { new_shared_country_values.technologies.size(), technology_unlock_level_t(0) }, + invention_unlock_levels { country_instance_deps.inventions.size(), technology_unlock_level_t(0) }, /* Politics */ - upper_house_proportion_by_ideology { country_instance_deps.ideologies }, - reforms { country_instance_deps.reform_groups }, - flag_overrides_by_government_type { country_instance_deps.government_types }, - crime_unlock_levels { country_instance_deps.crimes }, + upper_house_proportion_by_ideology { country_instance_deps.ideologies.size(), fixed_point_t::_0 }, + reforms { country_instance_deps.reform_groups.size(), std::nullopt }, + flag_overrides_by_government_type { country_instance_deps.government_types.size(), nullptr }, + crime_unlock_levels { country_instance_deps.crimes.size(), technology_unlock_level_t(0) }, /* Trade */ - goods_data { country_instance_deps.good_instances }, + goods_data { + country_instance_deps.good_instances.size(), + [pop_type_count = new_shared_country_values.pop_types.size()](good_index_t i)->pop_type_index_t { + return pop_type_count; + } + }, /* Diplomacy */ /* Military */ regiment_type_unlock_levels { - regiment_type_index_t(country_instance_deps.regiment_types.size()), + regiment_type_index_t(new_shared_country_values.regiment_types.size()), technology_unlock_level_t(0) }, ship_type_unlock_levels { @@ -180,7 +191,7 @@ CountryInstance::CountryInstance( if (current_government_type == nullptr) { return nullptr; } - GovernmentType const* flag_override = flag_overrides_by_government_type.at(*current_government_type); + GovernmentType const* flag_override = flag_overrides_by_government_type[current_government_type->index]; return flag_override == nullptr ? current_government_type : flag_override; @@ -248,13 +259,6 @@ CountryInstance::CountryInstance( // Exclude PROVINCE (local) modifier effects from the country's modifier sum modifier_sum.set_this_excluded_targets(ModifierEffect::target_t::PROVINCE); - // Some sliders need to have their max range limits temporarily set to 1 so they can start with a value of 0.5 or 1.0. - // The range limits will be corrected on the first gamestate update, and the values will go to the closest valid point. - for (ClampedValue& tax_rate_slider_value : tax_rate_slider_value_by_strata.get_values()) { - tax_rate_slider_value.set_bounds(0, 1); - tax_rate_slider_value.set_value(fixed_point_t::_0_50); - } - // army, navy and construction spending have minimums defined in EconomyDefines and always have an unmodified max (1.0). EconomyDefines const& economy_defines = country_instance_deps.economy_defines; army_spending_slider_value.set_bounds(economy_defines.get_minimum_army_spending_slider_value(), 1); @@ -285,19 +289,19 @@ CountryInstance::CountryInstance( update_parties_for_votes(&new_country_definition); - for (BuildingType const& building_type : building_type_unlock_levels.get_keys()) { + for (BuildingType const& building_type : new_shared_country_values.building_types) { if (building_type.is_enabled_by_default) { - unlock_building_type(building_type); + unlock_building_type(building_type.index); } } - for (Crime const& crime : crime_unlock_levels.get_keys()) { + for (Crime const& crime : country_instance_deps.crimes) { if (crime.is_default_active) { - unlock_crime(crime); + unlock_crime(crime.index); } } - for (RegimentType const& regiment_type : country_instance_deps.regiment_types) { + for (RegimentType const& regiment_type : new_shared_country_values.regiment_types) { if (regiment_type.starts_unlocked) { unlock_unit_type(regiment_type.index); } @@ -536,26 +540,18 @@ void CountryInstance::change_script_variable(memory::string const& variable_name script_variables[variable_name] += value; } -fixed_point_t CountryInstance::get_taxable_income_by_strata(Strata const& strata) const { +fixed_point_t CountryInstance::get_taxable_income_by_strata(strata_index_t strata_index) const { fixed_point_t running_total = 0; - for (auto const& [pop_type, taxable_income] : taxable_income_by_pop_type) { - if (pop_type.strata == strata) { + pop_type_index_t pop_type_index {}; + for (const fixed_point_t taxable_income : taxable_income_by_pop_type) { + if (shared_country_values.pop_types[pop_type_index].strata.index == strata_index) { running_total += taxable_income; } + ++pop_type_index; } return running_total; } -DerivedState& CountryInstance::get_effective_tax_rate_by_strata(Strata const& strata) { - return effective_tax_rate_by_strata.at(strata); -} - -ReadOnlyClampedValue& CountryInstance::get_tax_rate_slider_value_by_strata(Strata const& strata) { - return tax_rate_slider_value_by_strata.at(strata); -} -ReadOnlyClampedValue const& CountryInstance::get_tax_rate_slider_value_by_strata(Strata const& strata) const { - return tax_rate_slider_value_by_strata.at(strata); -} bool CountryInstance::add_owned_province(ProvinceInstance& new_item) { OV_ERR_FAIL_COND_V_MSG( @@ -647,31 +643,33 @@ bool CountryInstance::set_ruling_party(CountryParty const& new_ruling_party) { } } -bool CountryInstance::add_reform(Reform const& new_reform) { +bool CountryInstance::add_reform(reform_index_t new_reform_index) { + Reform const& new_reform = shared_country_values.reforms[new_reform_index]; ReformGroup const& reform_group = new_reform.group; - Reform const*& reform = reforms.at(reform_group); + std::optional& active_reform = reforms[reform_group.index]; + + if (active_reform == new_reform_index) { + return true; + } - if (reform != &new_reform) { - if (reform_group.is_administrative) { - if (reform != nullptr) { - total_administrative_multiplier -= reform->administrative_multiplier; - } - total_administrative_multiplier += new_reform.administrative_multiplier; + if (reform_group.is_administrative) { + if (active_reform.has_value()) { + Reform const& old_reform = shared_country_values.reforms[active_reform.value()]; + total_administrative_multiplier -= old_reform.administrative_multiplier; } + total_administrative_multiplier += new_reform.administrative_multiplier; + } - reform = &new_reform; + active_reform = new_reform_index; - // TODO - if new_reform.get_reform_group().is_uncivilised() ? - // TODO - new_reform.get_on_execute_trigger() / new_reform.get_on_execute_effect() ? + // TODO - if new_reform.get_reform_group().is_uncivilised() ? + // TODO - new_reform.get_on_execute_trigger() / new_reform.get_on_execute_effect() ? - return update_rule_set(); - } else { - return true; - } + return update_rule_set(); } -void CountryInstance::set_strata_tax_rate_slider_value(Strata const& strata, const fixed_point_t new_value) { - tax_rate_slider_value_by_strata.at(strata).set_value(new_value); +void CountryInstance::set_strata_tax_rate_slider_value(strata_index_t strata, const fixed_point_t new_value) { + tax_rate_slider_value_by_strata[strata].set_value(new_value); } void CountryInstance::set_army_spending_slider_value(const fixed_point_t new_value) { @@ -887,16 +885,16 @@ bool CountryInstance::unlock_unit_type(const ship_type_index_t ship_type_index) } bool CountryInstance::modify_building_type_unlock( - BuildingType const& building_type, technology_unlock_level_t tech_unlock_level_change + building_type_index_t building_type_index, technology_unlock_level_t tech_unlock_level_change ) { - building_level_t& unlock_level = building_type_unlock_levels.at(building_type); + building_level_t& unlock_level = building_type_unlock_levels[building_type_index]; building_level_t unlock_level_change = building_level_t(type_safe::get(tech_unlock_level_change)); // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < building_level_t(0)) { spdlog::error_s( "Attempted to change unlock level for building type {} in country {} to invalid value: current level = {}, change = {}, invalid new value = {}", - building_type, *this, unlock_level, unlock_level_change, + building_type_index, *this, unlock_level, unlock_level_change, unlock_level + unlock_level_change ); return false; @@ -904,6 +902,7 @@ bool CountryInstance::modify_building_type_unlock( unlock_level += unlock_level_change; + BuildingType const& building_type = shared_country_values.building_types[building_type_index]; if (building_type.production_type != nullptr) { good_instance_manager.enable_good(building_type.production_type->output_good); } @@ -911,26 +910,22 @@ bool CountryInstance::modify_building_type_unlock( return true; } -bool CountryInstance::unlock_building_type(BuildingType const& building_type) { - return modify_building_type_unlock(building_type, technology_unlock_level_t { 1 }); -} - -building_level_t const& CountryInstance::get_building_type_unlock_levels(BuildingType const& building_type) const { - return building_type_unlock_levels.at(building_type); +bool CountryInstance::unlock_building_type(building_type_index_t building_type_index) { + return modify_building_type_unlock(building_type_index, technology_unlock_level_t { 1 }); } -bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const { - return building_type_unlock_levels.at(building_type) > building_level_t(0); +bool CountryInstance::is_building_type_unlocked(building_type_index_t building_type_index) const { + return building_type_unlock_levels[building_type_index] > building_level_t(0); } -bool CountryInstance::modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change) { - technology_unlock_level_t& unlock_level = crime_unlock_levels.at(crime); +bool CountryInstance::modify_crime_unlock(crime_index_t crime_index, technology_unlock_level_t unlock_level_change) { + technology_unlock_level_t& unlock_level = crime_unlock_levels[crime_index]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { spdlog::error_s( "Attempted to change unlock level for crime {} in country {} to invalid value: current level = {}, change = {}, invalid new value = {}", - crime, *this, unlock_level, + crime_index, *this, unlock_level, unlock_level_change, unlock_level + unlock_level_change ); return false; @@ -941,12 +936,12 @@ bool CountryInstance::modify_crime_unlock(Crime const& crime, technology_unlock_ return true; } -bool CountryInstance::unlock_crime(Crime const& crime) { - return modify_crime_unlock(crime, technology_unlock_level_t { 1 }); +bool CountryInstance::unlock_crime(crime_index_t crime_index) { + return modify_crime_unlock(crime_index, technology_unlock_level_t { 1 }); } -bool CountryInstance::is_crime_unlocked(Crime const& crime) const { - return is_unlocked(crime_unlock_levels.at(crime)); +bool CountryInstance::is_crime_unlocked(crime_index_t crime_index) const { + return is_unlocked(crime_unlock_levels[crime_index]); } bool CountryInstance::modify_gas_attack_unlock(technology_unlock_level_t unlock_level_change) { @@ -1039,9 +1034,10 @@ unit_variant_t CountryInstance::get_max_unlocked_unit_variant() const { } bool CountryInstance::modify_technology_unlock( - Technology const& technology, technology_unlock_level_t unlock_level_change + technology_index_t technology_index, technology_unlock_level_t unlock_level_change ) { - technology_unlock_level_t& unlock_level = technology_unlock_levels.at(technology); + technology_unlock_level_t& unlock_level = technology_unlock_levels[technology_index]; + Technology const& technology = shared_country_values.technologies[technology_index]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -1062,38 +1058,39 @@ bool CountryInstance::modify_technology_unlock( if (technology.get_unit_variant().has_value()) { ret &= modify_unit_variant_unlock(*technology.get_unit_variant(), unlock_level_change); } - for (RegimentType const* unit : technology.activated_regiment_types) { - ret &= modify_unit_type_unlock(unit->index, unlock_level_change); + for (RegimentType const* regiment_type : technology.activated_regiment_types) { + ret &= modify_unit_type_unlock(regiment_type->index, unlock_level_change); } - for (ShipType const* unit : technology.activated_ship_types) { - ret &= modify_unit_type_unlock(unit->index, unlock_level_change); + for (ShipType const* ship_type : technology.activated_ship_types) { + ret &= modify_unit_type_unlock(ship_type->index, unlock_level_change); } - for (BuildingType const* building : technology.activated_buildings) { - ret &= modify_building_type_unlock(*building, unlock_level_change); + for (BuildingType const* building_type : technology.activated_buildings) { + ret &= modify_building_type_unlock(building_type->index, unlock_level_change); } return ret; } bool CountryInstance::set_technology_unlock_level( - Technology const& technology, technology_unlock_level_t unlock_level + technology_index_t technology, technology_unlock_level_t unlock_level ) { - const technology_unlock_level_t unlock_level_change = unlock_level - technology_unlock_levels.at(technology); + const technology_unlock_level_t unlock_level_change = unlock_level - technology_unlock_levels[technology]; return unlock_level_change != 0 ? modify_technology_unlock(technology, unlock_level_change) : true; } -bool CountryInstance::unlock_technology(Technology const& technology) { +bool CountryInstance::unlock_technology(technology_index_t technology) { return modify_technology_unlock(technology, technology_unlock_level_t { 1 }); } -bool CountryInstance::is_technology_unlocked(Technology const& technology) const { - return is_unlocked(technology_unlock_levels.at(technology)); +bool CountryInstance::is_technology_unlocked(technology_index_t technology) const { + return is_unlocked(technology_unlock_levels[technology]); } bool CountryInstance::modify_invention_unlock( - Invention const& invention, technology_unlock_level_t unlock_level_change + invention_index_t invention_index, technology_unlock_level_t unlock_level_change ) { - technology_unlock_level_t& unlock_level = invention_unlock_levels.at(invention); + technology_unlock_level_t& unlock_level = invention_unlock_levels[invention_index]; + Invention const& invention = shared_country_values.inventions[invention_index]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -1119,17 +1116,17 @@ bool CountryInstance::modify_invention_unlock( // TODO - handle invention.is_news() - for (RegimentType const* unit : invention.activated_regiment_types) { - ret &= modify_unit_type_unlock(unit->index, unlock_level_change); + for (RegimentType const* regiment_type : invention.activated_regiment_types) { + ret &= modify_unit_type_unlock(regiment_type->index, unlock_level_change); } - for (ShipType const* unit : invention.activated_ship_types) { - ret &= modify_unit_type_unlock(unit->index, unlock_level_change); + for (ShipType const* ship_type : invention.activated_ship_types) { + ret &= modify_unit_type_unlock(ship_type->index, unlock_level_change); } - for (BuildingType const* building : invention.activated_buildings) { - ret &= modify_building_type_unlock(*building, unlock_level_change); + for (BuildingType const* building_type : invention.activated_buildings) { + ret &= modify_building_type_unlock(building_type->index, unlock_level_change); } for (Crime const* crime : invention.enabled_crimes) { - ret &= modify_crime_unlock(*crime, unlock_level_change); + ret &= modify_crime_unlock(crime->index, unlock_level_change); } if (invention.unlocks_gas_attack) { ret &= modify_gas_attack_unlock(unlock_level_change); @@ -1142,18 +1139,18 @@ bool CountryInstance::modify_invention_unlock( } bool CountryInstance::set_invention_unlock_level( - Invention const& invention, technology_unlock_level_t unlock_level + invention_index_t invention_index, technology_unlock_level_t unlock_level ) { - const technology_unlock_level_t unlock_level_change = unlock_level - invention_unlock_levels.at(invention); - return unlock_level_change != 0 ? modify_invention_unlock(invention, unlock_level_change) : true; + const technology_unlock_level_t unlock_level_change = unlock_level - invention_unlock_levels[invention_index]; + return unlock_level_change != 0 ? modify_invention_unlock(invention_index, unlock_level_change) : true; } -bool CountryInstance::unlock_invention(Invention const& invention) { - return modify_invention_unlock(invention, technology_unlock_level_t { 1 }); +bool CountryInstance::unlock_invention(invention_index_t invention_index) { + return modify_invention_unlock(invention_index, technology_unlock_level_t { 1 }); } -bool CountryInstance::is_invention_unlocked(Invention const& invention) const { - return is_unlocked(invention_unlock_levels.at(invention)); +bool CountryInstance::is_invention_unlocked(invention_index_t invention_index) const { + return is_unlocked(invention_unlock_levels[invention_index]); } bool CountryInstance::is_primary_culture(Culture const& culture) const { @@ -1168,31 +1165,38 @@ bool CountryInstance::is_primary_or_accepted_culture(Culture const& culture) con return is_primary_culture(culture) || is_accepted_culture(culture); } -fixed_point_t CountryInstance::calculate_research_cost(Technology const& technology) const { +fixed_point_t CountryInstance::calculate_research_cost(technology_index_t technology_index) const { + Technology const& technology = shared_country_values.technologies[technology_index]; // TODO - what if research bonus is -100%? Divide by 0 -> infinite cost? return technology.cost / (fixed_point_t::_1 + get_modifier_effect_value( *modifier_effect_cache.get_research_bonus_effects(technology.area.folder) )); } -bool CountryInstance::can_research_tech(Technology const& technology, const Date today) const { - Technology const* current_research_copy = current_research.get_untracked(); +bool CountryInstance::can_research_tech(technology_index_t technology_index, const Date today) const { + Technology const& technology = shared_country_values.technologies[technology_index]; + const std::optional current_research_copy = current_research.get_untracked(); if ( technology.year > today.get_year() || !is_civilised() - || is_technology_unlocked(technology) - || (current_research_copy && technology == *current_research_copy) + || is_technology_unlocked(technology_index) + || technology_index == current_research_copy ) { return false; } const Technology::area_index_t index_in_area = technology.index_in_area; + if (index_in_area == 0) { + return true; + } - return index_in_area == 0 || is_technology_unlocked(technology.area.get_technologies()[index_in_area - 1]); + Technology const& preceding_technology = technology.area.get_technologies()[index_in_area - 1]; + return is_technology_unlocked(preceding_technology.index); } -void CountryInstance::start_research(Technology const& technology, const Date today) { - if (OV_unlikely(!can_research_tech(technology, today))) { +void CountryInstance::start_research(technology_index_t technology_index, const Date today) { + Technology const& technology = shared_country_values.technologies[technology_index]; + if (OV_unlikely(!can_research_tech(technology_index, today))) { spdlog::warn_s( "Attempting to start research for country \"{}\" on technology \"{}\" - cannot research this tech!", *this, technology @@ -1200,7 +1204,7 @@ void CountryInstance::start_research(Technology const& technology, const Date to return; } - current_research.set(&technology); + current_research.set(technology_index); invested_research_points.set(0); _update_current_tech(today); @@ -1246,7 +1250,9 @@ bool CountryInstance::apply_history_to_country( ret &= set_ruling_party(**entry.get_ruling_party()); } set_optional(last_election, entry.get_last_election()); - upper_house_proportion_by_ideology.copy_values_from(entry.get_upper_house_proportion_by_ideology()); + for (auto const& [k,v] : entry.get_upper_house_proportion_by_ideology()) { + upper_house_proportion_by_ideology[k.index] = v; + } if (entry.get_capital()) { capital = &map_instance.get_province_instance_by_definition(**entry.get_capital()); } @@ -1258,15 +1264,15 @@ bool CountryInstance::apply_history_to_country( } set_optional_state(prestige, entry.get_prestige()); for (Reform const* reform : entry.get_reforms()) { - ret &= add_reform(*reform); + ret &= add_reform(reform->index); } set_optional_state(tech_school, entry.get_tech_school()); for (auto const& [technology, level] : entry.get_technologies()) { - ret &= set_technology_unlock_level(*technology, level); + ret &= set_technology_unlock_level(technology->index, level); } for (auto const& [invention, activated] : entry.get_inventions()) { - ret &= set_invention_unlock_level(*invention, technology_unlock_level_t { static_cast(activated ? 1 : 0) }); + ret &= set_invention_unlock_level(invention->index, technology_unlock_level_t { static_cast(activated ? 1 : 0) }); } apply_foreign_investments(entry.get_foreign_investment(), country_instance_manager); @@ -1277,7 +1283,9 @@ bool CountryInstance::apply_history_to_country( ret &= apply_flag_map(entry.get_country_flags(), true); ret &= global_flags.apply_flag_map(entry.get_global_flags(), true); - flag_overrides_by_government_type.copy_values_from(entry.get_flag_overrides_by_government_type()); + for (auto const& [k, v] : entry.get_flag_overrides_by_government_type()) { + flag_overrides_by_government_type[k.index] = v; + } for (Decision const* decision : entry.get_decisions()) { // TODO - take decision } @@ -1335,7 +1343,7 @@ void CountryInstance::_update_budget() { const fixed_point_t min_tax = get_modifier_effect_value(*modifier_effect_cache.get_min_tax()); const fixed_point_t max_tax = nonzero_or_one(get_modifier_effect_value(*modifier_effect_cache.get_max_tax())); - for (ClampedValue& tax_rate_slider_value : tax_rate_slider_value_by_strata.get_values()) { + for (ClampedValue& tax_rate_slider_value : tax_rate_slider_value_by_strata) { tax_rate_slider_value.set_bounds(min_tax, max_tax); } @@ -1363,9 +1371,7 @@ void CountryInstance::_update_budget() { + get_modifier_effect_value(*modifier_effect_cache.get_tax_eff()) / 100 ); - TypedSpan pop_types( - shared_country_values.get_shared_pop_type_values().get_keys() - ); + TypedSpan pop_types = shared_country_values.pop_types; /* In Victoria 2, administration efficiency is updated in the UI immediately. @@ -1436,20 +1442,19 @@ void CountryInstance::_update_budget() { { pop_type_index_t pop_type_index {}; for (const pop_sum_t pop_size : get_population_by_type()) { - PopType const& pop_type = pop_types[pop_type_index]; const int64_t size = type_safe::get(pop_size); projected_administration_spending_unscaled_by_slider_running_total += size - * administration_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value(); + * administration_salary_base_by_pop_type[pop_type_index].get_untracked().get_raw_value(); projected_education_spending_unscaled_by_slider_running_total += size - * education_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value(); + * education_salary_base_by_pop_type[pop_type_index].get_untracked().get_raw_value(); projected_military_spending_unscaled_by_slider_running_total += size - * military_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value(); + * military_salary_base_by_pop_type[pop_type_index].get_untracked().get_raw_value(); projected_pensions_spending_unscaled_by_slider_running_total += size - * calculate_pensions_base(pop_type).get_raw_value(); + * calculate_pensions_base(pop_type_index).get_raw_value(); projected_unemployment_subsidies_spending_unscaled_by_slider_running_total += type_safe::get( get_unemployed_pops_by_type()[pop_type_index] ) - * calculate_unemployment_subsidies_base(pop_type).get_raw_value(); + * calculate_unemployment_subsidies_base(pop_type_index).get_raw_value(); ++pop_type_index; } } @@ -1472,30 +1477,30 @@ void CountryInstance::_update_budget() { )); } -fixed_point_t CountryInstance::calculate_pensions_base(PopType const& pop_type) { +fixed_point_t CountryInstance::calculate_pensions_base(pop_type_index_t pop_type_index) { return get_modifier_effect_value(*modifier_effect_cache.get_pension_level()) - * social_income_variant_base_by_pop_type.at(pop_type).get_untracked(); + * social_income_variant_base_by_pop_type[pop_type_index].get_untracked(); } -fixed_point_t CountryInstance::calculate_unemployment_subsidies_base(PopType const& pop_type) { +fixed_point_t CountryInstance::calculate_unemployment_subsidies_base(pop_type_index_t pop_type_index) { return get_modifier_effect_value(*modifier_effect_cache.get_unemployment_benefit()) - * social_income_variant_base_by_pop_type.at(pop_type).get_untracked(); + * social_income_variant_base_by_pop_type[pop_type_index].get_untracked(); } -fixed_point_t CountryInstance::calculate_minimum_wage_base(PopType const& pop_type) { - if (pop_type.is_slave) { +fixed_point_t CountryInstance::calculate_minimum_wage_base(pop_type_index_t pop_type_index) { + if (shared_country_values.pop_types[pop_type_index].is_slave) { return 0; } return get_modifier_effect_value(*modifier_effect_cache.get_minimum_wage()) - * social_income_variant_base_by_pop_type.at(pop_type).get_untracked(); + * social_income_variant_base_by_pop_type[pop_type_index].get_untracked(); } void CountryInstance::_update_current_tech(const Date today) { - Technology const* current_research_copy = current_research.get_untracked(); - if (current_research_copy == nullptr) { + const std::optional current_research_copy = current_research.get_untracked(); + if (!current_research_copy.has_value()) { return; } current_research_cost.set( - calculate_research_cost(*current_research_copy) + calculate_research_cost(current_research_copy.value()) ); const fixed_point_t daily_research_points_copy = daily_research_points.get_untracked(); @@ -1549,9 +1554,7 @@ void CountryInstance::_update_population() { research_points_from_pop_types.clear(); leadership_points_from_pop_types.clear(); - TypedSpan pop_types( - shared_country_values.get_shared_pop_type_values().get_keys() - ); + TypedSpan pop_types = shared_country_values.pop_types; { pop_type_index_t pop_type_index {}; for (const pop_sum_t pop_size : get_population_by_type()) { @@ -1743,9 +1746,9 @@ bool CountryInstance::update_rule_set() { } } - for (Reform const* reform : reforms.get_values()) { - if (reform != nullptr) { - rule_set.add_ruleset(reform->rules); + for (std::optional reform : reforms) { + if (reform.has_value()) { + rule_set.add_ruleset(shared_country_values.reforms[reform.value()].rules); } } @@ -1796,11 +1799,11 @@ void CountryInstance::update_modifier_sum_before_map(Date today, StaticModifierC } } - for (Reform const* reform : reforms.get_values()) { + for (std::optional reform : reforms) { // The country's reforms here could be null as they're stored in an FixedVector which has // values for every ReformGroup regardless of whether or not they have a reform set. - if (reform != nullptr) { - modifier_sum.add_modifier(*reform); + if (reform.has_value()) { + modifier_sum.add_modifier(shared_country_values.reforms[reform.value()]); } } @@ -1809,14 +1812,14 @@ void CountryInstance::update_modifier_sum_before_map(Date today, StaticModifierC modifier_sum.add_modifier(*tech_school_copy); } - for (Technology const& technology : technology_unlock_levels.get_keys()) { - if (is_technology_unlocked(technology)) { + for (Technology const& technology : shared_country_values.technologies) { + if (is_technology_unlocked(technology.index)) { modifier_sum.add_modifier(technology); } } - for (Invention const& invention : invention_unlock_levels.get_keys()) { - if (is_invention_unlocked(invention)) { + for (Invention const& invention : shared_country_values.inventions) { + if (is_invention_unlocked(invention.index)) { modifier_sum.add_modifier(invention); } } @@ -1984,7 +1987,7 @@ void CountryInstance::after_buy(void* actor, BuyResult const& buy_result) { } CountryInstance& country = *static_cast(actor); - good_data_t& good_data = country.goods_data.at_index(buy_result.good_index); + good_data_t& good_data = country.goods_data[buy_result.good_index]; const fixed_point_t money_spent = buy_result.money_spent_total; country.cash_stockpile -= money_spent; country.actual_national_stockpile_spending += money_spent; @@ -2002,7 +2005,7 @@ void CountryInstance::after_sell(void* actor, SellResult const& sell_result, mem } CountryInstance& country = *static_cast(actor); - good_data_t& good_data = country.goods_data.at_index(sell_result.good_index); + good_data_t& good_data = country.goods_data[sell_result.good_index]; const fixed_point_t money_gained = sell_result.money_gained; country.cash_stockpile += money_gained; country.actual_national_stockpile_income += money_gained; @@ -2096,7 +2099,7 @@ void CountryInstance::country_tick_before_map( was_social_budget_cut_yesterday = actual_social_budget < projected_social_spending_copy; was_import_subsidies_budget_cut_yesterday = actual_import_subsidies_budget < projected_import_subsidies_copy; - for (auto [good_instance, good_data] : goods_data) { + for (good_data_t& good_data : goods_data) { good_data.clear_daily_recorded_data(); } @@ -2111,7 +2114,7 @@ void CountryInstance::country_tick_before_map( //TODO market maker orders - taxable_income_by_pop_type.fill(0); + std::fill(taxable_income_by_pop_type.begin(), taxable_income_by_pop_type.end(), 0); actual_administration_spending = actual_education_spending = actual_military_spending @@ -2160,8 +2163,8 @@ void CountryInstance::manage_national_stockpile( memory::vector& good_indices_to_buy = reusable_good_index_vector; fixed_point_t weights_sum = 0; - for (auto [good_instance, good_data] : goods_data) { - const good_index_t good_index = good_instance.index; + for (good_index_t good_index {}; good_index < goods_data.size(); ++good_index) { + good_data_t const& good_data = goods_data[good_index]; if (good_data.is_automated || !good_data.is_selling) { const fixed_point_t quantity_to_allocate_for = good_data.is_automated ? good_data.government_needs - good_data.stockpile_amount @@ -2274,8 +2277,8 @@ void CountryInstance::country_tick_after_map(const Date today) { // Gain daily research points research_point_stockpile += daily_research_points.get_untracked(); - Technology const* current_research_copy = current_research.get_untracked(); - if (current_research_copy != nullptr) { + const std::optional current_research_copy = current_research.get_untracked(); + if (current_research_copy.has_value()) { const fixed_point_t research_points_spent = std::min( std::min( research_point_stockpile.get_untracked(), @@ -2288,8 +2291,8 @@ void CountryInstance::country_tick_after_map(const Date today) { invested_research_points += research_points_spent; if (invested_research_points.get_untracked() >= current_research_cost.get_untracked()) { - unlock_technology(*current_research_copy); - current_research.set(nullptr); + unlock_technology(current_research_copy.value()); + current_research.set(std::nullopt); invested_research_points.set(0); current_research_cost.set(0); } @@ -2317,13 +2320,14 @@ void CountryInstance::country_tick_after_map(const Date today) { } fixed_point_t total_gold_production = 0; - for (auto const& [good_instance, data] : goods_data) { - GoodDefinition const& good_definition = good_instance.good_definition; + for (good_index_t good_index {}; good_index < goods_data.size(); ++good_index) { + good_data_t const& good_data = goods_data[good_index]; + GoodDefinition const& good_definition = good_instance_manager.get_good_instance_by_index(good_index)->good_definition; if (!good_definition.is_money) { continue; } - for (auto const& [production_type, produced_quantity] : data.production_per_production_type) { + for (auto const& [production_type, produced_quantity] : good_data.production_per_production_type) { if (production_type->template_type != ProductionType::template_type_t::RGO) { continue; } @@ -2396,9 +2400,9 @@ void CountryInstance::country_tick_after_map(const Date today) { balance_history.push_back(yesterdays_balance); } -CountryInstance::good_data_t::good_data_t() - : mutex { memory::make_unique() } - { } +CountryInstance::good_data_t::good_data_t(const pop_type_index_t pop_type_count) + : mutex { memory::make_unique() }, + need_consumption_per_pop_type(pop_type_count, fixed_point_t::_0) { } void CountryInstance::good_data_t::clear_daily_recorded_data() { const std::lock_guard lock_guard { *mutex }; @@ -2420,29 +2424,29 @@ void CountryInstance::good_data_t::clear_daily_recorded_data() { production_per_production_type.clear(); } -void CountryInstance::report_pop_income_tax(PopType const& pop_type, const fixed_point_t gross_income, const fixed_point_t paid_as_tax) { +void CountryInstance::report_pop_income_tax(pop_type_index_t pop_type_index, const fixed_point_t gross_income, const fixed_point_t paid_as_tax) { const std::lock_guard lock_guard { taxable_income_mutex }; - taxable_income_by_pop_type.at(pop_type) += gross_income; + taxable_income_by_pop_type[pop_type_index] += gross_income; cash_stockpile += paid_as_tax; } -void CountryInstance::report_pop_need_consumption(PopType const& pop_type, const good_index_t good_index, const fixed_point_t quantity) { - good_data_t& good_data = goods_data.at_index(good_index); +void CountryInstance::report_pop_need_consumption(pop_type_index_t pop_type_index, const good_index_t good_index, const fixed_point_t quantity) { + good_data_t& good_data = goods_data[good_index]; const std::lock_guard lock_guard { *good_data.mutex }; - good_data.need_consumption_per_pop_type[&pop_type] += quantity; + good_data.need_consumption_per_pop_type[pop_type_index] += quantity; } -void CountryInstance::report_pop_need_demand(PopType const& pop_type, const good_index_t good_index, const fixed_point_t quantity) { - good_data_t& good_data = goods_data.at_index(good_index); +void CountryInstance::report_pop_need_demand(pop_type_index_t pop_type_index, const good_index_t good_index, const fixed_point_t quantity) { + good_data_t& good_data = goods_data[good_index]; const std::lock_guard lock_guard { *good_data.mutex }; good_data.pop_demand += quantity; } void CountryInstance::report_input_consumption(ProductionType const& production_type, const good_index_t good_index, const fixed_point_t quantity) { - good_data_t& good_data = goods_data.at_index(good_index); + good_data_t& good_data = goods_data[good_index]; const std::lock_guard lock_guard { *good_data.mutex }; good_data.input_consumption_per_production_type[&production_type] += quantity; } void CountryInstance::report_input_demand(ProductionType const& production_type, const good_index_t good_index, const fixed_point_t quantity) { - good_data_t& good_data = goods_data.at_index(good_index); + good_data_t& good_data = goods_data[good_index]; if (production_type.template_type == ProductionType::template_type_t::ARTISAN) { switch (game_rules_manager.get_artisanal_input_demand_category()) { @@ -2460,7 +2464,7 @@ void CountryInstance::report_input_demand(ProductionType const& production_type, good_data.factory_demand += quantity; } void CountryInstance::report_output(ProductionType const& production_type, const fixed_point_t quantity) { - good_data_t& good_data = get_good_data(production_type.output_good); + good_data_t& good_data = goods_data[production_type.output_good.index]; const std::lock_guard lock_guard { *good_data.mutex }; good_data.production_per_production_type[&production_type] += quantity; } @@ -2468,11 +2472,11 @@ void CountryInstance::report_output(ProductionType const& production_type, const void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop) { PopType const& pop_type = pop.get_type(); const pop_size_t pop_size = pop.get_size(); - SharedPopTypeValues const& pop_type_values = shared_country_values.get_shared_pop_type_values(pop_type); + SharedPopTypeValues const& pop_type_values = shared_country_values.shared_pop_type_values[pop_type.index]; if (actual_administration_budget > 0) { const fixed_point_t administration_salary = fp::mul_div( - pop_size * administration_salary_base_by_pop_type.at(pop_type).get_untracked(), + pop_size * administration_salary_base_by_pop_type[pop_type.index].get_untracked(), actual_administration_budget, projected_administration_spending_unscaled_by_slider.get_untracked() ) / Pop::size_denominator; @@ -2484,7 +2488,7 @@ void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop if (actual_education_budget > 0) { const fixed_point_t education_salary = fp::mul_div( - pop_size * education_salary_base_by_pop_type.at(pop_type).get_untracked(), + pop_size * education_salary_base_by_pop_type[pop_type.index].get_untracked(), actual_education_budget, projected_education_spending_unscaled_by_slider.get_untracked() ) / Pop::size_denominator; @@ -2496,7 +2500,7 @@ void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop if (actual_military_budget > 0) { const fixed_point_t military_salary = fp::mul_div( - pop_size * military_salary_base_by_pop_type.at(pop_type).get_untracked(), + pop_size * military_salary_base_by_pop_type[pop_type.index].get_untracked(), actual_military_budget, projected_military_spending_unscaled_by_slider.get_untracked() ) / Pop::size_denominator; @@ -2508,7 +2512,7 @@ void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop if (actual_social_budget > 0) { const fixed_point_t pension_income = fp::mul_div( - pop_size * calculate_pensions_base(pop_type), + pop_size * calculate_pensions_base(pop_type.index), actual_social_budget, projected_social_spending_unscaled_by_slider.get_untracked() ) / Pop::size_denominator; @@ -2518,7 +2522,7 @@ void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop } const fixed_point_t unemployment_subsidies = fp::mul_div( - pop.get_unemployed() * calculate_unemployment_subsidies_base(pop_type), + pop.get_unemployed() * calculate_unemployment_subsidies_base(pop_type.index), actual_social_budget, projected_social_spending_unscaled_by_slider.get_untracked() ) / Pop::size_denominator; @@ -2551,17 +2555,4 @@ fixed_point_t CountryInstance::apply_tariff(const fixed_point_t money_spent_on_i return tariff; } -CountryInstance::good_data_t& CountryInstance::get_good_data(GoodInstance const& good_instance) { - return goods_data.at(good_instance); -} -CountryInstance::good_data_t const& CountryInstance::get_good_data(GoodInstance const& good_instance) const { - return goods_data.at(good_instance); -} -CountryInstance::good_data_t& CountryInstance::get_good_data(GoodDefinition const& good_definition) { - return goods_data.at_index(good_definition.index); -} -CountryInstance::good_data_t const& CountryInstance::get_good_data(GoodDefinition const& good_definition) const { - return goods_data.at_index(good_definition.index); -} - template struct fmt::formatter; diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index d7b16afef..1a8f32500 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -1,11 +1,13 @@ #pragma once #include +#include #include #include #include "openvic-simulation/core/memory/SmartPtr.hpp" +#include "openvic-simulation/core/memory/FixedVector.hpp" #include "openvic-simulation/core/memory/Vector.hpp" #include "openvic-simulation/core/stl/containers/TypedSpan.hpp" #include "openvic-simulation/core/thread/SpinMutex.hpp" @@ -35,6 +37,7 @@ #if defined(__APPLE__) #include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/population/PopType.hpp" #endif namespace OpenVic { @@ -164,7 +167,7 @@ namespace OpenVic { memory::vector, fixed_point_t>> SPAN_PROPERTY(industrial_power_from_investments); size_t PROPERTY(industrial_rank, 0); fixed_point_map_t> PROPERTY(foreign_investments); - OV_IFLATMAP_PROPERTY(BuildingType, building_level_t, building_type_unlock_levels); + memory::FixedVector SPAN_PROPERTY(building_type_unlock_levels); // TODO - total amount of each good produced /* Budget */ @@ -173,19 +176,17 @@ namespace OpenVic { OV_STATE_PROPERTY(fixed_point_t, gold_income); atomic_fixed_point_t PROPERTY(cash_stockpile); spin_mutex taxable_income_mutex; - OV_IFLATMAP_PROPERTY(PopType, fixed_point_t, taxable_income_by_pop_type); + memory::FixedVector SPAN_PROPERTY(taxable_income_by_pop_type); OV_STATE_PROPERTY(fixed_point_t, tax_efficiency); - IndexedFlatMap> PROPERTY(effective_tax_rate_by_strata); + memory::FixedVector, strata_index_t> SPAN_PROPERTY(effective_tax_rate_by_strata); + memory::FixedVector SPAN_PROPERTY(tax_rate_slider_value_by_strata); public: - DerivedState& get_effective_tax_rate_by_strata(Strata const& strata); - private: - IndexedFlatMap tax_rate_slider_value_by_strata; - public: - [[nodiscard]] constexpr IndexedFlatMap const& get_tax_rate_slider_value_by_strata() const { + [[nodiscard]] constexpr TypedSpan> get_effective_tax_rate_by_strata() { + return effective_tax_rate_by_strata; + } + [[nodiscard]] constexpr TypedSpan get_tax_rate_slider_value_by_strata() { return tax_rate_slider_value_by_strata; } - [[nodiscard]] ReadOnlyClampedValue& get_tax_rate_slider_value_by_strata(Strata const& strata); - [[nodiscard]] ReadOnlyClampedValue const& get_tax_rate_slider_value_by_strata(Strata const& strata) const; private: OV_STATE_PROPERTY(fixed_point_t, administrative_efficiency_from_administrators); @@ -226,10 +227,10 @@ namespace OpenVic { atomic_fixed_point_t PROPERTY(actual_unemployment_subsidies_spending); //base here means not scaled by slider or pop size - IndexedFlatMap> administration_salary_base_by_pop_type; - IndexedFlatMap> education_salary_base_by_pop_type; - IndexedFlatMap> military_salary_base_by_pop_type; - IndexedFlatMap> social_income_variant_base_by_pop_type; + memory::FixedVector, pop_type_index_t> administration_salary_base_by_pop_type; + memory::FixedVector, pop_type_index_t> education_salary_base_by_pop_type; + memory::FixedVector, pop_type_index_t> military_salary_base_by_pop_type; + memory::FixedVector, pop_type_index_t> social_income_variant_base_by_pop_type; OV_CLAMPED_PROPERTY(tariff_rate_slider_value); fixed_point_t actual_import_subsidies_budget; @@ -244,10 +245,10 @@ namespace OpenVic { //projected cost is UI only and lists the different factories /* Technology */ - OV_IFLATMAP_PROPERTY(Technology, technology_unlock_level_t, technology_unlock_levels); - OV_IFLATMAP_PROPERTY(Invention, technology_unlock_level_t, invention_unlock_levels); + memory::FixedVector SPAN_PROPERTY(technology_unlock_levels); + memory::FixedVector SPAN_PROPERTY(invention_unlock_levels); OV_STATE_PROPERTY(int32_t, inventions_count); - OV_STATE_PROPERTY(Technology const*, current_research, nullptr); + OV_STATE_PROPERTY(std::optional, current_research, std::nullopt); OV_STATE_PROPERTY(fixed_point_t, invested_research_points); OV_STATE_PROPERTY(fixed_point_t, current_research_cost); OV_STATE_PROPERTY(Date, expected_research_completion_date); @@ -262,17 +263,16 @@ namespace OpenVic { OV_STATE_PROPERTY(GovernmentType const*, government_type, nullptr); Date PROPERTY(last_election); OV_STATE_PROPERTY(CountryParty const*, ruling_party, nullptr); - OV_IFLATMAP_PROPERTY(Ideology, fixed_point_t, upper_house_proportion_by_ideology); - OV_IFLATMAP_PROPERTY(ReformGroup, Reform const*, reforms); + memory::FixedVector SPAN_PROPERTY(upper_house_proportion_by_ideology); + memory::FixedVector, reform_group_index_t> SPAN_PROPERTY(reforms); OV_STATE_PROPERTY(fixed_point_t, total_administrative_multiplier); RuleSet PROPERTY(rule_set); - // TODO - national issue support distribution (for just voters and for everyone) - OV_IFLATMAP_PROPERTY(GovernmentType, GovernmentType const*, flag_overrides_by_government_type); + memory::FixedVector SPAN_PROPERTY(flag_overrides_by_government_type); OV_STATE_PROPERTY(fixed_point_t, suppression_points); OV_STATE_PROPERTY(fixed_point_t, infamy); // in 0-25+ range OV_STATE_PROPERTY(fixed_point_t, plurality); // in 0-100 range OV_STATE_PROPERTY(fixed_point_t, revanchism); - OV_IFLATMAP_PROPERTY(Crime, technology_unlock_level_t, crime_unlock_levels); + memory::FixedVector SPAN_PROPERTY(crime_unlock_levels); // TODO - rebel movements /* Population */ @@ -303,7 +303,7 @@ namespace OpenVic { DerivedState projected_spending; DerivedState has_import_subsidies; - fixed_point_t get_taxable_income_by_strata(Strata const& strata) const; + fixed_point_t get_taxable_income_by_strata(strata_index_t strata) const; // TODO - national foci /* Trade */ @@ -329,11 +329,11 @@ namespace OpenVic { fixed_point_t pop_demand; fixed_point_t available_amount; - ordered_map need_consumption_per_pop_type; + memory::FixedVector need_consumption_per_pop_type; ordered_map input_consumption_per_production_type; ordered_map production_per_production_type; - good_data_t(); + good_data_t(const pop_type_index_t pop_type_count); good_data_t(good_data_t&&) = default; good_data_t& operator=(good_data_t&&) = default; @@ -342,8 +342,12 @@ namespace OpenVic { }; private: - OV_IFLATMAP_PROPERTY(GoodInstance, good_data_t, goods_data); - + memory::FixedVector SPAN_PROPERTY(goods_data); + public: + [[nodiscard]] constexpr TypedSpan get_goods_data() { + return goods_data; + } + private: /* Diplomacy */ OV_STATE_PROPERTY(fixed_point_t, prestige); size_t PROPERTY(prestige_rank, 0); @@ -533,9 +537,9 @@ namespace OpenVic { bool remove_accepted_culture(Culture const& culture_to_remove); bool set_ruling_party(CountryParty const& new_ruling_party); - bool add_reform(Reform const& new_reform); + bool add_reform(reform_index_t new_reform_index); - void set_strata_tax_rate_slider_value(Strata const& strata, const fixed_point_t new_value); + void set_strata_tax_rate_slider_value(strata_index_t strata, const fixed_point_t new_value); void set_army_spending_slider_value(const fixed_point_t new_value); void set_navy_spending_slider_value(const fixed_point_t new_value); void set_construction_spending_slider_value(const fixed_point_t new_value); @@ -568,15 +572,13 @@ namespace OpenVic { bool unlock_unit_type(const regiment_type_index_t regiment_type_index); bool unlock_unit_type(const ship_type_index_t ship_type_index); - bool modify_building_type_unlock( - BuildingType const& building_type, technology_unlock_level_t unlock_level_change - ); - bool unlock_building_type(BuildingType const& building_type); - [[nodiscard]] bool is_building_type_unlocked(BuildingType const& building_type) const; + bool modify_building_type_unlock(building_type_index_t building_type_index, technology_unlock_level_t unlock_level_change); + bool unlock_building_type(building_type_index_t building_type_index); + [[nodiscard]] bool is_building_type_unlocked(building_type_index_t building_type_index) const; - bool modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change); - bool unlock_crime(Crime const& crime); - [[nodiscard]] bool is_crime_unlocked(Crime const& crime) const; + bool modify_crime_unlock(crime_index_t crime_index, technology_unlock_level_t unlock_level_change); + bool unlock_crime(crime_index_t crime_index); + [[nodiscard]] bool is_crime_unlocked(crime_index_t crime_index) const; bool modify_gas_attack_unlock(technology_unlock_level_t unlock_level_change); bool unlock_gas_attack(); @@ -590,32 +592,24 @@ namespace OpenVic { bool unlock_unit_variant(unit_variant_t unit_variant); [[nodiscard]] unit_variant_t get_max_unlocked_unit_variant() const; - bool modify_technology_unlock( - Technology const& technology, technology_unlock_level_t unlock_level_change - ); - bool set_technology_unlock_level( - Technology const& technology, technology_unlock_level_t unlock_level - ); - bool unlock_technology(Technology const& technology); - [[nodiscard]] bool is_technology_unlocked(Technology const& technology) const; + bool modify_technology_unlock(technology_index_t technology, technology_unlock_level_t unlock_level_change); + bool set_technology_unlock_level(technology_index_t technology, technology_unlock_level_t unlock_level); + bool unlock_technology(technology_index_t technology); + [[nodiscard]] bool is_technology_unlocked(technology_index_t technology) const; - bool modify_invention_unlock( - Invention const& invention, technology_unlock_level_t unlock_level_change - ); - bool set_invention_unlock_level( - Invention const& invention, technology_unlock_level_t unlock_level - ); - bool unlock_invention(Invention const& invention); - [[nodiscard]] bool is_invention_unlocked(Invention const& invention) const; + bool modify_invention_unlock(invention_index_t invention, technology_unlock_level_t unlock_level_change); + bool set_invention_unlock_level(invention_index_t invention, technology_unlock_level_t unlock_level); + bool unlock_invention(invention_index_t invention); + [[nodiscard]] bool is_invention_unlocked(invention_index_t invention) const; [[nodiscard]] bool is_primary_culture(Culture const& culture) const; // This only checks the accepted cultures list, ignoring the primary culture. [[nodiscard]] bool is_accepted_culture(Culture const& culture) const; [[nodiscard]] bool is_primary_or_accepted_culture(Culture const& culture) const; - [[nodiscard]] fixed_point_t calculate_research_cost(Technology const& technology) const; - [[nodiscard]] bool can_research_tech(Technology const& technology, const Date today) const; - void start_research(Technology const& technology, const Date today); + [[nodiscard]] fixed_point_t calculate_research_cost(technology_index_t technology) const; + [[nodiscard]] bool can_research_tech(technology_index_t technology, const Date today) const; + void start_research(technology_index_t technology, const Date today); // Sets the investment of each country in the map (rather than adding to them), leaving the rest unchanged. void apply_foreign_investments( @@ -674,8 +668,8 @@ namespace OpenVic { void _update_budget(); //base here means not scaled by slider or pop size - fixed_point_t calculate_pensions_base(PopType const& pop_type); - fixed_point_t calculate_unemployment_subsidies_base(PopType const& pop_type); + fixed_point_t calculate_pensions_base(pop_type_index_t pop_type); + fixed_point_t calculate_unemployment_subsidies_base(pop_type_index_t pop_type); // Expects current_research to be non-null void _update_current_tech(const Date today); @@ -709,20 +703,15 @@ namespace OpenVic { ); void country_tick_after_map(const Date today); - good_data_t& get_good_data(GoodInstance const& good_instance); - good_data_t const& get_good_data(GoodInstance const& good_instance) const; - good_data_t& get_good_data(GoodDefinition const& good_definition); - good_data_t const& get_good_data(GoodDefinition const& good_definition) const; - //thread safe - void report_pop_income_tax(PopType const& pop_type, const fixed_point_t gross_income, const fixed_point_t paid_as_tax); - void report_pop_need_consumption(PopType const& pop_type, const good_index_t good_index, const fixed_point_t quantity); - void report_pop_need_demand(PopType const& pop_type, const good_index_t good_index, const fixed_point_t quantity); + void report_pop_income_tax(pop_type_index_t pop_type, const fixed_point_t gross_income, const fixed_point_t paid_as_tax); + void report_pop_need_consumption(pop_type_index_t pop_type, const good_index_t good_index, const fixed_point_t quantity); + void report_pop_need_demand(pop_type_index_t pop_type, const good_index_t good_index, const fixed_point_t quantity); void report_input_consumption(ProductionType const& production_type, const good_index_t good_index, const fixed_point_t quantity); void report_input_demand(ProductionType const& production_type, const good_index_t good_index, const fixed_point_t quantity); void report_output(ProductionType const& production_type, const fixed_point_t quantity); void request_salaries_and_welfare_and_import_subsidies(Pop& pop); - fixed_point_t calculate_minimum_wage_base(PopType const& pop_type); + fixed_point_t calculate_minimum_wage_base(pop_type_index_t pop_type); fixed_point_t apply_tariff(const fixed_point_t money_spent_on_imports); }; } diff --git a/src/openvic-simulation/country/CountryInstanceDeps.hpp b/src/openvic-simulation/country/CountryInstanceDeps.hpp index c663e087e..9445d7352 100644 --- a/src/openvic-simulation/country/CountryInstanceDeps.hpp +++ b/src/openvic-simulation/country/CountryInstanceDeps.hpp @@ -1,6 +1,5 @@ #pragma once -#include "openvic-simulation/core/portable/ForwardableSpan.hpp" #include "openvic-simulation/core/stl/containers/TypedSpan.hpp" #include "openvic-simulation/population/PopsAggregateDeps.hpp" #include "openvic-simulation/types/Date.hpp" @@ -30,33 +29,28 @@ namespace OpenVic { struct PopType; struct ReformGroup; struct Strata; - struct Technology; struct UnitTypeManager; struct CountryInstanceDeps { - forwardable_span building_types; CountryDefines const& country_defines; CountryRelationManager& country_relations_manager; - forwardable_span crimes; + TypedSpan crimes; Date fallback_date_for_never_completing_research; DiplomacyDefines const& diplomacy_defines; EconomyDefines const& economy_defines; - forwardable_span ideologies; - forwardable_span inventions; + TypedSpan ideologies; + TypedSpan inventions; GameRulesManager const& game_rules_manager; - forwardable_span good_instances; + TypedSpan good_instances; GoodInstanceManager& good_instance_manager; - forwardable_span government_types; + TypedSpan government_types; MarketInstance& market_instance; MilitaryDefines const& military_defines; ModifierEffectCache const& modifier_effect_cache; PopsAggregateDeps pops_aggregate_deps; - forwardable_span pop_types; - forwardable_span reform_groups; - TypedSpan regiment_types; + TypedSpan reform_groups; TypedSpan ship_types; - forwardable_span stratas; - forwardable_span technologies; + TypedSpan stratas; UnitTypeManager const& unit_type_manager; }; } \ No newline at end of file diff --git a/src/openvic-simulation/country/CountryInstanceManager.cpp b/src/openvic-simulation/country/CountryInstanceManager.cpp index a29a82494..8a02c488c 100644 --- a/src/openvic-simulation/country/CountryInstanceManager.cpp +++ b/src/openvic-simulation/country/CountryInstanceManager.cpp @@ -13,30 +13,18 @@ #include "openvic-simulation/population/Pop.hpp" #include "openvic-simulation/utility/ThreadPool.hpp" -#if defined(__APPLE__) -#include "openvic-simulation/military/UnitType.hpp" -#endif - using namespace OpenVic; CountryInstanceManager::CountryInstanceManager( CountryDefines const& new_country_defines, CountryDefinitionManager const& new_country_definition_manager, CountryInstanceDeps const& country_instance_deps, - GoodInstanceManager const& new_good_instance_manager, - PopsDefines const& new_pop_defines, - forwardable_span pop_type_keys, - TypedSpan regiment_types, + SharedCountryValuesDeps const& shared_country_deps, ThreadPool& new_thread_pool ) : thread_pool { new_thread_pool }, country_definition_manager { new_country_definition_manager }, country_defines { new_country_defines }, - shared_country_values { - new_pop_defines, - new_good_instance_manager, - pop_type_keys, - regiment_types - }, + shared_country_values { shared_country_deps }, country_instances { country_index_t(new_country_definition_manager.get_country_definition_count()), [ diff --git a/src/openvic-simulation/country/CountryInstanceManager.hpp b/src/openvic-simulation/country/CountryInstanceManager.hpp index 65154b881..bba1ea7bf 100644 --- a/src/openvic-simulation/country/CountryInstanceManager.hpp +++ b/src/openvic-simulation/country/CountryInstanceManager.hpp @@ -5,7 +5,6 @@ #include "openvic-simulation/core/memory/FixedVector.hpp" #include "openvic-simulation/core/memory/Vector.hpp" -#include "openvic-simulation/core/stl/containers/TypedSpan.hpp" #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/country/SharedCountryValues.hpp" #include "openvic-simulation/types/Date.hpp" @@ -17,10 +16,8 @@ namespace OpenVic { struct CountryDefinitionManager; struct CountryInstanceDeps; struct CountryHistoryManager; - struct GoodInstanceManager; struct InstanceManager; - struct PopsDefines; - struct PopType; + struct SharedCountryValuesDeps; struct ThreadPool; struct CountryInstanceManager { @@ -47,10 +44,7 @@ namespace OpenVic { CountryDefines const& new_country_defines, CountryDefinitionManager const& new_country_definition_manager, CountryInstanceDeps const& country_instance_deps, - GoodInstanceManager const& new_good_instance_manager, - PopsDefines const& new_pop_defines, - forwardable_span pop_type_keys, - TypedSpan regiment_types, + SharedCountryValuesDeps const& shared_country_deps, ThreadPool& new_thread_pool ); diff --git a/src/openvic-simulation/country/SharedCountryValues.cpp b/src/openvic-simulation/country/SharedCountryValues.cpp index bbdf59f29..0c75848b3 100644 --- a/src/openvic-simulation/country/SharedCountryValues.cpp +++ b/src/openvic-simulation/country/SharedCountryValues.cpp @@ -1,32 +1,38 @@ #include "SharedCountryValues.hpp" #include "openvic-simulation/defines/PopsDefines.hpp" +#include "openvic-simulation/economy/BuildingType.hpp" // IWYU pragma: keep for BuildingType size #include "openvic-simulation/economy/GoodInstance.hpp" #include "openvic-simulation/economy/GoodInstanceManager.hpp" #include "openvic-simulation/military/UnitType.hpp" // IWYU pragma: keep for RegimentType size +#include "openvic-simulation/politics/Reform.hpp" // IWYU pragma: keep for Reform size #include "openvic-simulation/population/PopNeedsMacro.hpp" #include "openvic-simulation/population/PopType.hpp" -#include "openvic-simulation/types/IndexedFlatMap.hpp" +#include "openvic-simulation/research/Invention.hpp" // IWYU pragma: keep for Invention size +#include "openvic-simulation/research/Technology.hpp" // IWYU pragma: keep for Technology size +#include "openvic-simulation/types/TypedIndices.hpp" using namespace OpenVic; -SharedCountryValues::SharedCountryValues( - PopsDefines const& new_pop_defines, - GoodInstanceManager const& new_good_instance_manager, - decltype(shared_pop_type_values)::keys_span_type pop_type_keys, - TypedSpan new_regiment_types -) : pop_defines { new_pop_defines }, - good_instance_manager { new_good_instance_manager }, - shared_pop_type_values { pop_type_keys }, - regiment_types { new_regiment_types } - {} - -SharedPopTypeValues& SharedCountryValues::get_shared_pop_type_values(PopType const& pop_type) { - return shared_pop_type_values.at(pop_type); -} +SharedCountryValues::SharedCountryValues(SharedCountryValuesDeps const& deps) + : _shared_pop_type_values { + deps.pop_types.size(), + [pop_types = deps.pop_types](pop_type_index_t pop_type_index)->PopType const& { + return pop_types[pop_type_index]; + } + }, + good_instance_manager { deps.good_instance_manager }, + pop_defines { deps.pop_defines }, + building_types { deps.building_types }, + inventions { deps.inventions }, + pop_types { deps.pop_types }, + reforms { deps.reforms }, + regiment_types { deps.regiment_types }, + technologies { deps.technologies }, + shared_pop_type_values { _shared_pop_type_values } {} void SharedCountryValues::update_costs() { - for (SharedPopTypeValues& value : shared_pop_type_values.get_values()) { + for (SharedPopTypeValues& value : shared_pop_type_values) { value.update_costs(pop_defines, good_instance_manager); } } diff --git a/src/openvic-simulation/country/SharedCountryValues.hpp b/src/openvic-simulation/country/SharedCountryValues.hpp index fdd3cb0cf..82ca368b5 100644 --- a/src/openvic-simulation/country/SharedCountryValues.hpp +++ b/src/openvic-simulation/country/SharedCountryValues.hpp @@ -1,22 +1,17 @@ #pragma once +#include "openvic-simulation/core/memory/FixedVector.hpp" #include "openvic-simulation/core/stl/containers/TypedSpan.hpp" +#include "openvic-simulation/country/SharedCountryValuesDeps.hpp" #include "openvic-simulation/population/PopNeedsMacro.hpp" -#include "openvic-simulation/types/IndexedFlatMap.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/types/TypedIndices.hpp" #include "openvic-simulation/types/UnitBranchType.hpp" #include "openvic-simulation/utility/reactive/MutableState.hpp" -#if defined(__APPLE__) -#include "openvic-simulation/military/UnitType.hpp" -#endif - namespace OpenVic { - struct CountryInstanceManager; struct GoodInstanceManager; struct PopsDefines; - struct PopType; struct SharedCountryValues; struct SharedPopTypeValues { @@ -41,26 +36,28 @@ namespace OpenVic { constexpr SharedPopTypeValues(PopType const& new_pop_type) : pop_type { new_pop_type } {}; }; + struct CountryInstanceManager; struct SharedCountryValues { friend CountryInstanceManager; private: - PopsDefines const& pop_defines; GoodInstanceManager const& good_instance_manager; - OV_IFLATMAP_PROPERTY(PopType, SharedPopTypeValues, shared_pop_type_values); + PopsDefines const& pop_defines; + memory::FixedVector _shared_pop_type_values; void update_costs(); public: + TypedSpan building_types; + TypedSpan inventions; + TypedSpan pop_types; + TypedSpan reforms; TypedSpan regiment_types; + TypedSpan technologies; - SharedPopTypeValues& get_shared_pop_type_values(PopType const& pop_type); + // mutable SharedPopTypeValues required + TypedSpan shared_pop_type_values; - SharedCountryValues( - PopsDefines const& new_pop_defines, - GoodInstanceManager const& new_good_instance_manager, - decltype(shared_pop_type_values)::keys_span_type pop_type_keys, - TypedSpan new_regiment_types - ); + SharedCountryValues(SharedCountryValuesDeps const& deps); SharedCountryValues(SharedCountryValues&&) = delete; SharedCountryValues(SharedCountryValues const&) = delete; SharedCountryValues& operator=(SharedCountryValues&&) = delete; diff --git a/src/openvic-simulation/country/SharedCountryValuesDeps.hpp b/src/openvic-simulation/country/SharedCountryValuesDeps.hpp new file mode 100644 index 000000000..83169c0d6 --- /dev/null +++ b/src/openvic-simulation/country/SharedCountryValuesDeps.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "openvic-simulation/core/stl/containers/TypedSpan.hpp" +#include "openvic-simulation/types/TypedIndices.hpp" +#include "openvic-simulation/types/UnitBranchType.hpp" + +#if defined(__APPLE__) +#include "openvic-simulation/economy/BuildingType.hpp" +#include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/politics/Reform.hpp" +#include "openvic-simulation/research/Invention.hpp" +#include "openvic-simulation/research/Technology.hpp" +#endif + +namespace OpenVic { + struct BuildingType; + struct GoodInstanceManager; + struct Invention; + struct PopsDefines; + struct PopType; + struct Reform; + struct Technology; + + struct SharedCountryValuesDeps { + GoodInstanceManager const& good_instance_manager; + PopsDefines const& pop_defines; + TypedSpan building_types; + TypedSpan inventions; + TypedSpan pop_types; + TypedSpan reforms; + TypedSpan regiment_types; + TypedSpan technologies; + }; +} \ No newline at end of file diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp index f3cc4ccc0..2249600aa 100644 --- a/src/openvic-simulation/economy/BuildingType.cpp +++ b/src/openvic-simulation/economy/BuildingType.cpp @@ -99,7 +99,7 @@ bool BuildingType::can_be_built_in( } } - building_level_t const& unlocked_max_level = actor.get_building_type_unlock_levels(*this); + building_level_t const& unlocked_max_level = actor.get_building_type_unlock_levels()[index]; ModifierEffectCache::building_type_effects_t const& effects = modifier_effect_cache.get_building_type_effects(*this); const fixed_point_t min_level_modifier = location.get_modifier_effect_value(*effects.get_min_level()); return fixed_point_t { type_safe::get(unlocked_max_level) } diff --git a/src/openvic-simulation/economy/production/Employee.cpp b/src/openvic-simulation/economy/production/Employee.cpp index 5568563ad..7be214df4 100644 --- a/src/openvic-simulation/economy/production/Employee.cpp +++ b/src/openvic-simulation/economy/production/Employee.cpp @@ -2,6 +2,7 @@ #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/population/Pop.hpp" +#include "openvic-simulation/population/PopType.hpp" // IWYU pragma: keep for .index using namespace OpenVic; @@ -11,6 +12,6 @@ Employee::Employee(Pop& new_pop, const pop_size_t new_size) {} fixed_point_t Employee::update_minimum_wage(CountryInstance& country_to_report_economy) { - const fixed_point_t minimum_wage_base = country_to_report_economy.calculate_minimum_wage_base(pop.get_type()); + const fixed_point_t minimum_wage_base = country_to_report_economy.calculate_minimum_wage_base(pop.get_type().index); return minimum_wage_cached = minimum_wage_base * size / Pop::size_denominator; } \ No newline at end of file diff --git a/src/openvic-simulation/misc/GameAction.cpp b/src/openvic-simulation/misc/GameAction.cpp index 8a468b140..bb10fdef3 100644 --- a/src/openvic-simulation/misc/GameAction.cpp +++ b/src/openvic-simulation/misc/GameAction.cpp @@ -1,12 +1,42 @@ #include "GameAction.hpp" +#include + #include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/DefinitionManager.hpp" #include "openvic-simulation/InstanceManager.hpp" #include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/types/TypedIndices.hpp" using namespace OpenVic; +#define VALIDATE_INDEX(index_t, count) \ + bool validate(InstanceManager const& instance_manager, index_t index, std::string_view action_name) { \ + if (OV_unlikely(index < index_t{} || index >= index_t(count))) { \ + spdlog::error_s("{} called with invalid {}: {}", action_name, OpenVic::type_name(), index); \ + return false; \ + } \ + return true; \ + } + +VALIDATE_INDEX(country_index_t, instance_manager.get_country_instance_manager().get_country_instances().size()) +VALIDATE_INDEX(good_index_t, instance_manager.get_good_instance_manager().get_good_instances().size()) +VALIDATE_INDEX(province_index_t, instance_manager.get_map_instance().get_province_instances().size()) +VALIDATE_INDEX(regiment_type_index_t, instance_manager.definition_manager.get_military_manager().get_unit_type_manager().get_regiment_type_count()) +VALIDATE_INDEX(strata_index_t, instance_manager.definition_manager.get_pop_manager().get_strata_count()) +VALIDATE_INDEX(technology_index_t, instance_manager.definition_manager.get_research_manager().get_technology_manager().get_technology_count()) + +#undef VALIDATE_INDEX + +#define VALIDATE_OR_FAIL(x) \ + if (OV_unlikely(!validate(instance_manager, x, OpenVic::type_name()))) { \ + return false; \ + } + +#define GET_COUNTRY_INSTANCE_OR_FAIL(country_index) \ + VALIDATE_OR_FAIL(country_index) \ + CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + bool GameActionManager::VariantVisitor::operator() (none_argument_t const& argument) const { return false; } @@ -31,7 +61,7 @@ bool GameActionManager::VariantVisitor::operator() (set_speed_argument_t const& bool GameActionManager::VariantVisitor::operator() (set_ai_argument_t const& argument) const { const auto [country_index, new_is_ai] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); const bool old_ai = country.is_ai(); country.set_ai(new_is_ai); @@ -41,16 +71,11 @@ bool GameActionManager::VariantVisitor::operator() (set_ai_argument_t const& arg // Production bool GameActionManager::VariantVisitor::operator() (expand_province_building_argument_t const& argument) const { const auto [country_index, province_index, province_building_index] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); + VALIDATE_OR_FAIL(province_index); - ProvinceInstance* province = instance_manager.get_map_instance().get_province_instance_by_index(province_index); - - if (OV_unlikely(province == nullptr)) { - spdlog::error_s("GAME_ACTION_EXPAND_PROVINCE_BUILDING called with invalid province index: {}", province_index); - return false; - } - - return province->expand_building( + ProvinceInstance& province = *instance_manager.get_map_instance().get_province_instance_by_index(province_index); + return province.expand_building( instance_manager.definition_manager.get_modifier_manager().get_modifier_effect_cache(), province_building_index, country @@ -60,22 +85,16 @@ bool GameActionManager::VariantVisitor::operator() (expand_province_building_arg // Budget bool GameActionManager::VariantVisitor::operator() (set_strata_tax_argument_t const& argument) const { const auto [country_index, strata_index, tax_rate] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); - - Strata const* strata = instance_manager.definition_manager.get_pop_manager().get_strata_by_index(strata_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); + VALIDATE_OR_FAIL(strata_index); - if (OV_unlikely(strata == nullptr)) { - spdlog::error_s("GAME_ACTION_SET_STRATA_TAX called with invalid strata index: {}", strata_index); - return false; - } - - country.set_strata_tax_rate_slider_value(*strata, tax_rate); + country.set_strata_tax_rate_slider_value(strata_index, tax_rate); return false; } bool GameActionManager::VariantVisitor::operator() (set_army_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_army_spending_slider_value(spending); return false; @@ -83,7 +102,7 @@ bool GameActionManager::VariantVisitor::operator() (set_army_spending_argument_t bool GameActionManager::VariantVisitor::operator() (set_navy_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_navy_spending_slider_value(spending); return false; @@ -91,7 +110,7 @@ bool GameActionManager::VariantVisitor::operator() (set_navy_spending_argument_t bool GameActionManager::VariantVisitor::operator() (set_construction_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_construction_spending_slider_value(spending); return false; @@ -99,7 +118,7 @@ bool GameActionManager::VariantVisitor::operator() (set_construction_spending_ar bool GameActionManager::VariantVisitor::operator() (set_education_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_education_spending_slider_value(spending); return false; @@ -107,7 +126,7 @@ bool GameActionManager::VariantVisitor::operator() (set_education_spending_argum bool GameActionManager::VariantVisitor::operator() (set_administration_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_administration_spending_slider_value(spending); return false; @@ -115,7 +134,7 @@ bool GameActionManager::VariantVisitor::operator() (set_administration_spending_ bool GameActionManager::VariantVisitor::operator() (set_social_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_social_spending_slider_value(spending); return false; @@ -123,7 +142,7 @@ bool GameActionManager::VariantVisitor::operator() (set_social_spending_argument bool GameActionManager::VariantVisitor::operator() (set_military_spending_argument_t const& argument) const { const auto [country_index, spending] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_military_spending_slider_value(spending); return false; @@ -131,7 +150,7 @@ bool GameActionManager::VariantVisitor::operator() (set_military_spending_argume bool GameActionManager::VariantVisitor::operator() (set_tariff_rate_argument_t const& argument) const { const auto [country_index, tariff_rate] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); country.set_tariff_rate_slider_value(tariff_rate); return false; @@ -140,22 +159,11 @@ bool GameActionManager::VariantVisitor::operator() (set_tariff_rate_argument_t c // Technology bool GameActionManager::VariantVisitor::operator() (start_research_argument_t const& argument) const { const auto [country_index, technology_index] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); - - Technology const* technology = instance_manager.definition_manager - .get_research_manager() - .get_technology_manager() - .get_technology_by_index(technology_index); - - if (OV_unlikely(technology == nullptr)) { - spdlog::error_s("GAME_ACTION_START_RESEARCH called with invalid technology index: {}", technology_index); - return false; - } - - Technology const* old_research = country.get_current_research_untracked(); - - country.start_research(*technology, instance_manager.get_today()); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); + VALIDATE_OR_FAIL(technology_index); + std::optional old_research = country.get_current_research_untracked(); + country.start_research(technology_index, instance_manager.get_today()); return old_research != country.get_current_research_untracked(); } @@ -166,41 +174,26 @@ bool GameActionManager::VariantVisitor::operator() (start_research_argument_t co // Trade bool GameActionManager::VariantVisitor::operator() (set_good_automated_argument_t const& argument) const { const auto [country_index, good_index, new_is_automated] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); - - GoodInstance const* good = instance_manager.get_good_instance_manager().get_good_instance_by_index(good_index); - - if (OV_unlikely(good == nullptr)) { - spdlog::error_s("GAME_ACTION_SET_GOOD_AUTOMATED called with invalid good index: {}", good_index); - return false; - } - - CountryInstance::good_data_t& good_data = country.get_good_data(*good); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); + VALIDATE_OR_FAIL(good_index); + CountryInstance::good_data_t& good_data = country.get_goods_data()[good_index]; const bool old_automated = good_data.is_automated; - good_data.is_automated = new_is_automated; - return old_automated != good_data.is_automated; } bool GameActionManager::VariantVisitor::operator() (set_good_trade_order_argument_t const& argument) const { const auto [country_index, good_index, new_is_selling, new_cutoff] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); + VALIDATE_OR_FAIL(good_index); - GoodInstance const* good = instance_manager.get_good_instance_manager().get_good_instance_by_index(good_index); - - if (OV_unlikely(good == nullptr)) { - spdlog::error_s("GAME_ACTION_SET_GOOD_TRADE_ORDER called with invalid good index: {}", good_index); - return false; - } - - CountryInstance::good_data_t& good_data = country.get_good_data(*good); + CountryInstance::good_data_t& good_data = country.get_goods_data()[good_index]; if (OV_unlikely(good_data.is_automated)) { spdlog::error_s( "GAME_ACTION_SET_GOOD_TRADE_ORDER called for automated good! Country: {}, good: {}", - country, *good + country, good_index ); return false; } @@ -215,7 +208,7 @@ bool GameActionManager::VariantVisitor::operator() (set_good_trade_order_argumen spdlog::error_s( "GAME_ACTION_SET_GOOD_TRADE_ORDER called with negative stockpile cutoff {} for {} good \"{}\" in country \"{}\". Setting to 0.", good_data.stockpile_cutoff, - *good, + good_index, good_data.is_selling ? "selling" : "buying", country ); @@ -230,7 +223,7 @@ bool GameActionManager::VariantVisitor::operator() (set_good_trade_order_argumen // Military bool GameActionManager::VariantVisitor::operator() (create_leader_argument_t const& argument) const { const auto [country_index, unit_branch] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); if (country.get_create_leader_count() < 1) { spdlog::error_s( @@ -266,7 +259,7 @@ bool GameActionManager::VariantVisitor::operator() (set_use_leader_argument_t co bool GameActionManager::VariantVisitor::operator() (set_auto_create_leaders_argument_t const& argument) const { const auto [country_index, new_should_auto_create] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); const bool old_auto_create = country.get_auto_create_leaders(); country.set_auto_create_leaders(new_should_auto_create); @@ -275,7 +268,7 @@ bool GameActionManager::VariantVisitor::operator() (set_auto_create_leaders_argu bool GameActionManager::VariantVisitor::operator() (set_auto_assign_leaders_argument_t const& argument) const { const auto [country_index, new_should_auto_assign] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); const bool old_auto_assign = country.get_auto_assign_leaders(); country.set_auto_assign_leaders(new_should_auto_assign); @@ -284,7 +277,7 @@ bool GameActionManager::VariantVisitor::operator() (set_auto_assign_leaders_argu bool GameActionManager::VariantVisitor::operator() (set_mobilise_argument_t const& argument) const { const auto [country_index, new_is_mobilised] = argument; - CountryInstance& country = instance_manager.get_country_instance_manager().get_country_instance_by_index(country_index); + GET_COUNTRY_INSTANCE_OR_FAIL(country_index); const bool old_mobilise = country.is_mobilised(); country.set_mobilised(new_is_mobilised); @@ -293,27 +286,14 @@ bool GameActionManager::VariantVisitor::operator() (set_mobilise_argument_t cons bool GameActionManager::VariantVisitor::operator() (start_land_unit_recruitment_argument_t const& argument) const { const auto [regiment_type_index, province_index, pop_id_in_province] = argument; - auto const& unit_type_manager = instance_manager.definition_manager - .get_military_manager() - .get_unit_type_manager(); - if (OV_unlikely(regiment_type_index < regiment_type_index_t{} - || regiment_type_index >= regiment_type_index_t(unit_type_manager.get_regiment_type_count())) - ) { - spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid regiment type index: {}", regiment_type_index); - return false; - } - - RegimentType const& regiment_type = *unit_type_manager.get_regiment_type_by_index(regiment_type_index); + VALIDATE_OR_FAIL(regiment_type_index); + VALIDATE_OR_FAIL(province_index); - ProvinceInstance* province = instance_manager + ProvinceInstance& province = *instance_manager .get_map_instance() .get_province_instance_by_index(province_index); - if (OV_unlikely(province == nullptr)) { - spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid province index: {}", province_index); - return false; - } - Pop* pop = province->find_pop_by_id(pop_id_in_province); + Pop* pop = province.find_pop_by_id(pop_id_in_province); if (OV_unlikely(pop == nullptr)) { spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid pop_id_in_province: {}", pop_id_in_province); return false; @@ -325,3 +305,6 @@ bool GameActionManager::VariantVisitor::operator() (start_land_unit_recruitment_ //TODO actually instantiate a regiment in recruitment state return false; } + +#undef VALIDATE_OR_FAIL +#undef GET_COUNTRY_INSTANCE_OR_FAIL \ No newline at end of file diff --git a/src/openvic-simulation/population/Pop.cpp b/src/openvic-simulation/population/Pop.cpp index 3f11de5be..91eace36d 100644 --- a/src/openvic-simulation/population/Pop.cpp +++ b/src/openvic-simulation/population/Pop.cpp @@ -318,9 +318,9 @@ void Pop::pay_income_tax(fixed_point_t& income) { if (tax_collector_nullable == nullptr) { return; } - const fixed_point_t effective_tax_rate = tax_collector_nullable->get_effective_tax_rate_by_strata(get_type().strata).get_untracked(); + const fixed_point_t effective_tax_rate = tax_collector_nullable->get_effective_tax_rate_by_strata()[get_type().strata.index].get_untracked(); const fixed_point_t tax = effective_tax_rate * income; - tax_collector_nullable->report_pop_income_tax(type, income, tax); + tax_collector_nullable->report_pop_income_tax(type.get().index, income, tax); income -= tax; } @@ -569,6 +569,7 @@ void Pop::pop_tick_without_cleanup( yesterdays_import_value = 0; PopType const& pop_type = type; + pop_type_index_t pop_type_index = pop_type.index; PopStrataValuesFromProvince const& shared_strata_values = shared_values.get_effects_by_strata()[pop_type.strata.index]; PopsDefines const& defines = shared_values.defines; const fixed_point_t base_needs_scalar = ( @@ -590,7 +591,7 @@ void Pop::pop_tick_without_cleanup( continue; \ } \ if (country_to_report_economy_nullable != nullptr) { \ - country_to_report_economy_nullable->report_pop_need_demand(pop_type, good_index, max_quantity_to_buy); \ + country_to_report_economy_nullable->report_pop_need_demand(pop_type_index, good_index, max_quantity_to_buy); \ } \ need_category##_needs_desired_quantity += max_quantity_to_buy; \ auto goods_to_sell_iterator = goods_to_sell.find(good_index); \ @@ -600,7 +601,7 @@ void Pop::pop_tick_without_cleanup( max_quantity_to_buy -= own_produce_consumed; \ need_category##_needs_acquired_quantity += own_produce_consumed; \ if (country_to_report_economy_nullable != nullptr) { \ - country_to_report_economy_nullable->report_pop_need_consumption(pop_type, good_index, own_produce_consumed); \ + country_to_report_economy_nullable->report_pop_need_consumption(pop_type_index, good_index, own_produce_consumed); \ } \ } \ if (OV_likely(max_quantity_to_buy > 0)) { \ @@ -734,7 +735,7 @@ void Pop::after_buy(void* actor, BuyResult const& buy_result) { pop.need_category##_needs_acquired_quantity += consumed_quantity; \ quantity_left_to_consume -= consumed_quantity; \ if (get_country_to_report_economy_nullable != nullptr) { \ - get_country_to_report_economy_nullable->report_pop_need_consumption(pop.type, good_index, consumed_quantity); \ + get_country_to_report_economy_nullable->report_pop_need_consumption(pop.type.get().index, good_index, consumed_quantity); \ } \ const fixed_point_t expense = fp::mul_div( \ money_spent, \