Skip to content

Commit 483ea26

Browse files
committed
Unlink BudgetMenu instances before one is invalidated
1 parent 6a49e69 commit 483ea26

4 files changed

Lines changed: 30 additions & 3 deletions

File tree

extension/doc_classes/MenuSingleton.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@
255255
<description>
256256
</description>
257257
</method>
258+
<method name="unlink_budget_menu_from_cpp">
259+
<return type="void" />
260+
<description>
261+
</description>
262+
</method>
258263
<method name="update_search_results">
259264
<return type="void" />
260265
<param index="0" name="text" type="String" />

extension/src/openvic-extension/singletons/MenuSingleton.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ void MenuSingleton::_bind_methods() {
446446

447447
/* BUDGET MENU */
448448
OV_BIND_METHOD(MenuSingleton::link_budget_menu_to_cpp, { "godot_budget_menu" });
449+
OV_BIND_METHOD(MenuSingleton::unlink_budget_menu_from_cpp);
449450

450451
/* Find/Search Panel */
451452
OV_BIND_METHOD(MenuSingleton::generate_search_cache);
@@ -1539,9 +1540,15 @@ String MenuSingleton::get_longform_date() const {
15391540
void MenuSingleton::link_budget_menu_to_cpp(GUINode const* const godot_budget_menu) {
15401541
ERR_FAIL_NULL(godot_budget_menu);
15411542
GameSingleton& game_singleton = *GameSingleton::get_singleton();
1542-
BudgetMenu* old_instance = budget_menu.get();
1543-
if (old_instance != nullptr) {
1544-
game_singleton.gamestate_updated.disconnect(&BudgetMenu::update, old_instance);
1543+
1544+
if (budget_menu) {
1545+
UtilityFunctions::push_error(
1546+
"Trying to link new C++ and GDScript BudgetMenu instances without unlinking the old instances first! "
1547+
"The unlinking must happen just before the GDScript BudgetMenu is freed, "
1548+
"otherwise the C++ BudgetMenu will continue running despite all its UI node pointers now being invalid."
1549+
);
1550+
1551+
unlink_budget_menu_from_cpp();
15451552
}
15461553

15471554
auto const& strata_keys = game_singleton.get_definition_manager().get_pop_manager().get_stratas();
@@ -1556,6 +1563,15 @@ void MenuSingleton::link_budget_menu_to_cpp(GUINode const* const godot_budget_me
15561563
game_singleton.gamestate_updated.connect(&BudgetMenu::update, budget_menu.get());
15571564
}
15581565

1566+
void MenuSingleton::unlink_budget_menu_from_cpp() {
1567+
if (budget_menu) {
1568+
GameSingleton::get_singleton()->gamestate_updated.disconnect(&BudgetMenu::update, budget_menu.get());
1569+
budget_menu.reset();
1570+
} else {
1571+
UtilityFunctions::push_warning("unlink_budget_menu_from_cpp called but no C++ BudgetMenu instance was linked!");
1572+
}
1573+
}
1574+
15591575
/* Find/Search Panel */
15601576

15611577
Error MenuSingleton::generate_search_cache() {

extension/src/openvic-extension/singletons/MenuSingleton.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ namespace OpenVic {
287287

288288
/* BUDGET MENU */
289289
void link_budget_menu_to_cpp(GUINode const* const godot_budget_menu);
290+
void unlink_budget_menu_from_cpp();
290291

291292
/* Find/Search Panel */
292293
// TODO - update on country government type change and state creation/destruction

game/src/UI/Session/BudgetMenu.gd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ func _notification(what : int) -> void:
7878
match what:
7979
NOTIFICATION_TRANSLATION_CHANGED:
8080
_update_info()
81+
NOTIFICATION_PREDELETE:
82+
# If the C++ BudgetMenu isn't freed before the destruction of this GUINode, then its update method, triggered by
83+
# gamestate updates, could be called after all the child UI nodes they refer to have been freed,
84+
# meaning the C++ BudgetMenu would be dereferencing invalid pointers.
85+
MenuSingleton.unlink_budget_menu_from_cpp()
8186

8287
func _on_update_active_nation_management_screen(active_screen : NationManagement.Screen) -> void:
8388
_active = active_screen == SCREEN

0 commit comments

Comments
 (0)