summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-12-03 16:33:52 -0500
committerJonathan Bradley <jcb@pikum.xyz>2025-12-03 16:33:52 -0500
commite0922bfbba791549c96e33a33e69f488bf5009fc (patch)
tree8fa2d934f09aa8200de031b71b1c7503e9f4be52
parent4c28646a9a8ca092ca0307b5429fb842bd17bd55 (diff)
pke: tear down levels + settle ECS before shutdown
-rw-r--r--src/game.cpp43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/game.cpp b/src/game.cpp
index 01aba10..f56e129 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -86,7 +86,7 @@ void Game_Tick(double delta) {
}
}
- if (pkeSettings.rt.activeLevel->pke_cb_tick.func != nullptr) {
+ if (pkeSettings.rt.activeLevel && pkeSettings.rt.activeLevel->pke_cb_tick.func != nullptr) {
reinterpret_cast<void(*)(double delta)>(pkeSettings.rt.activeLevel->pke_cb_tick.func)(delta);
}
@@ -260,6 +260,47 @@ void pke_game_main_run() {
void pke_game_main_teardown() {
fprintf(stdout, "[%s] pke_game_main_teardown Entering.\n", __FILE__);
+ // tear down any loaded levels
+ if (pkeSettings.rt.nextLevel != nullptr) {
+ if (pkeSettings.rt.nextLevel->pke_cb_teardown.func != nullptr) {
+ pkeSettings.rt.nextLevel->pke_cb_teardown.func();
+ }
+ pke_level_teardown(pkeSettings.rt.nextLevel);
+ pkeSettings.rt.nextLevel = nullptr;
+ }
+ if (pkeSettings.rt.activeLevel != nullptr) {
+ if (pkeSettings.rt.activeLevel->pke_cb_teardown.func != nullptr) {
+ pkeSettings.rt.activeLevel->pke_cb_teardown.func();
+ }
+ pke_level_teardown(pkeSettings.rt.activeLevel);
+ pkeSettings.rt.activeLevel = nullptr;
+ }
+ if (pkeSettings.rt.previousLevel != nullptr) {
+ if (pkeSettings.rt.previousLevel->pke_cb_teardown.func != nullptr) {
+ pkeSettings.rt.previousLevel->pke_cb_teardown.func();
+ }
+ pke_level_teardown(pkeSettings.rt.previousLevel);
+ pkeSettings.rt.previousLevel = nullptr;
+ }
+
+ // Tick until entities have settled.
+ // This allows things like nested entities (static_ui) to flush out.
+ // Without this, plugins will have their OnTeardown called before the engine
+ // has had a chance to free anything active.
+ // Example: player input LIFO error if a loaded level had an active set.
+ pk_bkt_arr *bkt_arr_ents = ECS_GetEntities();
+ pk_bkt_arr_handle settle_handle_l = pk_bkt_arr_handle_MAX;
+ pk_bkt_arr_handle settle_handle_r = pk_bkt_arr_handle_MAX;
+ pk_bkt_arr_handle settle_handle_ll = bkt_arr_ents->head_l;
+ pk_bkt_arr_handle settle_handle_rr = bkt_arr_ents->head_r;
+ while (settle_handle_ll != settle_handle_l && settle_handle_rr != settle_handle_r) {
+ Game_Tick(0.f);
+ settle_handle_l = settle_handle_ll;
+ settle_handle_r = settle_handle_rr;
+ settle_handle_ll = bkt_arr_ents->head_l;
+ settle_handle_rr = bkt_arr_ents->head_r;
+ }
+
fprintf(stdout, "Game_Main SHUTDOWN INITIATED\n");
#ifndef NDEBUG
// TODO debug print buckets before shutdown