diff --git a/extension/doc_classes/MenuSingleton.xml b/extension/doc_classes/MenuSingleton.xml index 99421d83..f78edf06 100644 --- a/extension/doc_classes/MenuSingleton.xml +++ b/extension/doc_classes/MenuSingleton.xml @@ -255,6 +255,11 @@ + + + + + diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp index f01e1307..db10d46b 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp @@ -215,10 +215,19 @@ Error GFXMaskedFlagTexture::set_flag_country_name_and_type( Error GFXMaskedFlagTexture::set_flag_country(CountryInstance* new_flag_country) { if (new_flag_country == nullptr) { + flag_government_type_connection = {}; return set_flag_country_and_type(nullptr, {}); } - GovernmentType const* government_type = new_flag_country->flag_government_type.get_untracked(); + GovernmentType const* const government_type = new_flag_country->flag_government_type.get( + [this,new_flag_country](signal<>& changed) mutable -> void { + flag_government_type_connection = changed.connect_scoped( + [this,new_flag_country]() -> void { + set_flag_country(new_flag_country); + } + ); + } + ); const StringName new_flag_type = government_type != nullptr ? StringName { Utilities::std_to_godot_string(government_type->get_flag_type()) } @@ -232,13 +241,13 @@ Error GFXMaskedFlagTexture::set_flag_country_name(String const& new_flag_country return set_flag_country(nullptr); } - GameSingleton* game_singleton = GameSingleton::get_singleton(); + GameSingleton* const game_singleton = GameSingleton::get_singleton(); ERR_FAIL_NULL_V(game_singleton, FAILED); - InstanceManager* instance_manager = game_singleton->get_instance_manager(); + InstanceManager* const instance_manager = game_singleton->get_instance_manager(); ERR_FAIL_NULL_V(instance_manager, FAILED); - CountryInstance* new_flag_country = instance_manager->get_country_instance_manager() + CountryInstance* const new_flag_country = instance_manager->get_country_instance_manager() .get_country_instance_by_identifier( Utilities::godot_to_std_string(new_flag_country_name) ); diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp index 97489316..002f79b4 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "openvic-extension/classes/GFXButtonStateTexture.hpp" @@ -9,8 +10,11 @@ namespace OpenVic { struct CountryInstance; class GFXMaskedFlagTexture : public GFXButtonStateHavingTexture { + private: GDCLASS(GFXMaskedFlagTexture, GFXButtonStateHavingTexture) + scoped_connection flag_government_type_connection; + GFX::MaskedFlag const* PROPERTY(gfx_masked_flag, nullptr); CountryDefinition const* PROPERTY(flag_country, nullptr); godot::StringName PROPERTY(flag_type); diff --git a/extension/src/openvic-extension/classes/GUILabel.cpp b/extension/src/openvic-extension/classes/GUILabel.cpp index f1d33545..5bfdf971 100644 --- a/extension/src/openvic-extension/classes/GUILabel.cpp +++ b/extension/src/openvic-extension/classes/GUILabel.cpp @@ -18,6 +18,10 @@ using namespace OpenVic; using namespace godot; using namespace OpenVic::Utilities::literals; +GUILabel::~GUILabel() { + disconnect_all(); +} + GUILabel::string_segment_t::string_segment_t(String&& new_text, Color const& new_colour, real_t new_width) : text { std::move(new_text) }, colour { new_colour }, width { new_width } {} @@ -594,7 +598,7 @@ std::pair GUILabel::generate_display_te std::vector GUILabel::generate_lines_and_segments( String const& display_text, colour_instructions_t const& colour_instructions -) const { +) { static constexpr char RESET_COLOUR_CODE = '!'; std::vector unwrapped_lines; @@ -641,7 +645,7 @@ std::vector GUILabel::generate_lines_and_segments( void GUILabel::separate_lines( String const& string, Color const& colour, std::vector& unwrapped_lines -) const { +) { static const String NEWLINE_MARKER = "\n"; int64_t start_pos = 0; @@ -664,7 +668,7 @@ void GUILabel::separate_lines( void GUILabel::separate_currency_segments( String const& string, Color const& colour, line_t& line -) const { +) { int64_t start_pos = 0; int64_t marker_pos; @@ -694,28 +698,30 @@ GUILabel::flag_segment_t GUILabel::make_flag_segment(String const& identifier) { InstanceManager* instance_manager = game_singleton.get_instance_manager(); - if (instance_manager != nullptr) { - CountryInstance* country_instance = - instance_manager->get_country_instance_manager().get_country_instance_by_identifier( + if (instance_manager == nullptr) { + CountryDefinition const* country_definition = + game_singleton.get_definition_manager().get_country_definition_manager().get_country_definition_by_identifier( Utilities::godot_to_std_string(identifier) ); - if (country_instance != nullptr) { - country_index = country_instance->get_country_definition().get_index(); - - GovernmentType const* government_type = country_instance->flag_government_type.get_untracked(); - if (government_type != nullptr) { - flag_type = Utilities::std_to_godot_string(government_type->get_flag_type()); - } + if (country_definition != nullptr) { + country_index = country_definition->get_index(); } } else { - CountryDefinition const* country_definition = - game_singleton.get_definition_manager().get_country_definition_manager().get_country_definition_by_identifier( + CountryInstance* const country_instance = instance_manager->get_country_instance_manager() + .get_country_instance_by_identifier( Utilities::godot_to_std_string(identifier) ); - if (country_definition != nullptr) { - country_index = country_definition->get_index(); + if (country_instance != nullptr) { + country_index = country_instance->get_country_definition().get_index(); + DerivedState& flag_government_type_state = country_instance->flag_government_type; + GovernmentType const* const flag_government_type = flag_government_type_state.get([this](signal<>& changed) mutable -> void { + changed.connect(&GUILabel::on_flag_government_type_changed, this); + }); + if (flag_government_type != nullptr) { + flag_type = Utilities::std_to_godot_string(flag_government_type->get_flag_type()); + } } } @@ -740,9 +746,14 @@ GUILabel::flag_segment_t GUILabel::make_flag_segment(String const& identifier) { return flag_segment; } +void GUILabel::on_flag_government_type_changed() { + disconnect_all(); + _queue_line_update(); +} + void GUILabel::separate_flag_segments( String const& string, Color const& colour, line_t& line -) const { +) { const auto push_string_segment = [this, &string, &colour, &line](int64_t start, int64_t end) -> void { String substring = string.substr(start, end - start); const real_t width = get_string_width(substring); diff --git a/extension/src/openvic-extension/classes/GUILabel.hpp b/extension/src/openvic-extension/classes/GUILabel.hpp index 0cf62629..0389e740 100644 --- a/extension/src/openvic-extension/classes/GUILabel.hpp +++ b/extension/src/openvic-extension/classes/GUILabel.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "openvic-extension/classes/GFXSpriteTexture.hpp" #include "openvic-extension/classes/GUIHasTooltip.hpp" @@ -17,7 +18,9 @@ namespace godot { } namespace OpenVic { - class GUILabel : public godot::Control { + struct GovernmentType; + + class GUILabel : public godot::Control, public observer { GDCLASS(GUILabel, godot::Control) GUI_TOOLTIP_DEFINITIONS @@ -81,6 +84,7 @@ namespace OpenVic { ); GUILabel(); + ~GUILabel() override; /* Reset gui_text to nullptr and reset current text. */ void clear(); @@ -124,6 +128,7 @@ namespace OpenVic { void _queue_line_update(); void _update_lines(); + void on_flag_government_type_changed(); godot::String generate_substituted_text(godot::String const& base_text) const; std::pair generate_display_text_and_colour_instructions( @@ -131,17 +136,17 @@ namespace OpenVic { ) const; std::vector generate_lines_and_segments( godot::String const& display_text, colour_instructions_t const& colour_instructions - ) const; + ); void separate_lines( godot::String const& string, godot::Color const& colour, std::vector& lines - ) const; + ); void separate_currency_segments( godot::String const& string, godot::Color const& colour, line_t& line - ) const; - static flag_segment_t make_flag_segment(godot::String const& identifier); + ); + flag_segment_t make_flag_segment(godot::String const& identifier); void separate_flag_segments( godot::String const& string, godot::Color const& colour, line_t& line - ) const; + ); std::vector wrap_lines(std::vector& unwrapped_lines) const; void adjust_to_content_size(); }; diff --git a/extension/src/openvic-extension/classes/GUIScrollbar.cpp b/extension/src/openvic-extension/classes/GUIScrollbar.cpp index 52d593d6..8a2747ec 100644 --- a/extension/src/openvic-extension/classes/GUIScrollbar.cpp +++ b/extension/src/openvic-extension/classes/GUIScrollbar.cpp @@ -299,7 +299,7 @@ void GUIScrollbar::emit_value_changed() { return; } emit_signal(signal_value_changed(), value); - value_changed(); + scaled_value.set(_get_scaled_value(value)); } void GUIScrollbar::reset() { @@ -522,12 +522,8 @@ void GUIScrollbar::set_value_as_ratio(float new_ratio) { set_value(step_count * new_ratio); } -fixed_point_t GUIScrollbar::get_value_scaled_fp() const { - return _get_scaled_value(value); -} - float GUIScrollbar::get_value_scaled() const { - return get_value_scaled_fp().to_float(); + return _get_scaled_value(value).to_float(); } void GUIScrollbar::set_step_count(const int32_t new_step_count) { @@ -592,12 +588,25 @@ void GUIScrollbar::set_range_limits_fp( : std::optional{} ); } -void GUIScrollbar::set_range_limits_and_value_from_slider_value(ReadOnlyClampedValue& slider_value) { +void GUIScrollbar::link_to(ReadOnlyClampedValue& clamped_value) { + clamped_value_connection.disconnect(); set_range_limits_fp( - slider_value.get_min(), - slider_value.get_max() + clamped_value.get_min(), + clamped_value.get_max() ); - set_scaled_value(slider_value.get_value_untracked()); + set_scaled_value(clamped_value.get_value( + [this](signal& dependency_changed) mutable -> void { + clamped_value_connection = std::move(dependency_changed.connect( + &GUIScrollbar::set_scaled_value, + this + )); + } + )); +} + +void GUIScrollbar::unlink() { + clamped_value_connection.disconnect(); + clamped_value_connection={}; } void GUIScrollbar::set_length_override(real_t new_length_override) { diff --git a/extension/src/openvic-extension/classes/GUIScrollbar.hpp b/extension/src/openvic-extension/classes/GUIScrollbar.hpp index f20a15f6..34e17d0f 100644 --- a/extension/src/openvic-extension/classes/GUIScrollbar.hpp +++ b/extension/src/openvic-extension/classes/GUIScrollbar.hpp @@ -6,14 +6,14 @@ #include #include -#include #include +#include #include "openvic-extension/classes/GFXSpriteTexture.hpp" #include "openvic-extension/classes/GUIHasTooltip.hpp" namespace OpenVic { - struct SliderValue; + struct ReadOnlyClampedValue; class GUIScrollbar : public godot::Control { GDCLASS(GUIScrollbar, godot::Control) @@ -47,6 +47,9 @@ namespace OpenVic { int32_t scale_denominator = 1; int32_t PROPERTY(step_count, 1); int32_t PROPERTY(value, 0); + STATE_PROPERTY(fixed_point_t, scaled_value); + + scoped_connection clamped_value_connection; bool PROPERTY_CUSTOM_PREFIX(range_limited, is, false); std::optional upper_range_limit; @@ -91,7 +94,6 @@ namespace OpenVic { public: static godot::StringName const& signal_value_changed(); - mutable signal_property value_changed; GUIScrollbar(); @@ -114,8 +116,6 @@ namespace OpenVic { float get_value_as_ratio() const; void set_value_as_ratio(float new_ratio); - - fixed_point_t get_value_scaled_fp() const; float get_value_scaled() const; void set_step_count(const int32_t new_step_count); @@ -132,9 +132,10 @@ namespace OpenVic { const std::optional new_lower_range_limit, const std::optional new_upper_range_limit ); - void set_range_limits_and_value_from_slider_value( + void link_to( ReadOnlyClampedValue& slider_value ); + void unlink(); /* Override the main dimension of gui_scollbar's size with the specified length. */ void set_length_override(real_t new_length_override); diff --git a/extension/src/openvic-extension/components/ReactiveComponent.cpp b/extension/src/openvic-extension/components/ReactiveComponent.cpp new file mode 100644 index 00000000..5165f83d --- /dev/null +++ b/extension/src/openvic-extension/components/ReactiveComponent.cpp @@ -0,0 +1,48 @@ +#include "ReactiveComponent.hpp" + +using namespace OpenVic; + +void ReactiveComponent::add_connection(connection conn) { + const std::lock_guard lock_guard { connections_lock }; + connections.emplace_back(std::move(conn)); +} + +void ReactiveComponent::disconnect_all() { + const std::lock_guard lock_guard { connections_lock }; + connections.clear(); +} + +void ReactiveComponent::update_if_dirty() { + if (!is_initialised) { + initialise(); + is_initialised = true; + } + + if (!is_dirty) { + return; + } + + const std::lock_guard lock_guard { is_dirty_lock }; + if (!is_dirty) { + return; + } + + update(); + + is_dirty = false; +} + +void ReactiveComponent::mark_dirty() { + if (is_dirty) { + return; + } + + const std::lock_guard lock_guard { is_dirty_lock }; + if (is_dirty) { + return; + } + + disconnect_all(); + is_dirty = true; + marked_dirty(); +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/ReactiveComponent.hpp b/extension/src/openvic-extension/components/ReactiveComponent.hpp new file mode 100644 index 00000000..d513ccee --- /dev/null +++ b/extension/src/openvic-extension/components/ReactiveComponent.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include + +namespace OpenVic { + struct ReactiveComponent { + private: + memory::vector connections; + std::mutex connections_lock; + bool is_dirty = true; + bool is_initialised = false; + std::mutex is_dirty_lock; + protected: + ReactiveComponent() {} + virtual ~ReactiveComponent() { + disconnect_all(); + } + + constexpr bool has_no_connections() const { + return connections.empty(); + } + + void add_connection(connection conn); + + template + auto connect_to_mark_dirty() { + return [this](signal& dependency_changed) mutable -> void { + connect_to_mark_dirty(dependency_changed); + }; + } + + template + auto connect_to_mark_dirty(signal& dependency_changed) { + add_connection(dependency_changed.connect([this](Args...) mutable -> void { mark_dirty(); })); + } + + auto connect_property_to_mark_dirty() { + return [this](signal_property& dependency_changed) mutable -> void { + add_connection(dependency_changed.connect(&ReactiveComponent::mark_dirty, this)); + }; + } + + template + auto connect_to_mark_dirty(signal_property& dependency_changed) { + add_connection(dependency_changed.connect([this](Args...) mutable -> void { mark_dirty(); })); + } + + void disconnect_all(); + virtual void initialise() {} + virtual void update() = 0; + public: + signal_property marked_dirty; + + ReactiveComponent(ReactiveComponent&&) = delete; + ReactiveComponent(ReactiveComponent const&) = delete; + ReactiveComponent& operator=(ReactiveComponent&&) = delete; + ReactiveComponent& operator=(ReactiveComponent const&) = delete; + + void update_if_dirty(); + void mark_dirty(); + }; +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/AdministrationBudget.cpp b/extension/src/openvic-extension/components/budget/AdministrationBudget.cpp index 52e0b077..9036667a 100644 --- a/extension/src/openvic-extension/components/budget/AdministrationBudget.cpp +++ b/extension/src/openvic-extension/components/budget/AdministrationBudget.cpp @@ -3,10 +3,12 @@ #include #include #include +#include #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUINode.hpp" #include "openvic-extension/classes/GUIScrollbar.hpp" +#include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/singletons/PlayerSingleton.hpp" #include "openvic-extension/utility/Utilities.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" @@ -53,17 +55,14 @@ AdministrationBudget::AdministrationBudget( administrative_efficiency_tooltip_args[4] = administrative_efficiency_label.tr("ADM_EXPLAIN_DESC"); } -fixed_point_t AdministrationBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t AdministrationBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { static const godot::StringName administrative_efficiency_template = "%s\n%s%s\n--------------\n%s%s%s%s"; - - const fixed_point_t administrative_efficiency_from_administrators = country.get_administrative_efficiency_from_administrators_untracked(); + const fixed_point_t administrative_efficiency_from_administrators = country.get_administrative_efficiency_from_administrators( + connect_to_mark_dirty() + ); administrative_efficiency_label.set_text( Utilities::format( "%s%%", @@ -103,10 +102,10 @@ fixed_point_t AdministrationBudget::calculate_budget_and_update_custom( "BUDGET_ADMIN_EFFICIENCY_DESC" ).replace( Utilities::get_percentage_value_placeholder(), - Utilities::fixed_point_to_string_dp(100 * country.get_administrator_percentage_untracked(), 1) + Utilities::fixed_point_to_string_dp(100 * country.get_administrator_percentage(connect_to_mark_dirty()), 1) ).replace( "MAX", - Utilities::fixed_point_to_string_dp(100 * country.desired_administrator_percentage.get_untracked(), 1) + Utilities::fixed_point_to_string_dp(100 * country.desired_administrator_percentage.get(connect_to_mark_dirty()), 1) ); administrative_efficiency_tooltip_args[5] = administrative_efficiency_label.tr( "COMWID_BASE" @@ -115,6 +114,7 @@ fixed_point_t AdministrationBudget::calculate_budget_and_update_custom( Utilities::percentage_to_string_dp(country_defines.get_max_bureaucracy_percentage(), 1) ); + add_connection(GameSingleton::get_singleton()->gamestate_updated.connect(&BudgetMenu::mark_dirty, this)); //for reforms godot::String reforms_part = ""; for (auto const& [group, reform] : country.get_reforms()) { if (!group.get_is_administrative() || reform == nullptr) { @@ -146,13 +146,13 @@ fixed_point_t AdministrationBudget::calculate_budget_and_update_custom( administrative_efficiency_template % administrative_efficiency_tooltip_args ); - return scaled_value * country.get_projected_administration_spending_unscaled_by_slider_untracked(); + return scaled_value * country.get_projected_administration_spending_unscaled_by_slider(connect_to_mark_dirty()); } ReadOnlyClampedValue& AdministrationBudget::get_clamped_value(CountryInstance& country) const { return country.get_administration_spending_slider_value(); } -void AdministrationBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void AdministrationBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_administration_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/AdministrationBudget.hpp b/extension/src/openvic-extension/components/budget/AdministrationBudget.hpp index 9f717255..e1d5880b 100644 --- a/extension/src/openvic-extension/components/budget/AdministrationBudget.hpp +++ b/extension/src/openvic-extension/components/budget/AdministrationBudget.hpp @@ -18,13 +18,11 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: AdministrationBudget( GUINode const& parent, CountryDefines const& new_country_defines ); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.cpp b/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.cpp index 1d75bc29..cd798df4 100644 --- a/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.cpp +++ b/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.cpp @@ -22,10 +22,6 @@ ArmyStockpileBudget::ArmyStockpileBudget(GUINode const& parent): slider.set_block_signals(false); } -fixed_point_t ArmyStockpileBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t ArmyStockpileBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value @@ -37,6 +33,6 @@ ReadOnlyClampedValue& ArmyStockpileBudget::get_clamped_value(CountryInstance& co return country.get_army_spending_slider_value(); } -void ArmyStockpileBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void ArmyStockpileBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_national_stockpile_army_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.hpp b/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.hpp index 97de4b6b..b5524748 100644 --- a/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.hpp +++ b/extension/src/openvic-extension/components/budget/ArmyStockpileBudget.hpp @@ -11,10 +11,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: ArmyStockpileBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenu.cpp b/extension/src/openvic-extension/components/budget/BudgetMenu.cpp index 3aea1663..a86fd5ff 100644 --- a/extension/src/openvic-extension/components/budget/BudgetMenu.cpp +++ b/extension/src/openvic-extension/components/budget/BudgetMenu.cpp @@ -1,13 +1,15 @@ #include "BudgetMenu.hpp" -#include - #include #include +#include #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUINode.hpp" +#include "openvic-extension/components/budget/BudgetMenuExpenses.hpp" +#include "openvic-extension/components/budget/BudgetMenuIncome.hpp" +#include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/singletons/PlayerSingleton.hpp" #include "openvic-extension/utility/Utilities.hpp" @@ -19,62 +21,29 @@ BudgetMenu::BudgetMenu( ModifierEffectCache const& modifier_effect_cache, CountryDefines const& country_defines ) : cash_stockpile_label{*parent.get_gui_label_from_nodepath("./country_budget/total_funds_val")}, - gold_income_label{*parent.get_gui_label_from_nodepath("./country_budget/gold_inc")}, projected_balance_label{*parent.get_gui_label_from_nodepath("./country_budget/balance")}, - projected_expenses_label{*parent.get_gui_label_from_nodepath("./country_budget/total_exp")}, - projected_income_label{*parent.get_gui_label_from_nodepath("./country_budget/total_inc")}, - administration_budget{parent,country_defines}, diplomatic_budget{parent}, - education_budget{parent}, - military_budget{parent}, - national_stockpile_budget{parent}, - social_budget{parent}, tariff_budget{parent,country_defines}, - projected_income_template{generate_projected_income_template(strata_keys.size())} - { - tax_budgets.reserve(strata_keys.size()); - connections.reserve(7 + strata_keys.size()); - connections.push_back(administration_budget.balance_changed.connect(&BudgetMenu::update_projected_expenses_and_balance, this)); - connections.push_back(diplomatic_budget.balance_changed.connect(&BudgetMenu::update_all_projections, this)); - connections.push_back(education_budget.balance_changed.connect(&BudgetMenu::update_projected_expenses_and_balance, this)); - connections.push_back(military_budget.balance_changed.connect(&BudgetMenu::update_projected_expenses_and_balance, this)); - connections.push_back(national_stockpile_budget.balance_changed.connect(&BudgetMenu::update_projected_expenses_and_balance, this)); - connections.push_back(social_budget.balance_changed.connect(&BudgetMenu::update_projected_expenses_and_balance, this)); - connections.push_back(tariff_budget.balance_changed.connect(&BudgetMenu::update_all_projections, this)); - for (Strata const& strata : strata_keys) { - StrataTaxBudget& strata_tax_budget = tax_budgets.emplace_back(parent, strata, modifier_effect_cache); - connections.push_back(strata_tax_budget.balance_changed.connect(&BudgetMenu::update_projected_income_and_balance, this)); - } - - GUILabel::set_text_and_tooltip( - parent, "./country_budget/gold_desc", - "GOLD","precious_metal_desc" - ); - GUILabel::set_text_and_tooltip( - parent, "./country_budget/ind_sub_desc", - "BUDGET_INDUSTRIAL_SUBSIDIES","IND_SUP_DESC" - ); + expenses_component{parent, country_defines, diplomatic_budget, tariff_budget}, + income_component{parent, strata_keys, modifier_effect_cache, diplomatic_budget, tariff_budget} +{ + GUILabel::set_text_and_tooltip( + parent, "./country_budget/ind_sub_desc", + "BUDGET_INDUSTRIAL_SUBSIDIES","IND_SUP_DESC" + ); +} - projected_income_args.resize(5 + strata_keys.size()); - projected_expenses_args.resize(8); +void BudgetMenu::update() { + CountryInstance* const player_country_ptr = PlayerSingleton::get_singleton()->get_player_country( + connect_to_mark_dirty() + ); + if (player_country_ptr == nullptr) { + return; } + CountryInstance& country = *player_country_ptr; -void BudgetMenu::update_projected_balance() { - CountryInstance const* const country_ptr = PlayerSingleton::get_singleton()->get_player_country(); - ERR_FAIL_NULL(country_ptr); - CountryInstance const& country = *country_ptr; - fixed_point_t projected_balance = country.get_gold_income_untracked() - + administration_budget.get_balance() - + diplomatic_budget.get_balance() - + education_budget.get_balance() - + military_budget.get_balance() - + national_stockpile_budget.get_balance() - + social_budget.get_balance() - + tariff_budget.get_balance(); - - for (StrataTaxBudget const& strata_tax_budget : tax_budgets) { - projected_balance += strata_tax_budget.get_balance(); - } + const fixed_point_t projected_balance = income_component.get_projected_income(connect_property_to_mark_dirty()) + - expenses_component.get_projected_expenses(connect_property_to_mark_dirty()); projected_balance_label.set_text( Utilities::format( @@ -83,169 +52,12 @@ void BudgetMenu::update_projected_balance() { Utilities::cash_to_string_dp_dynamic(projected_balance) ) ); -} - -void BudgetMenu::update_projected_expenses() { - static const godot::StringName projected_expenses_template = "%s\n--------------\n%s\n%s\n%s\n%s\n%s\n%s%s"; - const fixed_point_t projected_expenses = administration_budget.get_expenses() - + diplomatic_budget.get_expenses() - + education_budget.get_expenses() - + military_budget.get_expenses() - + national_stockpile_budget.get_expenses() - + social_budget.get_expenses() - + tariff_budget.get_expenses(); - //TODO: + import subsidies? - //TODO: + factory subsidies - //TODO: + interest - const fixed_point_t interest_expenses = 0; - - projected_expenses_label.set_text( - Utilities::cash_to_string_dp_dynamic(projected_expenses) - ); - projected_expenses_args[0] = projected_expenses_label.tr("BUDGET_TOTAL_EXPENSE").replace( - Utilities::get_short_value_placeholder(), - Utilities::float_to_string_dp(projected_expenses, 3) - ); - projected_expenses_args[1] = education_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_args[2] = administration_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_args[3] = social_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_args[4] = military_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_args[5] = projected_expenses_label.tr("BUDGET_INTEREST").replace( - Utilities::get_short_value_placeholder(), - Utilities::float_to_string_dp(interest_expenses, 1) - ); - projected_expenses_args[6] = national_stockpile_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_args[7] = diplomatic_budget.generate_expenses_summary_text(projected_expenses_label); - projected_expenses_label.set_tooltip_string( - projected_expenses_template % projected_expenses_args - ); -} - -void BudgetMenu::update_projected_expenses_and_balance() { - update_projected_expenses(); - update_projected_balance(); -} - -void BudgetMenu::update_projected_income() { - CountryInstance const* const country_ptr = PlayerSingleton::get_singleton()->get_player_country(); - ERR_FAIL_NULL(country_ptr); - CountryInstance const& country = *country_ptr; - size_t i = 1; - - fixed_point_t projected_income_excluding_tariffs = 0; - for (StrataTaxBudget const& strata_tax_budget : tax_budgets) { - const fixed_point_t strata_tax = strata_tax_budget.get_income(); - projected_income_excluding_tariffs += strata_tax; - projected_income_args[i++] = strata_tax_budget.generate_income_summary_text(projected_income_label); - } - - projected_income_args[i++] = tariff_budget.generate_income_summary_text(projected_income_label); - const fixed_point_t stockpile_income = 0; //TODO stockpile sales - projected_income_excluding_tariffs += stockpile_income; - projected_income_args[i++] = projected_income_label.tr("BUDGET_EXPORTS").replace( - Utilities::get_short_value_placeholder(), - Utilities::float_to_string_dp(stockpile_income, 1) - ); - - const fixed_point_t gold_income = country.get_gold_income_untracked(); - projected_income_excluding_tariffs += gold_income; - projected_income_args[i++] = projected_income_label.tr("BUDGET_GOLD").replace( - Utilities::get_short_value_placeholder(), - Utilities::float_to_string_dp(gold_income, 1) - ); - projected_income_args[i++] = diplomatic_budget.generate_income_summary_text(projected_income_label); - - const fixed_point_t projected_income = projected_income_excluding_tariffs + tariff_budget.get_income(); - projected_income_args[0] = projected_income_label.tr("BUDGET_TOTAL_INCOME").replace( - Utilities::get_short_value_placeholder(), - Utilities::float_to_string_dp(projected_income, 3) - ); - projected_income_label.set_text( - Utilities::cash_to_string_dp_dynamic(projected_income_excluding_tariffs) - ); - projected_income_label.set_tooltip_string( - projected_income_template % projected_income_args - ); - - //TODO stockpile sold to construction projects -} - -void BudgetMenu::update_projected_income_and_balance() { - update_projected_income(); - update_projected_balance(); -} - -void BudgetMenu::update_all_projections() { - update_projected_balance(); - update_projected_expenses(); - update_projected_income(); -} - -#define DO_FOR_ALL_COMPONENTS(F) \ - administration_budget.F; \ - diplomatic_budget.F; \ - education_budget.F; \ - military_budget.F; \ - national_stockpile_budget.F; \ - social_budget.F; \ - tariff_budget.F; \ - for (StrataTaxBudget& strata_tax_budget : tax_budgets) { \ - strata_tax_budget.F; \ - } - -void BudgetMenu::update() { - CountryInstance* const country_ptr = PlayerSingleton::get_singleton()->get_player_country(); - ERR_FAIL_NULL(country_ptr); - CountryInstance& country = *country_ptr; - - //this will trigger a lot of signals we should ignore - for (connection& c : connections) { - c.block(); - }; - DO_FOR_ALL_COMPONENTS(full_update(country)) - for (connection& c : connections) { - c.unblock(); - }; - update_all_projections(); - - const fixed_point_t gold_income = country.get_gold_income_untracked(); - gold_income_label.set_text( - Utilities::format_with_currency( - Utilities::float_to_string_dp(gold_income, 1) - ) - ); - gold_income_label.set_tooltip_string( - gold_income_label.tr("BUDGET_GOLD_INCOME_DESC") - //TODO add separator & list all province names + income if gold_income > 0 - ); + add_connection(GameSingleton::get_singleton()->gamestate_updated.connect(&BudgetMenu::mark_dirty, this)); //for cash stockpile const fixed_point_t cash_stockpile = country.get_cash_stockpile(); cash_stockpile_label.set_text( Utilities::format_with_currency( Utilities::float_to_string_suffixed(cash_stockpile) ) ); -} - -godot::StringName BudgetMenu::generate_projected_income_template(const size_t tax_budgets_size) { - static const std::string_view projected_income_template_start = "%s\n--------------"; - static const std::string_view projected_income_template_dynamic_part = "\n%s"; - - memory::string projected_income_template; - projected_income_template.reserve( - projected_income_template_start.size() - + projected_income_template_dynamic_part.size() * (tax_budgets_size + 3) - ); - - projected_income_template.append(projected_income_template_start); - for (size_t i = 0; i < tax_budgets_size; ++i) { - projected_income_template.append(projected_income_template_dynamic_part); - } - projected_income_template += "\n%s\n%s\n%s%s"; - return godot::StringName( - projected_income_template.data(), - false - ); -} - -#undef DO_FOR_ALL_COMPONENTS \ No newline at end of file +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenu.hpp b/extension/src/openvic-extension/components/budget/BudgetMenu.hpp index d05bf938..11d09970 100644 --- a/extension/src/openvic-extension/components/budget/BudgetMenu.hpp +++ b/extension/src/openvic-extension/components/budget/BudgetMenu.hpp @@ -5,48 +5,31 @@ #include #include +#include "openvic-extension/components/budget/BudgetMenuExpenses.hpp" +#include "openvic-extension/components/budget/BudgetMenuIncome.hpp" #include "openvic-extension/components/budget/AdministrationBudget.hpp" #include "openvic-extension/components/budget/DiplomaticBudget.hpp" -#include "openvic-extension/components/budget/EducationBudget.hpp" -#include "openvic-extension/components/budget/MilitaryBudget.hpp" #include "openvic-extension/components/budget/NationalStockpileBudget.hpp" -#include "openvic-extension/components/budget/SocialBudget.hpp" #include "openvic-extension/components/budget/StrataTaxBudget.hpp" #include "openvic-extension/components/budget/TariffBudget.hpp" +#include "openvic-extension/components/ReactiveComponent.hpp" namespace OpenVic { struct CountryInstance; struct GUINode; struct GUILabel; - struct BudgetMenu { + struct BudgetMenu : public ReactiveComponent { private: - static godot::StringName generate_projected_income_template(const size_t tax_budgets_size); - - const godot::StringName projected_income_template; - godot::Array projected_income_args; - godot::Array projected_expenses_args; - memory::vector connections; GUILabel& cash_stockpile_label; - GUILabel& gold_income_label; GUILabel& projected_balance_label; - GUILabel& projected_expenses_label; - GUILabel& projected_income_label; - AdministrationBudget administration_budget; DiplomaticBudget diplomatic_budget; - EducationBudget education_budget; - MilitaryBudget military_budget; - NationalStockpileBudget national_stockpile_budget; - SocialBudget social_budget; TariffBudget tariff_budget; - memory::vector tax_budgets; - void update_projected_balance(); - void update_projected_expenses(); - void update_projected_expenses_and_balance(); - void update_projected_income(); - void update_projected_income_and_balance(); - void update_all_projections(); + BudgetMenuExpenses expenses_component; + BudgetMenuIncome income_component; + + void update() override; public: BudgetMenu( GUINode const& parent, @@ -54,6 +37,5 @@ namespace OpenVic { ModifierEffectCache const& modifier_effect_cache, CountryDefines const& country_defines ); - void update(); }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.cpp b/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.cpp new file mode 100644 index 00000000..af717b54 --- /dev/null +++ b/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.cpp @@ -0,0 +1,100 @@ +#include "BudgetMenuExpenses.hpp" + +#include + +#include "openvic-extension/classes/GUILabel.hpp" +#include "openvic-extension/classes/GUINode.hpp" +#include "openvic-extension/components/budget/DiplomaticBudget.hpp" +#include "openvic-extension/components/budget/TariffBudget.hpp" +#include "openvic-extension/utility/Utilities.hpp" + +using namespace OpenVic; + +BudgetMenuExpenses::BudgetMenuExpenses( + GUINode const& parent, + CountryDefines const& country_defines, + DiplomaticBudget& new_diplomatic_budget, + TariffBudget& new_tariff_budget +) : projected_expenses_label{*parent.get_gui_label_from_nodepath("./country_budget/total_exp")}, + administration_budget{parent,country_defines}, + diplomatic_budget{new_diplomatic_budget}, + education_budget{parent}, + military_budget{parent}, + national_stockpile_budget{parent}, + social_budget{parent}, + tariff_budget{new_tariff_budget} + { + GUILabel::set_text_and_tooltip( + parent, "./country_budget/ind_sub_desc", + "BUDGET_INDUSTRIAL_SUBSIDIES","IND_SUP_DESC" + ); + projected_expenses_args.resize(8); + } + +void BudgetMenuExpenses::update() { + static const godot::StringName projected_expenses_template = "%s\n--------------\n%s\n%s\n%s\n%s\n%s\n%s%s"; + + const fixed_point_t administration_expenses = administration_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t diplomatic_expenses = diplomatic_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t education_expenses = education_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t military_expenses = military_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t national_stockpile_expenses= national_stockpile_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t social_expenses = social_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t tariff_expenses = -std::min( + tariff_budget.get_balance(connect_property_to_mark_dirty()), + fixed_point_t::_0 + ); + const fixed_point_t projected_expenses_total = administration_expenses + + diplomatic_expenses + + education_expenses + + military_expenses + + national_stockpile_expenses + + social_expenses + + tariff_expenses; + //TODO: + import subsidies? + //TODO: + factory subsidies + //TODO: + interest + const fixed_point_t interest_expenses = 0; + + projected_expenses_label.set_text( + Utilities::cash_to_string_dp_dynamic(projected_expenses_total) + ); + + projected_expenses_args[0] = projected_expenses_label.tr("BUDGET_TOTAL_EXPENSE").replace( + Utilities::get_short_value_placeholder(), + Utilities::float_to_string_dp(projected_expenses_total, 3) + ); + projected_expenses_args[1] = education_budget.generate_expenses_summary_text( + education_expenses, + projected_expenses_label + ); + projected_expenses_args[2] = administration_budget.generate_expenses_summary_text( + administration_expenses, + projected_expenses_label + ); + projected_expenses_args[3] = social_budget.generate_expenses_summary_text( + social_expenses, + projected_expenses_label + ); + projected_expenses_args[4] = military_budget.generate_expenses_summary_text( + military_expenses, + projected_expenses_label + ); + projected_expenses_args[5] = projected_expenses_label.tr("BUDGET_INTEREST").replace( + Utilities::get_short_value_placeholder(), + Utilities::float_to_string_dp(interest_expenses, 1) + ); + projected_expenses_args[6] = national_stockpile_budget.generate_expenses_summary_text( + national_stockpile_expenses, + projected_expenses_label + ); + projected_expenses_args[7] = diplomatic_budget.generate_expenses_summary_text( + diplomatic_expenses, + projected_expenses_label + ); + projected_expenses_label.set_tooltip_string( + projected_expenses_template % projected_expenses_args + ); + + _projected_expenses = projected_expenses_total; +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.hpp b/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.hpp new file mode 100644 index 00000000..f05c9c5a --- /dev/null +++ b/extension/src/openvic-extension/components/budget/BudgetMenuExpenses.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include +#include + +#include "openvic-extension/components/budget/AdministrationBudget.hpp" +#include "openvic-extension/components/budget/EducationBudget.hpp" +#include "openvic-extension/components/budget/MilitaryBudget.hpp" +#include "openvic-extension/components/budget/NationalStockpileBudget.hpp" +#include "openvic-extension/components/budget/SocialBudget.hpp" +#include "openvic-extension/components/ReactiveComponent.hpp" + +namespace OpenVic { + struct CountryInstance; + struct DiplomaticBudget; + struct GUINode; + struct GUILabel; + struct TariffBudget; + + struct BudgetMenuExpenses : public ReactiveComponent { + private: + godot::Array projected_expenses_args; + GUILabel& projected_expenses_label; + AdministrationBudget administration_budget; + DiplomaticBudget& diplomatic_budget; + EducationBudget education_budget; + MilitaryBudget military_budget; + NationalStockpileBudget national_stockpile_budget; + SocialBudget social_budget; + TariffBudget& tariff_budget; + + fixed_point_t _projected_expenses; + + void update() override; + public: + BudgetMenuExpenses( + GUINode const& parent, + CountryDefines const& country_defines, + DiplomaticBudget& new_diplomatic_budget, + TariffBudget& new_tariff_budget + ); + + template + requires std::invocable&> + [[nodiscard]] fixed_point_t get_projected_expenses(ConnectTemplateType&& connect) { + connect(marked_dirty); + update_if_dirty(); + return _projected_expenses; + } + }; +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenuIncome.cpp b/extension/src/openvic-extension/components/budget/BudgetMenuIncome.cpp new file mode 100644 index 00000000..ad3d75f6 --- /dev/null +++ b/extension/src/openvic-extension/components/budget/BudgetMenuIncome.cpp @@ -0,0 +1,142 @@ +#include "BudgetMenuIncome.hpp" + +#include + +#include +#include +#include + +#include "openvic-extension/classes/GUILabel.hpp" +#include "openvic-extension/classes/GUINode.hpp" +#include "openvic-extension/singletons/PlayerSingleton.hpp" +#include "openvic-extension/utility/Utilities.hpp" + +using namespace OpenVic; + +BudgetMenuIncome::BudgetMenuIncome( + GUINode const& parent, + utility::forwardable_span strata_keys, + ModifierEffectCache const& modifier_effect_cache, + DiplomaticBudget& new_diplomatic_budget, + TariffBudget& new_tariff_budget +) : gold_income_label{*parent.get_gui_label_from_nodepath("./country_budget/gold_inc")}, + projected_income_label{*parent.get_gui_label_from_nodepath("./country_budget/total_inc")}, + diplomatic_budget{new_diplomatic_budget}, + tariff_budget{new_tariff_budget}, + projected_income_template{generate_projected_income_template(strata_keys.size())}, + tax_budgets(strata_keys.size(), [ + strata_keys, + parent_ptr=&parent, + modifier_effect_cache_ptr=&modifier_effect_cache + ](const size_t i)->auto { + return std::make_tuple(parent_ptr, &strata_keys[i], modifier_effect_cache_ptr); + }) + { + GUILabel::set_text_and_tooltip( + parent, "./country_budget/gold_desc", + "GOLD","precious_metal_desc" + ); + + projected_income_args.resize(5 + strata_keys.size()); + } + +void BudgetMenuIncome::update() { + CountryInstance* const player_country_ptr = PlayerSingleton::get_singleton()->get_player_country( + connect_to_mark_dirty() + ); + if (player_country_ptr == nullptr) { + return; + } + CountryInstance& country = *player_country_ptr; + + const fixed_point_t gold_income = country.get_gold_income(connect_to_mark_dirty()); + gold_income_label.set_text( + Utilities::format_with_currency( + Utilities::float_to_string_dp(gold_income, 1) + ) + ); + gold_income_label.set_tooltip_string( + gold_income_label.tr("BUDGET_GOLD_INCOME_DESC") + //TODO add separator & list all province names + income if gold_income > 0 + ); + + size_t i = 1; + + fixed_point_t projected_income_excluding_tariffs = 0; + for (StrataTaxBudget& strata_tax_budget : tax_budgets) { + const fixed_point_t strata_tax = strata_tax_budget.get_balance(connect_property_to_mark_dirty()); + projected_income_excluding_tariffs += strata_tax; + projected_income_args[i++] = strata_tax_budget.generate_income_summary_text( + strata_tax, + projected_income_label + ); + } + + const fixed_point_t tariff_income = std::max( + fixed_point_t::_0, + tariff_budget.get_balance(connect_property_to_mark_dirty()) + ); + + projected_income_args[i++] = tariff_budget.generate_income_summary_text( + tariff_income, + projected_income_label + ); + const fixed_point_t stockpile_income = 0; //TODO stockpile sales + projected_income_excluding_tariffs += stockpile_income; + projected_income_args[i++] = projected_income_label.tr("BUDGET_EXPORTS").replace( + Utilities::get_short_value_placeholder(), + Utilities::float_to_string_dp(stockpile_income, 1) + ); + + projected_income_excluding_tariffs += gold_income; + projected_income_args[i++] = projected_income_label.tr("BUDGET_GOLD").replace( + Utilities::get_short_value_placeholder(), + Utilities::float_to_string_dp(gold_income, 1) + ); + + const fixed_point_t diplomatic_income = std::max( //not counted in projected_income + fixed_point_t::_0, + diplomatic_budget.get_balance(connect_property_to_mark_dirty()) + ); + projected_income_args[i++] = diplomatic_budget.generate_income_summary_text( + diplomatic_income, + projected_income_label + ); + + const fixed_point_t projected_income_including_tariffs = projected_income_excluding_tariffs + tariff_income; + projected_income_args[0] = projected_income_label.tr("BUDGET_TOTAL_INCOME").replace( + Utilities::get_short_value_placeholder(), + Utilities::float_to_string_dp(projected_income_including_tariffs, 3) + ); + projected_income_label.set_text( + Utilities::cash_to_string_dp_dynamic(projected_income_excluding_tariffs) + ); + projected_income_label.set_tooltip_string( + projected_income_template % projected_income_args + ); + + //TODO stockpile sold to construction projects + + _projected_income = projected_income_including_tariffs; +} + +godot::StringName BudgetMenuIncome::generate_projected_income_template(const size_t tax_budgets_size) { + static const std::string_view projected_income_template_start = "%s\n--------------"; + static const std::string_view projected_income_template_dynamic_part = "\n%s"; + + memory::string projected_income_template; + projected_income_template.reserve( + projected_income_template_start.size() + + projected_income_template_dynamic_part.size() * (tax_budgets_size + 3) + ); + + projected_income_template.append(projected_income_template_start); + for (size_t i = 0; i < tax_budgets_size; ++i) { + projected_income_template.append(projected_income_template_dynamic_part); + } + projected_income_template += "\n%s\n%s\n%s%s"; + return godot::StringName( + projected_income_template.data(), + false + ); +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/BudgetMenuIncome.hpp b/extension/src/openvic-extension/components/budget/BudgetMenuIncome.hpp new file mode 100644 index 00000000..a92998b0 --- /dev/null +++ b/extension/src/openvic-extension/components/budget/BudgetMenuIncome.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "openvic-extension/components/budget/StrataTaxBudget.hpp" +#include "openvic-extension/components/ReactiveComponent.hpp" + +namespace OpenVic { + struct CountryInstance; + struct DiplomaticBudget; + struct GUINode; + struct GUILabel; + struct TariffBudget; + + struct BudgetMenuIncome : public ReactiveComponent { + private: + static godot::StringName generate_projected_income_template(const size_t tax_budgets_size); + + const godot::StringName projected_income_template; + godot::Array projected_income_args; + GUILabel& gold_income_label; + GUILabel& projected_income_label; + DiplomaticBudget& diplomatic_budget; + TariffBudget& tariff_budget; + memory::FixedVector tax_budgets; + + fixed_point_t _projected_income; + + void update() override; + public: + BudgetMenuIncome( + GUINode const& parent, + utility::forwardable_span strata_keys, + ModifierEffectCache const& modifier_effect_cache, + DiplomaticBudget& new_diplomatic_budget, + TariffBudget& new_tariff_budget + ); + + template + requires std::invocable&> + [[nodiscard]] fixed_point_t get_projected_income(ConnectTemplateType&& connect) { + connect(marked_dirty); + update_if_dirty(); + return _projected_income; + } + }; +} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.cpp b/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.cpp index 6eca2cc2..0453af5d 100644 --- a/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.cpp +++ b/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.cpp @@ -22,10 +22,6 @@ ConstructionStockpileBudget::ConstructionStockpileBudget(GUINode const& parent): slider.set_block_signals(false); } -fixed_point_t ConstructionStockpileBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t ConstructionStockpileBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value @@ -37,6 +33,6 @@ ReadOnlyClampedValue& ConstructionStockpileBudget::get_clamped_value(CountryInst return country.get_construction_spending_slider_value(); } -void ConstructionStockpileBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void ConstructionStockpileBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_national_stockpile_construction_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.hpp b/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.hpp index 643e7f5a..38422c2a 100644 --- a/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.hpp +++ b/extension/src/openvic-extension/components/budget/ConstructionStockpileBudget.hpp @@ -11,10 +11,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: ConstructionStockpileBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/DiplomaticBudget.cpp b/extension/src/openvic-extension/components/budget/DiplomaticBudget.cpp index 2c27f6ac..f360213c 100644 --- a/extension/src/openvic-extension/components/budget/DiplomaticBudget.cpp +++ b/extension/src/openvic-extension/components/budget/DiplomaticBudget.cpp @@ -6,6 +6,7 @@ #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUINode.hpp" +#include "openvic-extension/singletons/PlayerSingleton.hpp" #include "openvic-extension/utility/Utilities.hpp" using namespace OpenVic; @@ -37,17 +38,26 @@ fixed_point_t DiplomaticBudget::get_expenses() const { ) \ : "" -void DiplomaticBudget::full_update(CountryInstance& country) { +void DiplomaticBudget::update() { + CountryInstance* const player_country_ptr = PlayerSingleton::get_singleton()->get_player_country( + connect_to_mark_dirty() + ); + if (player_country_ptr == nullptr) { + return; + } + CountryInstance& country = *player_country_ptr; + const CountryInstance::index_t index = country.get_index(); + //TODO get from sim once sim has it - reparations_income = fixed_point_t::_0_50; - war_subsidies_income = fixed_point_t::_1; - reparations_expenses = fixed_point_t::_1; - war_subsidies_expenses = fixed_point_t::_0_50; + reparations_income = index+fixed_point_t::_0_50; + war_subsidies_income = index+fixed_point_t::_1; + reparations_expenses = index+fixed_point_t::_1; + war_subsidies_expenses = index+fixed_point_t::_0_50; const fixed_point_t diplomatic_balance = reparations_income + war_subsidies_income - reparations_expenses - war_subsidies_expenses; - set_balance(diplomatic_balance); + _balance = diplomatic_balance; balance_label.set_text( Utilities::format( @@ -72,7 +82,10 @@ void DiplomaticBudget::full_update(CountryInstance& country) { #undef TOOLTIP_TEXT_PART -godot::String DiplomaticBudget::generate_income_summary_text(godot::Object const& translation_object) const { +godot::String DiplomaticBudget::generate_income_summary_text( + const fixed_point_t income, //ignored as this is special + godot::Object const& translation_object +) const { //war_subsidies_income are excluded here in Victoria 2 return reparations_income > 0 ? "\n"+translation_object.tr( @@ -84,7 +97,10 @@ godot::String DiplomaticBudget::generate_income_summary_text(godot::Object const : ""; } -godot::String DiplomaticBudget::generate_expenses_summary_text(godot::Object const& translation_object) const { +godot::String DiplomaticBudget::generate_expenses_summary_text( + const fixed_point_t expenses, //ignored as this is special + godot::Object const& translation_object +) const { //war_subsidies_expenses are excluded here in Victoria 2 return reparations_expenses > 0 ? "\n"+translation_object.tr( diff --git a/extension/src/openvic-extension/components/budget/DiplomaticBudget.hpp b/extension/src/openvic-extension/components/budget/DiplomaticBudget.hpp index bfc2a6b0..bbb5623c 100644 --- a/extension/src/openvic-extension/components/budget/DiplomaticBudget.hpp +++ b/extension/src/openvic-extension/components/budget/DiplomaticBudget.hpp @@ -2,16 +2,20 @@ #include -#include "openvic-extension/components/budget/abstract/BudgetComponent.hpp" +#include +#include + #include "openvic-extension/components/budget/abstract/BudgetIncomeComponent.hpp" #include "openvic-extension/components/budget/abstract/BudgetExpenseComponent.hpp" +#include "openvic-extension/components/ReactiveComponent.hpp" namespace OpenVic { + struct CountryInstance; struct GUILabel; struct GUINode; struct DiplomaticBudget : - public BudgetComponent, + public ReactiveComponent, public BudgetExpenseComponent, public BudgetIncomeComponent { private: @@ -22,17 +26,33 @@ namespace OpenVic { fixed_point_t reparations_expenses; fixed_point_t war_subsidies_income; fixed_point_t war_subsidies_expenses; - public: - fixed_point_t get_income() const override; - fixed_point_t get_expenses() const override; + fixed_point_t _balance; + fixed_point_t get_income() const; + fixed_point_t get_expenses() const; + protected: + void update() override; + public: DiplomaticBudget(GUINode const& parent); - void full_update(CountryInstance& country) override; - godot::String generate_income_summary_text(godot::Object const& translation_object) const override; - godot::String generate_expenses_summary_text(godot::Object const& translation_object) const override; + godot::String generate_income_summary_text( + const fixed_point_t income, + godot::Object const& translation_object + ) const override; + godot::String generate_expenses_summary_text( + const fixed_point_t expenses, + godot::Object const& translation_object + ) const override; godot::String generate_balance_summary_income_text(godot::Object const& translation_object) const; godot::String generate_balance_summary_expenses_text(godot::Object const& translation_object) const; + + template + requires std::invocable&> + [[nodiscard]] fixed_point_t get_balance(ConnectTemplateType&& connect) { + connect(marked_dirty); + update_if_dirty(); + return _balance; + } }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/EducationBudget.cpp b/extension/src/openvic-extension/components/budget/EducationBudget.cpp index 11159277..e6ccb252 100644 --- a/extension/src/openvic-extension/components/budget/EducationBudget.cpp +++ b/extension/src/openvic-extension/components/budget/EducationBudget.cpp @@ -39,21 +39,17 @@ EducationBudget::EducationBudget(GUINode const& parent): } } -fixed_point_t EducationBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t EducationBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { - return scaled_value * country.get_projected_education_spending_unscaled_by_slider_untracked(); + return scaled_value * country.get_projected_education_spending_unscaled_by_slider(connect_to_mark_dirty()); } ReadOnlyClampedValue& EducationBudget::get_clamped_value(CountryInstance& country) const { return country.get_education_spending_slider_value(); } -void EducationBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void EducationBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_education_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/EducationBudget.hpp b/extension/src/openvic-extension/components/budget/EducationBudget.hpp index fd60c3ef..5f044958 100644 --- a/extension/src/openvic-extension/components/budget/EducationBudget.hpp +++ b/extension/src/openvic-extension/components/budget/EducationBudget.hpp @@ -11,10 +11,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: EducationBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/MilitaryBudget.cpp b/extension/src/openvic-extension/components/budget/MilitaryBudget.cpp index f76a5266..7183ba71 100644 --- a/extension/src/openvic-extension/components/budget/MilitaryBudget.cpp +++ b/extension/src/openvic-extension/components/budget/MilitaryBudget.cpp @@ -5,6 +5,7 @@ #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUIScrollbar.hpp" #include "openvic-extension/singletons/PlayerSingleton.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" using namespace OpenVic; @@ -39,21 +40,17 @@ MilitaryBudget::MilitaryBudget(GUINode const& parent): } } -fixed_point_t MilitaryBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t MilitaryBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { - return scaled_value * country.get_projected_military_spending_unscaled_by_slider_untracked(); + return scaled_value * country.get_projected_military_spending_unscaled_by_slider(connect_to_mark_dirty()); } ReadOnlyClampedValue& MilitaryBudget::get_clamped_value(CountryInstance& country) const { return country.get_military_spending_slider_value(); } -void MilitaryBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void MilitaryBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_military_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/MilitaryBudget.hpp b/extension/src/openvic-extension/components/budget/MilitaryBudget.hpp index 59d3a0aa..542ff851 100644 --- a/extension/src/openvic-extension/components/budget/MilitaryBudget.hpp +++ b/extension/src/openvic-extension/components/budget/MilitaryBudget.hpp @@ -11,10 +11,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: MilitaryBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/NationalStockpileBudget.cpp b/extension/src/openvic-extension/components/budget/NationalStockpileBudget.cpp index 42ef08fc..4f801fd5 100644 --- a/extension/src/openvic-extension/components/budget/NationalStockpileBudget.cpp +++ b/extension/src/openvic-extension/components/budget/NationalStockpileBudget.cpp @@ -21,46 +21,24 @@ NationalStockpileBudget::NationalStockpileBudget(GUINode const& parent): army_stockpile_budget{parent}, navy_stockpile_budget{parent}, construction_stockpile_budget{parent} -{ - connections[0] = army_stockpile_budget.balance_changed.connect(&NationalStockpileBudget::on_slider_value_changed, this); - connections[1] = navy_stockpile_budget.balance_changed.connect(&NationalStockpileBudget::on_slider_value_changed, this); - connections[2] = construction_stockpile_budget.balance_changed.connect(&NationalStockpileBudget::on_slider_value_changed, this); - +{ GUILabel::set_text_and_tooltip( parent, "./country_budget/nat_stock_desc", "BUDGET_NATIONAL_STOCKPILE","NAT_STOCK_DESC" ); } -fixed_point_t NationalStockpileBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - -void NationalStockpileBudget::on_slider_value_changed() { - CountryInstance* const country_ptr = PlayerSingleton::get_singleton()->get_player_country(); - ERR_FAIL_NULL(country_ptr); - update_labels(*country_ptr); -} - -void NationalStockpileBudget::full_update(CountryInstance& country) {\ - for (connection& c : connections) { - c.block(); - }; - army_stockpile_budget.full_update(country); - navy_stockpile_budget.full_update(country); - construction_stockpile_budget.full_update(country); - for (connection& c : connections) { - c.unblock(); - }; - - update_labels(country); -} +void NationalStockpileBudget::update() { + CountryInstance* const player_country_ptr = PlayerSingleton::get_singleton()->get_player_country_untracked(); + if (player_country_ptr == nullptr) { + return; + } + CountryInstance& country = *player_country_ptr; -void NationalStockpileBudget::update_labels(CountryInstance& country) { - const fixed_point_t military_balance = army_stockpile_budget.get_balance() - + navy_stockpile_budget.get_balance(); - const fixed_point_t balance = military_balance - + construction_stockpile_budget.get_balance(); + const fixed_point_t military_balance = army_stockpile_budget.get_balance(connect_property_to_mark_dirty()) + + navy_stockpile_budget.get_balance(connect_property_to_mark_dirty()); + const fixed_point_t new_balance = military_balance + + construction_stockpile_budget.get_balance(connect_property_to_mark_dirty()); military_costs_label.set_text( Utilities::cash_to_string_dp_dynamic(-military_balance) @@ -72,8 +50,8 @@ void NationalStockpileBudget::update_labels(CountryInstance& country) { Utilities::cash_to_string_dp_dynamic(3) //TODO ); expenses_label.set_text( - Utilities::cash_to_string_dp_dynamic(-balance) + Utilities::cash_to_string_dp_dynamic(-new_balance) ); - set_balance(balance); + _balance = new_balance; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/NationalStockpileBudget.hpp b/extension/src/openvic-extension/components/budget/NationalStockpileBudget.hpp index 11cd3e51..d3b9a2e7 100644 --- a/extension/src/openvic-extension/components/budget/NationalStockpileBudget.hpp +++ b/extension/src/openvic-extension/components/budget/NationalStockpileBudget.hpp @@ -1,18 +1,19 @@ #pragma once -#include "openvic-extension/components/budget/abstract/BudgetComponent.hpp" +#include + #include "openvic-extension/components/budget/ArmyStockpileBudget.hpp" #include "openvic-extension/components/budget/ConstructionStockpileBudget.hpp" #include "openvic-extension/components/budget/NavyStockpileBudget.hpp" +#include "openvic-extension/components/ReactiveComponent.hpp" namespace OpenVic { struct GUILabel; struct GUINode; struct GUIScrollbar; - struct NationalStockpileBudget : public BudgetComponent, public BudgetExpenseComponent { + struct NationalStockpileBudget : public ReactiveComponent, public BudgetExpenseComponent { private: - connection connections[3]; GUILabel& military_costs_label; GUILabel& todays_actual_stockpile_spending_label; GUILabel& overseas_costs_label; @@ -20,12 +21,17 @@ namespace OpenVic { ArmyStockpileBudget army_stockpile_budget; NavyStockpileBudget navy_stockpile_budget; ConstructionStockpileBudget construction_stockpile_budget; - void on_slider_value_changed(); - void update_labels(CountryInstance& country); - + fixed_point_t _balance; public: NationalStockpileBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; - void full_update(CountryInstance& country) override; + void update() override; + + template + requires std::invocable&> + [[nodiscard]] fixed_point_t get_balance(ConnectTemplateType&& connect) { + connect(marked_dirty); + update_if_dirty(); + return _balance; + } }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/NavyStockpileBudget.cpp b/extension/src/openvic-extension/components/budget/NavyStockpileBudget.cpp index 1e63eebe..85cbbfd2 100644 --- a/extension/src/openvic-extension/components/budget/NavyStockpileBudget.cpp +++ b/extension/src/openvic-extension/components/budget/NavyStockpileBudget.cpp @@ -22,10 +22,6 @@ NavyStockpileBudget::NavyStockpileBudget(GUINode const& parent): slider.set_block_signals(false); } -fixed_point_t NavyStockpileBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t NavyStockpileBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value @@ -37,6 +33,6 @@ ReadOnlyClampedValue& NavyStockpileBudget::get_clamped_value(CountryInstance& co return country.get_navy_spending_slider_value(); } -void NavyStockpileBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void NavyStockpileBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_national_stockpile_navy_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/NavyStockpileBudget.hpp b/extension/src/openvic-extension/components/budget/NavyStockpileBudget.hpp index 1143f729..c74d2a4a 100644 --- a/extension/src/openvic-extension/components/budget/NavyStockpileBudget.hpp +++ b/extension/src/openvic-extension/components/budget/NavyStockpileBudget.hpp @@ -11,10 +11,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: NavyStockpileBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/SocialBudget.cpp b/extension/src/openvic-extension/components/budget/SocialBudget.cpp index ade6d6fe..36ca8d37 100644 --- a/extension/src/openvic-extension/components/budget/SocialBudget.cpp +++ b/extension/src/openvic-extension/components/budget/SocialBudget.cpp @@ -43,22 +43,24 @@ SocialBudget::SocialBudget(GUINode const& parent): } } -fixed_point_t SocialBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - fixed_point_t SocialBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { - const fixed_point_t pensions = scaled_value * country.get_projected_pensions_spending_unscaled_by_slider_untracked(); + const fixed_point_t pensions = scaled_value * country.get_projected_pensions_spending_unscaled_by_slider( + connect_to_mark_dirty() + ); pensions_label.set_text( Utilities::cash_to_string_dp_dynamic(pensions) ); - const fixed_point_t unemployment_subsidies = scaled_value * country.get_projected_unemployment_subsidies_spending_unscaled_by_slider_untracked(); + + const fixed_point_t unemployment_subsidies = scaled_value * country.get_projected_unemployment_subsidies_spending_unscaled_by_slider( + connect_to_mark_dirty() + ); unemployment_subsidies_label.set_text( Utilities::cash_to_string_dp_dynamic(unemployment_subsidies) ); + return pensions + unemployment_subsidies; } @@ -66,6 +68,6 @@ ReadOnlyClampedValue& SocialBudget::get_clamped_value(CountryInstance& country) return country.get_social_spending_slider_value(); } -void SocialBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void SocialBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_social_spending_slider_value(scaled_value); } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/SocialBudget.hpp b/extension/src/openvic-extension/components/budget/SocialBudget.hpp index 167f9221..edc92bd8 100644 --- a/extension/src/openvic-extension/components/budget/SocialBudget.hpp +++ b/extension/src/openvic-extension/components/budget/SocialBudget.hpp @@ -13,10 +13,8 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: SocialBudget(GUINode const& parent); - fixed_point_t get_expenses() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/StrataTaxBudget.cpp b/extension/src/openvic-extension/components/budget/StrataTaxBudget.cpp index 9b300f68..c4ee97a1 100644 --- a/extension/src/openvic-extension/components/budget/StrataTaxBudget.cpp +++ b/extension/src/openvic-extension/components/budget/StrataTaxBudget.cpp @@ -15,19 +15,19 @@ using namespace OpenVic; StrataTaxBudget::StrataTaxBudget( - GUINode const& parent, - Strata const& new_strata, - ModifierEffectCache const& new_modifier_effect_cache + GUINode const* parent, + Strata const* new_strata, + ModifierEffectCache const* new_modifier_effect_cache ): SliderBudgetComponent( - parent, - generate_slider_tooltip_localisation_key(new_strata), + *parent, + generate_slider_tooltip_localisation_key(*new_strata), BALANCE, - Utilities::format("./country_budget/tax_%d_slider", static_cast(new_strata.get_index())), - Utilities::format("./country_budget/tax_%d_inc", static_cast(new_strata.get_index())) + Utilities::format("./country_budget/tax_%d_slider", static_cast(new_strata->get_index())), + Utilities::format("./country_budget/tax_%d_inc", static_cast(new_strata->get_index())) ), - BudgetIncomeComponent(generate_summary_localisation_key(new_strata), 1), - strata{new_strata}, - modifier_effect_cache{new_modifier_effect_cache} + BudgetIncomeComponent(generate_summary_localisation_key(*new_strata), 1), + strata{*new_strata}, + modifier_effect_cache{*new_modifier_effect_cache} { slider.set_block_signals(true); slider.set_step_count(100); @@ -35,9 +35,9 @@ StrataTaxBudget::StrataTaxBudget( slider.set_block_signals(false); GUILabel::set_text_and_tooltip( - parent, - Utilities::format("./country_budget/tax_%d_desc", static_cast(new_strata.get_index())), - generate_slider_tooltip_localisation_key(new_strata), + *parent, + Utilities::format("./country_budget/tax_%d_desc", static_cast(new_strata->get_index())), + generate_slider_tooltip_localisation_key(*new_strata), Utilities::format( "TAX_%s_DESC", (godot::String::utf8( @@ -48,24 +48,20 @@ StrataTaxBudget::StrataTaxBudget( ); } -fixed_point_t StrataTaxBudget::get_income() const { - return std::max(fixed_point_t::_0, get_balance()); -} - fixed_point_t StrataTaxBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { return scaled_value * country.get_taxable_income_by_strata(strata) - * country.get_tax_efficiency_untracked(); + * country.get_tax_efficiency(connect_to_mark_dirty()); } ReadOnlyClampedValue& StrataTaxBudget::get_clamped_value(CountryInstance& country) const { return country.get_tax_rate_slider_value_by_strata(strata); } -void StrataTaxBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void StrataTaxBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_strata_tax_rate_slider_value( strata, scaled_value @@ -105,7 +101,7 @@ void StrataTaxBudget::update_slider_tooltip( const godot::String localised_strata_tax = slider.tr(slider_tooltip_localisation_key); - const fixed_point_t tax_efficiency = country.get_tax_efficiency_untracked(); + const fixed_point_t tax_efficiency = country.get_tax_efficiency(connect_to_mark_dirty()); const godot::String tax_efficiency_text = slider.tr(tax_efficiency_localisation_key).replace( Utilities::get_long_value_placeholder(), Utilities::float_to_string_dp(100 * tax_efficiency, 2) diff --git a/extension/src/openvic-extension/components/budget/StrataTaxBudget.hpp b/extension/src/openvic-extension/components/budget/StrataTaxBudget.hpp index c53df96e..f556fb05 100644 --- a/extension/src/openvic-extension/components/budget/StrataTaxBudget.hpp +++ b/extension/src/openvic-extension/components/budget/StrataTaxBudget.hpp @@ -20,19 +20,16 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; void update_slider_tooltip( CountryInstance& country, const fixed_point_t scaled_value ) override; - public: StrataTaxBudget( - GUINode const& parent, - Strata const& new_strata, - ModifierEffectCache const& new_modifier_effect_cache + GUINode const* parent, + Strata const* new_strata, + ModifierEffectCache const* new_modifier_effect_cache ); - StrataTaxBudget(StrataTaxBudget&&) = default; - fixed_point_t get_income() const override; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/TariffBudget.cpp b/extension/src/openvic-extension/components/budget/TariffBudget.cpp index b9fb8ead..ef93b098 100644 --- a/extension/src/openvic-extension/components/budget/TariffBudget.cpp +++ b/extension/src/openvic-extension/components/budget/TariffBudget.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUINode.hpp" @@ -46,28 +47,20 @@ TariffBudget::TariffBudget( ); } -fixed_point_t TariffBudget::get_expenses() const { - return std::max(fixed_point_t::_0, -get_balance()); -} - -fixed_point_t TariffBudget::get_income() const { - return std::max(fixed_point_t::_0, get_balance()); -} - fixed_point_t TariffBudget::calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) { return scaled_value - * country.get_yesterdays_import_value_untracked() - * country.tariff_efficiency.get_untracked(); + * country.get_yesterdays_import_value(connect_to_mark_dirty()) + * country.tariff_efficiency.get(connect_to_mark_dirty()); } ReadOnlyClampedValue& TariffBudget::get_clamped_value(CountryInstance& country) const { return country.get_tariff_rate_slider_value(); } -void TariffBudget::on_slider_value_changed(const fixed_point_t scaled_value) { +void TariffBudget::on_slider_scaled_value_changed(const fixed_point_t scaled_value) { PlayerSingleton::get_singleton()->set_tariff_rate_slider_value(scaled_value); } @@ -95,7 +88,7 @@ void TariffBudget::update_slider_tooltip( "Y"+Utilities::get_percentage_value_placeholder(), //not percentage_to_string_dp as localisation text contains the % prefix+Utilities::fixed_point_to_string_dp( - 100 * scaled_value * country.tariff_efficiency.get_untracked(), + 100 * scaled_value * country.tariff_efficiency.get(connect_to_mark_dirty()), 1 ) ); @@ -104,7 +97,7 @@ void TariffBudget::update_slider_tooltip( Utilities::get_percentage_value_placeholder(), //not percentage_to_string_dp as localisation text contains the % Utilities::fixed_point_to_string_dp( - 100 * country.get_administrative_efficiency_from_administrators_untracked(), + 100 * country.get_administrative_efficiency_from_administrators(connect_to_mark_dirty()), 1 ) ); diff --git a/extension/src/openvic-extension/components/budget/TariffBudget.hpp b/extension/src/openvic-extension/components/budget/TariffBudget.hpp index a3304d87..b75d0890 100644 --- a/extension/src/openvic-extension/components/budget/TariffBudget.hpp +++ b/extension/src/openvic-extension/components/budget/TariffBudget.hpp @@ -21,15 +21,12 @@ namespace OpenVic { const fixed_point_t scaled_value ) override; ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const override; - void on_slider_value_changed(const fixed_point_t scaled_value) override; - + void on_slider_scaled_value_changed(const fixed_point_t scaled_value) override; public: TariffBudget( GUINode const& parent, CountryDefines const& country_defines ); - fixed_point_t get_expenses() const override; - fixed_point_t get_income() const override; void update_slider_tooltip( CountryInstance& country, const fixed_point_t scaled_value diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.cpp b/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.cpp deleted file mode 100644 index 532b4b20..00000000 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "BudgetComponent.hpp" - -using namespace OpenVic; - -fixed_point_t BudgetComponent::get_balance() const { - return balance; -} - -void BudgetComponent::set_balance(const fixed_point_t new_balance) { - if (balance == new_balance) {; - return; - } - - balance = new_balance; - balance_changed(); -} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.hpp b/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.hpp deleted file mode 100644 index 8e7b7a69..00000000 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetComponent.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -namespace OpenVic { - struct CountryInstance; - - struct BudgetComponent { - private: - fixed_point_t balance = 0; - - protected: - void set_balance(const fixed_point_t balance); - - public: - signal_property balance_changed; - fixed_point_t get_balance() const; - virtual void full_update(CountryInstance& country) = 0; - }; -} \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.cpp b/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.cpp index dbec463e..d447445c 100644 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.cpp +++ b/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.cpp @@ -11,9 +11,9 @@ BudgetExpenseComponent::BudgetExpenseComponent( expenses_summary_decimal_places{new_expenses_summary_decimal_places} {} godot::String BudgetExpenseComponent::generate_expenses_summary_text( + const fixed_point_t expenses, godot::Object const& translation_object ) const { - const fixed_point_t expenses = get_expenses(); return translation_object.tr(expenses_summary_localisation_key).replace( Utilities::get_short_value_placeholder(), expenses_summary_decimal_places < 0 @@ -22,9 +22,12 @@ godot::String BudgetExpenseComponent::generate_expenses_summary_text( ); } -godot::String BudgetExpenseComponent::generate_balance_expenses_summary_text(godot::Object const& translation_object) const { +godot::String BudgetExpenseComponent::generate_balance_expenses_summary_text( + const fixed_point_t expenses, + godot::Object const& translation_object +) const { static const godot::StringName red_minus = "R-"; - const fixed_point_t expenses = get_expenses(); //TODO use yesterdays value + //TODO use yesterdays value return translation_object.tr(expenses_summary_localisation_key).replace( "Y$VAL$", red_minus + Utilities::float_to_string_dp(expenses, expenses_summary_decimal_places) diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.hpp b/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.hpp index 18dab83d..2ffa73cc 100644 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.hpp +++ b/extension/src/openvic-extension/components/budget/abstract/BudgetExpenseComponent.hpp @@ -21,8 +21,13 @@ namespace OpenVic { const int32_t new_expenses_summary_decimal_places = -1 ); public: - virtual fixed_point_t get_expenses() const = 0; - virtual godot::String generate_expenses_summary_text(godot::Object const& translation_object) const; - virtual godot::String generate_balance_expenses_summary_text(godot::Object const& translation_object) const; + virtual godot::String generate_expenses_summary_text( + const fixed_point_t expenses, + godot::Object const& translation_object + ) const; + virtual godot::String generate_balance_expenses_summary_text( + const fixed_point_t expenses, + godot::Object const& translation_object + ) const; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.cpp b/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.cpp index 77dae159..b625bdce 100644 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.cpp +++ b/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.cpp @@ -11,9 +11,9 @@ BudgetIncomeComponent::BudgetIncomeComponent( income_summary_decimal_places{new_income_summary_decimal_places} {} godot::String BudgetIncomeComponent::generate_income_summary_text( + const fixed_point_t income, godot::Object const& translation_object ) const { - const fixed_point_t income = get_income(); return translation_object.tr(income_summary_localisation_key).replace( Utilities::get_short_value_placeholder(), income_summary_decimal_places < 0 @@ -22,9 +22,12 @@ godot::String BudgetIncomeComponent::generate_income_summary_text( ); } -godot::String BudgetIncomeComponent::generate_balance_income_summary_text(godot::Object const& translation_object) const { +godot::String BudgetIncomeComponent::generate_balance_income_summary_text( + const fixed_point_t income, + godot::Object const& translation_object +) const { static const godot::StringName green_plus = "G+"; - const fixed_point_t income = get_income(); //TODO use yesterdays value + //TODO use yesterdays value return translation_object.tr(income_summary_localisation_key).replace( "Y$VAL$", green_plus + Utilities::float_to_string_dp(income, income_summary_decimal_places) diff --git a/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.hpp b/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.hpp index 9f4bd422..bf6f2ff6 100644 --- a/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.hpp +++ b/extension/src/openvic-extension/components/budget/abstract/BudgetIncomeComponent.hpp @@ -21,8 +21,13 @@ namespace OpenVic { const int32_t new_income_summary_decimal_places = -1 ); public: - virtual fixed_point_t get_income() const = 0; - virtual godot::String generate_income_summary_text(godot::Object const& translation_object) const; - virtual godot::String generate_balance_income_summary_text(godot::Object const& translation_object) const; + virtual godot::String generate_income_summary_text( + const fixed_point_t income, + godot::Object const& translation_object + ) const; + virtual godot::String generate_balance_income_summary_text( + const fixed_point_t income, + godot::Object const& translation_object + ) const; }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.cpp b/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.cpp index 1249a12d..18ec01f8 100644 --- a/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.cpp +++ b/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.cpp @@ -3,11 +3,14 @@ #include #include +#include +#include #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/classes/GUINode.hpp" #include "openvic-extension/classes/GUIScrollbar.hpp" #include "openvic-extension/singletons/PlayerSingleton.hpp" +#include "openvic-simulation/types/Signal.hpp" using namespace OpenVic; @@ -32,31 +35,52 @@ SliderBudgetComponent::SliderBudgetComponent( }, slider{*parent.get_gui_scrollbar_from_nodepath(slider_path)} { - slider.set_block_signals(true); - slider.set_step_count(100); - slider.set_scale(0, 1, 100); - slider.set_block_signals(false); - slider.value_changed.connect(&SliderBudgetComponent::_on_slider_value_changed, this); + slider_scaled_value_cached = slider.get_scaled_value( + [this](signal& slider_scaled_value_changed) mutable -> void { + slider_scaled_value_connection = std::move( + slider_scaled_value_changed.connect(&SliderBudgetComponent::_on_slider_scaled_value_changed, this) + ); + } + ); + player_country_cached = PlayerSingleton::get_singleton()->get_player_country( + [this](signal& player_country_changed) mutable ->void { + player_country_connection = std::move( + player_country_changed.connect(&SliderBudgetComponent::_on_player_country_changed, this) + ); + } + ); } -void SliderBudgetComponent::_on_slider_value_changed() { - const fixed_point_t scaled_value = slider.get_value_scaled_fp(); - on_slider_value_changed(scaled_value); - CountryInstance* const country_ptr = PlayerSingleton::get_singleton()->get_player_country(); - ERR_FAIL_NULL(country_ptr); - update_labels(*country_ptr, scaled_value); +void SliderBudgetComponent::initialise() { + _on_player_country_changed(player_country_cached); } -void SliderBudgetComponent::full_update(CountryInstance& country) { - ReadOnlyClampedValue& clamped_value = get_clamped_value(country); +void SliderBudgetComponent::_on_player_country_changed(CountryInstance* new_player_country) { + player_country_cached = new_player_country; + if (new_player_country == nullptr) { + slider.unlink(); + } else { + ReadOnlyClampedValue& clamped_value = get_clamped_value(*new_player_country); + slider.set_block_signals(true); + slider.link_to(clamped_value); + slider.set_block_signals(false); + slider_scaled_value_cached = clamped_value.get_value_untracked(); + } + mark_dirty(); +} - slider.set_block_signals(true); - slider.set_range_limits_and_value_from_slider_value(clamped_value); - slider.set_block_signals(false); - update_labels(country, clamped_value.get_value_untracked()); +void SliderBudgetComponent::_on_slider_scaled_value_changed(const fixed_point_t scaled_value) { + slider_scaled_value_cached = scaled_value; + on_slider_scaled_value_changed(scaled_value); + mark_dirty(); } -void SliderBudgetComponent::update_labels(CountryInstance& country, const fixed_point_t scaled_value) { +void SliderBudgetComponent::update() { + if (player_country_cached == nullptr) { + return; + } + CountryInstance& country = *player_country_cached; + const fixed_point_t scaled_value = slider_scaled_value_cached; const fixed_point_t budget = calculate_budget_and_update_custom(country, scaled_value); if (budget_label != nullptr) { budget_label->set_text( @@ -72,10 +96,9 @@ void SliderBudgetComponent::update_labels(CountryInstance& country, const fixed_ update_slider_tooltip(country, scaled_value); - const fixed_point_t balance = budget_type == EXPENSES + _balance = budget_type == EXPENSES ? -budget : budget; - set_balance(balance); } void SliderBudgetComponent::update_slider_tooltip( diff --git a/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.hpp b/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.hpp index 8982b27f..286ee456 100644 --- a/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.hpp +++ b/extension/src/openvic-extension/components/budget/abstract/SliderBudgetComponent.hpp @@ -3,7 +3,9 @@ #include #include -#include "openvic-extension/components/budget/abstract/BudgetComponent.hpp" +#include + +#include "openvic-extension/components/ReactiveComponent.hpp" namespace OpenVic { struct CountryInstance; @@ -17,13 +19,19 @@ namespace OpenVic { EXPENSES }; - struct SliderBudgetComponent : public BudgetComponent { + struct SliderBudgetComponent : public ReactiveComponent { private: - //multiplies balance by -1 for balance_label - const BudgetType budget_type; + const BudgetType budget_type; //multiplies balance by -1 for balance_label GUILabel* const percent_label; - void _on_slider_value_changed(); - void update_labels(CountryInstance& country, const fixed_point_t scaled_value); + fixed_point_t _balance; + + scoped_connection player_country_connection; + CountryInstance* player_country_cached; + void _on_player_country_changed(CountryInstance* const player_country); + + scoped_connection slider_scaled_value_connection; + fixed_point_t slider_scaled_value_cached; + void _on_slider_scaled_value_changed(const fixed_point_t scaled_value); protected: const godot::String slider_tooltip_localisation_key; GUIScrollbar& slider; @@ -38,18 +46,26 @@ namespace OpenVic { godot::NodePath const& percent_label_path = {} ); + void initialise() override; + virtual void update_slider_tooltip( + CountryInstance& country, + const fixed_point_t scaled_value + ); + virtual fixed_point_t calculate_budget_and_update_custom( CountryInstance& country, const fixed_point_t scaled_value ) = 0; virtual ReadOnlyClampedValue& get_clamped_value(CountryInstance& country) const = 0; - virtual void on_slider_value_changed(const fixed_point_t scaled_value) = 0; - virtual void update_slider_tooltip( - CountryInstance& country, - const fixed_point_t scaled_value - ); - + virtual void on_slider_scaled_value_changed(const fixed_point_t scaled_value) = 0; + void update() override; public: - void full_update(CountryInstance& country) override; + template + requires std::invocable&> + [[nodiscard]] fixed_point_t get_balance(ConnectTemplateType&& connect) { + connect(marked_dirty); + update_if_dirty(); + return _balance; + } }; } \ No newline at end of file diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp index e6cab201..32ac058e 100644 --- a/extension/src/openvic-extension/singletons/GameSingleton.cpp +++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp @@ -155,7 +155,7 @@ Error GameSingleton::setup_game(int32_t bookmark_index) { PlayerSingleton& player_singleton = *PlayerSingleton::get_singleton(); player_singleton.set_player_country(starting_country); - ERR_FAIL_NULL_V(player_singleton.get_player_country(), FAILED); + ERR_FAIL_NULL_V(player_singleton.get_player_country_untracked(), FAILED); // TODO - remove this test starting research for (Technology const& technology : @@ -288,7 +288,7 @@ Error GameSingleton::_update_colour_image() { PlayerSingleton const& player_singleton = *PlayerSingleton::get_singleton(); if (instance_manager != nullptr && !get_definition_manager().get_mapmode_manager().generate_mapmode_colours( - instance_manager->get_map_instance(), mapmode, player_singleton.get_player_country(), + instance_manager->get_map_instance(), mapmode, player_singleton.get_player_country_untracked(), player_singleton.get_selected_province(), colour_data_array.ptrw() )) { err = FAILED; diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp index bb00571b..69fc1e8c 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp @@ -88,8 +88,8 @@ String MenuSingleton::_get_state_name(State const& state) const { } String MenuSingleton::_get_country_name(CountryInstance const& country) const { - GovernmentType const* government_type = country.get_government_type_untracked(); - if (government_type != nullptr) { + GovernmentType const* const government_type = country.get_government_type_untracked(); + if (government_type != nullptr && !government_type->get_identifier().empty()) { const String government_name_key = Utilities::std_to_godot_string(StringUtils::append_string_views( country.get_identifier(), "_", government_type->get_identifier() )); @@ -106,9 +106,9 @@ String MenuSingleton::_get_country_name(CountryInstance const& country) const { String MenuSingleton::_get_country_adjective(CountryInstance const& country) const { static constexpr std::string_view adjective = "_ADJ"; + GovernmentType const* const government_type = country.get_government_type_untracked(); - GovernmentType const* government_type = country.get_government_type_untracked(); - if (government_type != nullptr) { + if (government_type != nullptr && !government_type->get_identifier().empty()) { const String government_adjective_key = Utilities::std_to_godot_string(StringUtils::append_string_views( country.get_identifier(), "_", government_type->get_identifier(), adjective )); @@ -295,7 +295,7 @@ String MenuSingleton::_make_rules_tooltip(RuleSet const& rules) const { } String MenuSingleton::_make_mobilisation_impact_tooltip() const { - CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance const* const country = PlayerSingleton::get_singleton()->get_player_country_untracked(); if (country == nullptr) { return {}; @@ -446,6 +446,7 @@ void MenuSingleton::_bind_methods() { /* BUDGET MENU */ OV_BIND_METHOD(MenuSingleton::link_budget_menu_to_cpp, { "godot_budget_menu" }); + OV_BIND_METHOD(MenuSingleton::update_budget_menu_cpp); /* Find/Search Panel */ OV_BIND_METHOD(MenuSingleton::generate_search_cache); @@ -1132,7 +1133,7 @@ int32_t MenuSingleton::get_rgo_owner_pop_icon_index() const { /* TOPBAR */ Dictionary MenuSingleton::get_topbar_info() const { - CountryInstance* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance* const country = PlayerSingleton::get_singleton()->get_player_country_untracked(); if (country == nullptr) { return {}; } @@ -1270,7 +1271,7 @@ Dictionary MenuSingleton::get_topbar_info() const { static const StringName research_points_key = "research_points"; static const StringName research_points_tooltip_key = "research_points_tooltip"; - Technology const* current_research = country->get_current_research_untracked(); + Technology const* const current_research = country->get_current_research_untracked(); if (current_research != nullptr) { static const StringName research_localisation_key = "TECHNOLOGYVIEW_RESEARCH_TOOLTIP"; static const String tech_replace_key = "$TECH$"; @@ -1539,11 +1540,6 @@ String MenuSingleton::get_longform_date() const { void MenuSingleton::link_budget_menu_to_cpp(GUINode const* const godot_budget_menu) { ERR_FAIL_NULL(godot_budget_menu); GameSingleton& game_singleton = *GameSingleton::get_singleton(); - BudgetMenu* old_instance = budget_menu.get(); - if (old_instance != nullptr) { - game_singleton.gamestate_updated.disconnect(&BudgetMenu::update, old_instance); - } - auto const& strata_keys = game_singleton.get_definition_manager().get_pop_manager().get_stratas(); ModifierEffectCache const& modifier_effect_cache = game_singleton.get_definition_manager().get_modifier_manager().get_modifier_effect_cache(); CountryDefines const& country_defines = game_singleton.get_definition_manager().get_define_manager().get_country_defines(); @@ -1553,7 +1549,10 @@ void MenuSingleton::link_budget_menu_to_cpp(GUINode const* const godot_budget_me modifier_effect_cache, country_defines ); - game_singleton.gamestate_updated.connect(&BudgetMenu::update, budget_menu.get()); +} + +void MenuSingleton::update_budget_menu_cpp() const { + budget_menu->update_if_dirty(); } /* Find/Search Panel */ diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp index 0ceb0b34..f26a18e7 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp @@ -287,6 +287,7 @@ namespace OpenVic { /* BUDGET MENU */ void link_budget_menu_to_cpp(GUINode const* const godot_budget_menu); + void update_budget_menu_cpp() const; /* Find/Search Panel */ // TODO - update on country government type change and state creation/destruction diff --git a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp index cea34ab0..11370ea0 100644 --- a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp +++ b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp @@ -302,7 +302,7 @@ Dictionary MenuSingleton::make_in_progress_unit_dict() const { // TODO - remove test data, read actual in-progress units from SIM UnitType const* unit_type = definition_manager.get_military_manager().get_unit_type_manager().get_unit_type_by_index(0); - ProvinceInstance const* location = PlayerSingleton::get_singleton()->get_player_country()->get_capital(); + ProvinceInstance const* location = PlayerSingleton::get_singleton()->get_player_country_untracked()->get_capital(); const Date eta { 1900 }; const fixed_point_t progress = fixed_point_t::_0_50; const ordered_map> required_goods { @@ -360,7 +360,7 @@ Dictionary MenuSingleton::get_military_menu_info() { StaticModifierCache const& static_modifier_cache = definition_manager.get_modifier_manager().get_static_modifier_cache(); IssueManager const& issue_manager = definition_manager.get_politics_manager().get_issue_manager(); - CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country_untracked(); if (country == nullptr) { return {}; } diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.cpp b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp index fc1e6b63..21b382a2 100644 --- a/extension/src/openvic-extension/singletons/PlayerSingleton.cpp +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "openvic-extension/classes/GUIScrollbar.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" @@ -64,7 +65,7 @@ PlayerSingleton* PlayerSingleton::get_singleton() { return singleton; } -PlayerSingleton::PlayerSingleton() { +PlayerSingleton::PlayerSingleton() : player_country{nullptr} { ERR_FAIL_COND(singleton != nullptr); singleton = this; } @@ -76,7 +77,8 @@ PlayerSingleton::~PlayerSingleton() { // Player country void PlayerSingleton::set_player_country(CountryInstance* new_player_country) { - if (OV_unlikely(player_country == new_player_country)) { + CountryInstance* const old_player_country = player_country.get_untracked(); + if (OV_unlikely(old_player_country == new_player_country)) { return; } @@ -84,23 +86,23 @@ void PlayerSingleton::set_player_country(CountryInstance* new_player_country) { InstanceManager* instance_manager = game_singleton.get_instance_manager(); ERR_FAIL_NULL(instance_manager); - if (player_country != nullptr) { + if (old_player_country != nullptr) { instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_AI, - std::pair { player_country->get_index(), true } + std::pair { old_player_country->get_index(), true } ); } - player_country = new_player_country; - - if (player_country != nullptr) { + if (new_player_country != nullptr) { instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_AI, - std::pair { player_country->get_index(), false } + std::pair { new_player_country->get_index(), false } ); } - Logger::info("Set player country to: ", player_country != nullptr ? player_country->get_identifier() : ""); + player_country.set(new_player_country); + + Logger::info("Set player country to: ", new_player_country != nullptr ? new_player_country->get_identifier() : ""); game_singleton._on_gamestate_updated(); } @@ -116,8 +118,9 @@ void PlayerSingleton::set_player_country_by_province_number(int32_t province_num } Vector2 PlayerSingleton::get_player_country_capital_position() const { - if (player_country != nullptr) { - ProvinceInstance const* capital = player_country->get_capital(); + CountryInstance const* const current_player_country = player_country.get_untracked(); + if (current_player_country != nullptr) { + ProvinceInstance const* capital = current_player_country->get_capital(); if (capital != nullptr) { return GameSingleton::get_singleton()->get_billboard_pos(capital->get_province_definition()); @@ -213,12 +216,13 @@ void PlayerSingleton::expand_selected_province_building(int32_t building_index) // Budget #define SET_SLIDER_GAME_ACTION(value_name, game_action_name) \ void PlayerSingleton::set_##value_name##_slider_value(fixed_point_t const value) const { \ - if (player_country == nullptr) { \ + CountryInstance const* const current_player_country = player_country.get_untracked(); \ + if (current_player_country == nullptr) { \ return; \ } \ GameSingleton::get_singleton()->get_instance_manager()->queue_game_action( \ game_action_type_t::GAME_ACTION_SET_##game_action_name, \ - std::pair { player_country->get_index(), value } \ + std::pair { current_player_country->get_index(), value } \ ); \ } @@ -234,12 +238,11 @@ SET_SLIDER_GAME_ACTION(tariff_rate, TARIFF_RATE) #undef SET_SLIDER_GAME_ACTION void PlayerSingleton::set_strata_tax_rate_slider_value(Strata const& strata, fixed_point_t const value) const { - if (player_country == nullptr) { - return; - } + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); GameSingleton::get_singleton()->get_instance_manager()->queue_game_action( game_action_type_t::GAME_ACTION_SET_STRATA_TAX, - std::tuple { player_country->get_index(), strata.get_index(), value } + std::tuple { current_player_country->get_index(), strata.get_index(), value } ); } @@ -251,28 +254,30 @@ void PlayerSingleton::set_strata_tax_rate_slider_value(Strata const& strata, fix // Trade void PlayerSingleton::set_good_automated(int32_t good_index, bool is_automated) const { - ERR_FAIL_NULL(player_country); + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_GOOD_AUTOMATED, - std::tuple { player_country->get_index(), good_index, is_automated } + std::tuple { current_player_country->get_index(), good_index, is_automated } ); } void PlayerSingleton::set_good_trade_order(int32_t good_index, bool is_selling, GUIScrollbar const* amount_slider) const { + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); ERR_FAIL_NULL(amount_slider); - ERR_FAIL_NULL(player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_GOOD_TRADE_ORDER, std::tuple { - player_country->get_index(), good_index, is_selling, - MenuSingleton::calculate_trade_menu_stockpile_cutoff_amount_fp(amount_slider->get_value_scaled_fp()) + current_player_country->get_index(), good_index, is_selling, + MenuSingleton::calculate_trade_menu_stockpile_cutoff_amount_fp(amount_slider->get_scaled_value_untracked()) } ); } @@ -281,14 +286,15 @@ void PlayerSingleton::set_good_trade_order(int32_t good_index, bool is_selling, // Military void PlayerSingleton::create_leader(bool is_general) const { - ERR_FAIL_NULL(player_country); + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_CREATE_LEADER, - std::pair { player_country->get_index(), is_general } + std::pair { current_player_country->get_index(), is_general } ); } @@ -303,37 +309,40 @@ void PlayerSingleton::set_can_use_leader(uint64_t leader_id, bool can_use) const } void PlayerSingleton::set_auto_create_leaders(bool value) const { - ERR_FAIL_NULL(player_country); + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_AUTO_CREATE_LEADERS, - std::pair { player_country->get_index(), value } + std::pair { current_player_country->get_index(), value } ); } void PlayerSingleton::set_auto_assign_leaders(bool value) const { - ERR_FAIL_NULL(player_country); + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_AUTO_ASSIGN_LEADERS, - std::pair { player_country->get_index(), value } + std::pair { current_player_country->get_index(), value } ); } void PlayerSingleton::set_mobilise(bool value) const { - ERR_FAIL_NULL(player_country); + CountryInstance const* const current_player_country = player_country.get_untracked(); + ERR_FAIL_NULL(current_player_country); InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); instance_manager->queue_game_action( game_action_type_t::GAME_ACTION_SET_MOBILISE, - std::pair { player_country->get_index(), value } + std::pair { current_player_country->get_index(), value } ); } diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp index c04ec1cb..9c17d5ff 100644 --- a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace OpenVic { struct CountryInstance; @@ -16,7 +17,7 @@ namespace OpenVic { static inline PlayerSingleton* singleton = nullptr; - CountryInstance* player_country = nullptr; + STATE_PROPERTY(CountryInstance*, player_country); ProvinceInstance const* PROPERTY(selected_province, nullptr); static godot::StringName const& _signal_province_selected(); @@ -31,12 +32,6 @@ namespace OpenVic { ~PlayerSingleton(); // Player country - [[nodiscard]] constexpr CountryInstance* get_player_country() { - return player_country; - } - [[nodiscard]] constexpr CountryInstance const* get_player_country() const { - return player_country; - } void set_player_country(CountryInstance* new_player_country); void set_player_country_by_province_number(int32_t province_number); godot::Vector2 get_player_country_capital_position() const; diff --git a/extension/src/openvic-extension/singletons/TradeMenu.cpp b/extension/src/openvic-extension/singletons/TradeMenu.cpp index cfa6f2b9..e943c7fb 100644 --- a/extension/src/openvic-extension/singletons/TradeMenu.cpp +++ b/extension/src/openvic-extension/singletons/TradeMenu.cpp @@ -26,7 +26,7 @@ Dictionary MenuSingleton::get_trade_menu_good_categories_info() const { GoodInstanceManager const& good_instance_manager = instance_manager->get_good_instance_manager(); GoodDefinitionManager const& good_definition_manager = good_instance_manager.get_good_definition_manager(); - CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country_untracked(); Dictionary ret; @@ -130,7 +130,7 @@ Dictionary MenuSingleton::get_trade_menu_trade_details_info( instance_manager->get_good_instance_manager().get_good_instance_by_index(trade_detail_good_index); ERR_FAIL_NULL_V(good_instance, {}); - CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country_untracked(); Dictionary ret; @@ -197,7 +197,7 @@ Dictionary MenuSingleton::get_trade_menu_tables_info() const { ERR_FAIL_NULL_V(instance_manager, {}); GoodInstanceManager const& good_instance_manager = instance_manager->get_good_instance_manager(); - CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country(); + CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country_untracked(); Dictionary ret; @@ -327,5 +327,5 @@ Dictionary MenuSingleton::get_trade_menu_tables_info() const { float MenuSingleton::calculate_trade_menu_stockpile_cutoff_amount(GUIScrollbar const* slider) { ERR_FAIL_NULL_V(slider, 0.0f); - return calculate_trade_menu_stockpile_cutoff_amount_fp(slider->get_value_scaled_fp()); + return calculate_trade_menu_stockpile_cutoff_amount_fp(slider->get_scaled_value_untracked()); } diff --git a/game/src/UI/Session/BudgetMenu.gd b/game/src/UI/Session/BudgetMenu.gd index c6462456..34ed9988 100644 --- a/game/src/UI/Session/BudgetMenu.gd +++ b/game/src/UI/Session/BudgetMenu.gd @@ -74,6 +74,10 @@ func _ready() -> void: _update_info() +func _process(_delta : float) -> void: + if visible: + MenuSingleton.update_budget_menu_cpp() + func _notification(what : int) -> void: match what: NOTIFICATION_TRANSLATION_CHANGED: