summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-11-07 11:43:56 -0500
committerJonathan Bradley <jcb@pikum.xyz>2025-11-07 12:26:15 -0500
commitc3c4d351f8ccfc678aaa2de458326a11884aef19 (patch)
tree11c74d89da371667858f17139df55896a3ade67c
parent5da699cff8a39bf1dc41b2d302c3e9c202496971 (diff)
pke: split up Game_Main and pass plugins to init
-rw-r--r--editor/editor.cpp1
-rw-r--r--src/game.cpp335
-rw-r--r--src/game.hpp10
-rw-r--r--src/window.cpp45
-rw-r--r--tests/pke-test-load-unload.cpp2
5 files changed, 214 insertions, 179 deletions
diff --git a/editor/editor.cpp b/editor/editor.cpp
index 2c66c8c..2a53b61 100644
--- a/editor/editor.cpp
+++ b/editor/editor.cpp
@@ -2233,7 +2233,6 @@ void PkeEditor_RecordImGui() {
RecordImGuiEntityTypes();
RecordImGuiAssets();
RecordImGuiPlayerInput();
- Game_RecordImGui();
}
}
diff --git a/src/game.cpp b/src/game.cpp
index c4a023d..01aba10 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -31,44 +31,12 @@
#include <fstream>
#include <thread>
-const char *levelName = "demo-level";
+void Game_Init();
+void Game_Tick(double delta);
+void Game_Teardown();
+void Game_RecordImGui();
-const int64_t consoleBufferCount = 30;
-const int64_t consoleLineLength = 128;
-char consoleBuffer[consoleBufferCount][consoleLineLength];
-int64_t consoleBufferIndex = 0;
-void Game_RecordImGui() {
- static bool scrollToBottom = true;
- if (!ImGui::Begin("Console", &pkeSettings.editorSettings.isShowingConsole)) {
- ImGui::End();
- return;
- }
- ImVec2 region = ImGui::GetContentRegionAvail();
- region.y -= 27;
- if (ImGui::BeginListBox("##ConsoleHistory", region)) {
- for (int64_t i = consoleBufferIndex + 1; i < consoleBufferCount; ++i) {
- ImGui::Text("%s", consoleBuffer[i]);
- }
- for (int64_t i = 0; i < consoleBufferIndex; ++i) {
- ImGui::Text("%s", consoleBuffer[i]);
- }
- if (scrollToBottom) ImGui::SetScrollHereY(1);
- scrollToBottom = false;
- ImGui::EndListBox();
- }
- ImGui::Separator();
- if (ImGui::InputText("##ConsoleInput", consoleBuffer[consoleBufferIndex], consoleLineLength, ImGuiInputTextFlags_EnterReturnsTrue)) {
- // TODO parse and execute.
- scrollToBottom = true;
- consoleBufferIndex = (consoleBufferIndex + 1) % consoleBufferCount;
- memset(consoleBuffer[consoleBufferIndex], '\0', consoleLineLength);
- }
- auto focusedFlags = (ImGuiFocusedFlags_ChildWindows);
- if (ImGui::IsWindowFocused(focusedFlags) && !ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemHovered() && !ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseClicked(ImGuiMouseButton_Left, true)) {
- ImGui::SetKeyboardFocusHere(-1);
- }
- ImGui::End();
-}
+const char *levelName = "demo-level";
void Game_Tick(double delta) {
pk_mem_bucket_reset(pkeSettings.mem_bkt.game_transient);
@@ -132,161 +100,171 @@ void Game_Tick(double delta) {
window_tick_late(delta);
}
-void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
+void pke_game_main_init(PKEWindowProperties windowProps, const char *executablePath, PKEPluginInterface *plugins, unsigned int n_plugins) {
+ fprintf(stdout, "[%s] pke_game_main_init Entering.\n", __FILE__);
+ unsigned int u;
+
pkeSettings.executablePath = executablePath;
- fprintf(stdout, "Game_Main Entering\n");
- try {
- Game_Init();
- pk_ev_init(pkeSettings.mem_bkt.game);
- PkeThreads_Init();
- AM_Init();
- ECS_Init();
- Physics_Init();
- pke_audio_init();
- PkeCamera_Init();
- pke_level_init();
- pke_scene_master_init();
- CreateWindow(windowProps);
- EntityType_Init();
- pke_input_init();
- FontType_Init();
- pke_ui_init();
- pke_ui_init_bindings();
- PkeProject_Load(pkeSettings.args.projectPath);
- if (pkeSettings.args.pluginPath != nullptr) {
- PkePlugin_Load(pkeSettings.args.pluginPath);
- }
- for (long i = 0; i < LoadedPkePlugins.next; ++i) {
- if (LoadedPkePlugins[i].OnInit != nullptr) {
- LoadedPkePlugins[i].OnInit();
- }
+
+ Game_Init();
+ pk_ev_init(pkeSettings.mem_bkt.game);
+ PkeThreads_Init();
+ AM_Init();
+ ECS_Init();
+ Physics_Init();
+ pke_audio_init();
+ PkeCamera_Init();
+ pke_level_init();
+ pke_scene_master_init();
+ CreateWindow(windowProps);
+ EntityType_Init();
+ pke_input_init();
+ FontType_Init();
+ pke_ui_init();
+ pke_ui_init_bindings();
+ PkeProject_Load(pkeSettings.args.projectPath);
+ if (pkeSettings.args.pluginPath != nullptr) {
+ PkePlugin_Load(pkeSettings.args.pluginPath);
+ }
+ for (u = 0; u < n_plugins; ++u) {
+ pk_arr_append_t<PKEPluginInterface>(&LoadedPkePlugins, plugins[u]);
+ }
+ for (u = 0; u < LoadedPkePlugins.next; ++u) {
+ if (LoadedPkePlugins[u].OnInit != nullptr) {
+ LoadedPkePlugins[u].OnInit();
}
+ }
- //
- // at this point, everything is loaded or initialized.
- //
+ fprintf(stdout, "[%s] pke_game_main_init Exiting.\n", __FILE__);
+}
- // if we were passed only a scene name, create a faux level.
- if (!pkeSettings.args.levelName) {
- // TODO uuids
- pke_level *lvl = pke_level_create("faux-level", pk_uuid_zed, pk_uuid_zed);
- fprintf(stdout, "[Game_Main] Creating faux level.\n");
- pkeSettings.rt.activeLevel = lvl;
- }
+void pke_game_main_load() {
+ fprintf(stdout, "[%s] pke_game_main_load Entering.\n", __FILE__);
- if (pkeSettings.args.levelName == nullptr && pkeSettings.args.sceneName != nullptr) {
- scene_instance si{};
- pke_scene *scene;
- std::ifstream f(pkeSettings.args.sceneName);
- if (!f.is_open()) {
- fprintf(stdout, "[Game_Main] Did not find scene by name specified in arg: '%s'\n", pkeSettings.args.sceneName);
- goto GAME_SHUTDOWN;
- }
- fprintf(stdout, "[Game_Main] loading scene from arg (expecting path): %s\n", pkeSettings.args.sceneName);
- srlztn_deserialize_helper *h = pke_deserialize_init(pkeSettings.rt.activeLevel, pkeSettings.mem_bkt.game_transient);
- // 2025-09-09 JCB Scenes no longer contain anything so I'm not sure there's a reason to create one here.
- // spit-balling here, maybe "scene" files should be assets and not much more.
- scene = pke_scene_create(pkeSettings.args.sceneName);
- pke_deserialize_scene_from_stream(f, h);
- pke_deserialize_scene(h);
- pke_deserialize_teardown(h);
- si.scene_handle = scene->scene_handle;
- pk_arr_append_t(&pkeSettings.rt.activeLevel->scene_instances, si);
+ // if we were passed only a scene name, create a faux level.
+ if (!pkeSettings.args.levelName) {
+ // TODO uuids
+ pke_level *lvl = pke_level_create("faux-level", pk_uuid_zed, pk_uuid_zed);
+ fprintf(stdout, "[%s] pke_game_main_load Creating faux level.\n", __FILE__);
+ pkeSettings.rt.activeLevel = lvl;
+ }
+
+ if (pkeSettings.args.levelName == nullptr && pkeSettings.args.sceneName != nullptr) {
+ scene_instance si{};
+ pke_scene *scene;
+ std::ifstream f(pkeSettings.args.sceneName);
+ if (!f.is_open()) {
+ fprintf(stdout, "[%s] pke_game_main_load Did not find scene by name specified in arg: '%s'\n", __FILE__, pkeSettings.args.sceneName);
+ exit(1);
}
+ fprintf(stdout, "[%s] pke_game_main_load loading scene from arg (expecting path): %s\n", __FILE__, pkeSettings.args.sceneName);
+ srlztn_deserialize_helper *h = pke_deserialize_init(pkeSettings.rt.activeLevel, pkeSettings.mem_bkt.game_transient);
+ // 2025-09-09 JCB Scenes no longer contain anything so I'm not sure there's a reason to create one here.
+ // spit-balling here, maybe "scene" files should be assets and not much more.
+ scene = pke_scene_create(pkeSettings.args.sceneName);
+ pke_deserialize_scene_from_stream(f, h);
+ pke_deserialize_scene(h);
+ pke_deserialize_teardown(h);
+ si.scene_handle = scene->scene_handle;
+ pk_arr_append_t(&pkeSettings.rt.activeLevel->scene_instances, si);
+ }
- GameTimePoint lastTimePoint = pkeSettings.steadyClock.now();
- double deltaTillNextRender = pkeSettings.deltaPerFrame;
- GameTimePoint lastLogTimePoint = pkeSettings.steadyClock.now();
- int64_t tickCount = 0;
- int64_t renderCount = 0;
+ fprintf(stdout, "[%s] pke_game_main_load Exiting.\n", __FILE__);
+}
- int64_t nsAhead = 0.0;
+void pke_game_main_run() {
+ fprintf(stdout, "[%s] pke_game_main_run Entering.\n", __FILE__);
- while (pkeSettings.isGameRunning) {
+ GameTimePoint lastTimePoint = pkeSettings.steadyClock.now();
+ double deltaTillNextRender = pkeSettings.deltaPerFrame;
+ GameTimePoint lastLogTimePoint = pkeSettings.steadyClock.now();
+ int64_t tickCount = 0;
+ int64_t renderCount = 0;
- glfwPollEvents();
+ int64_t nsAhead = 0.0;
- int64_t nsAheadHolder = 0.0;
- if (nsAhead > 0) {
- nsAheadHolder = nsAhead;
- std::this_thread::sleep_for(GameTimeDuration(nsAhead));
- nsAhead = 0;
- }
- if (vidMode.refreshRate != pkeSettings.targetFPS) {
- pkeSettings.targetFPS = vidMode.refreshRate;
- pkeSettings.deltaPerFrame = 1 / double(pkeSettings.targetFPS);
- }
+ while (pkeSettings.isGameRunning) {
- GameTimePoint currentTimePoint = pkeSettings.steadyClock.now();
- double deltaThisTick = ((currentTimePoint - lastTimePoint).count() - nsAheadHolder) / NANO_DENOM_DOUBLE;
- deltaThisTick = std::min(deltaThisTick, pkeSettings.minimumDeltaPerFrame);
- lastTimePoint = currentTimePoint;
-
- deltaTillNextRender -= deltaThisTick;
- bool shouldRender = pkeSettings.graphicsSettings.isFramerateUnlocked
- || pkeSettings.graphicsSettings.isWaitingForVsync
- || deltaTillNextRender <= 0.0;
-
- if (shouldRender == false && (deltaTillNextRender > 0.0 && deltaTillNextRender - (deltaThisTick * 2.0) <= 0.0)) {
- /*
- * We are ahead of the render schedule
- * && the current tick's speed would put us behind schedule next tick.
- * Simulate the extra time we are ahead and prepare to sleep the difference
- * before the next tick.
- */
- nsAhead = std::floor(deltaTillNextRender * NANO_DENOM_DOUBLE);
- deltaThisTick += deltaTillNextRender;
- shouldRender = true;
- }
+ glfwPollEvents();
- tickCount += 1;
- Game_Tick(deltaThisTick);
-
- pkeSettings.rt.was_framebuffer_resized = false;
- if (shouldRender) {
- Render();
- renderCount += 1;
- double msBehind = deltaTillNextRender * -1000;
- int64_t behindCount = 0;
- while (deltaTillNextRender < pkeSettings.deltaPerFrame) {
- behindCount += 1;
- deltaTillNextRender += pkeSettings.deltaPerFrame;
- }
- if (behindCount > 2) {
- fprintf(stderr, "[PKE::main] late render - simulated ahead: %fms - delta behind: %fms - missed frames:%ld\n", nsAheadHolder / (NANO_DENOM_DOUBLE / 1000), msBehind, behindCount - 1);
- fflush(stderr);
- }
- }
+ int64_t nsAheadHolder = 0.0;
+ if (nsAhead > 0) {
+ nsAheadHolder = nsAhead;
+ std::this_thread::sleep_for(GameTimeDuration(nsAhead));
+ nsAhead = 0;
+ }
+ if (vidMode.refreshRate != pkeSettings.targetFPS) {
+ pkeSettings.targetFPS = vidMode.refreshRate;
+ pkeSettings.deltaPerFrame = 1 / double(pkeSettings.targetFPS);
+ }
- pkeSettings.stats.last_deltas[0] = pkeSettings.stats.last_deltas[1];
- pkeSettings.stats.last_deltas[1] = pkeSettings.stats.last_deltas[2];
- pkeSettings.stats.last_deltas[2] = deltaThisTick;
- pkeSettings.stats.tick_rate = 3.L / (pkeSettings.stats.last_deltas[0] + pkeSettings.stats.last_deltas[1] + pkeSettings.stats.last_deltas[2]);
- if ((currentTimePoint - lastLogTimePoint).count() > std::chrono::nanoseconds::period::den) {
- lastLogTimePoint = currentTimePoint;
- fprintf(stdout, "TPS: ~%.03f - actual:%ld - presents:%ld\n", pkeSettings.stats.tick_rate, tickCount, renderCount);
- fflush(stdout);
- tickCount = 0;
- renderCount = 0;
- }
+ GameTimePoint currentTimePoint = pkeSettings.steadyClock.now();
+ double deltaThisTick = ((currentTimePoint - lastTimePoint).count() - nsAheadHolder) / NANO_DENOM_DOUBLE;
+ deltaThisTick = std::min(deltaThisTick, pkeSettings.minimumDeltaPerFrame);
+ lastTimePoint = currentTimePoint;
- pkeSettings.isGameRunning = !glfwWindowShouldClose(window);
+ deltaTillNextRender -= deltaThisTick;
+ bool shouldRender = pkeSettings.graphicsSettings.isFramerateUnlocked
+ || pkeSettings.graphicsSettings.isWaitingForVsync
+ || deltaTillNextRender <= 0.0;
+
+ if (shouldRender == false && (deltaTillNextRender > 0.0 && deltaTillNextRender - (deltaThisTick * 2.0) <= 0.0)) {
+ /*
+ * We are ahead of the render schedule
+ * && the current tick's speed would put us behind schedule next tick.
+ * Simulate the extra time we are ahead and prepare to sleep the difference
+ * before the next tick.
+ */
+ nsAhead = std::floor(deltaTillNextRender * NANO_DENOM_DOUBLE);
+ deltaThisTick += deltaTillNextRender;
+ shouldRender = true;
}
- vkDeviceWaitIdle(vkDevice);
+ tickCount += 1;
+ Game_Tick(deltaThisTick);
+
+ pkeSettings.rt.was_framebuffer_resized = false;
+ if (shouldRender) {
+ Render();
+ renderCount += 1;
+ double msBehind = deltaTillNextRender * -1000;
+ int64_t behindCount = 0;
+ while (deltaTillNextRender < pkeSettings.deltaPerFrame) {
+ behindCount += 1;
+ deltaTillNextRender += pkeSettings.deltaPerFrame;
+ }
+ if (behindCount > 2) {
+ fprintf(stderr, "[PKE::main] late render - simulated ahead: %fms - delta behind: %fms - missed frames:%ld\n", nsAheadHolder / (NANO_DENOM_DOUBLE / 1000), msBehind, behindCount - 1);
+ fflush(stderr);
+ }
+ }
+
+ pkeSettings.stats.last_deltas[0] = pkeSettings.stats.last_deltas[1];
+ pkeSettings.stats.last_deltas[1] = pkeSettings.stats.last_deltas[2];
+ pkeSettings.stats.last_deltas[2] = deltaThisTick;
+ pkeSettings.stats.tick_rate = 3.L / (pkeSettings.stats.last_deltas[0] + pkeSettings.stats.last_deltas[1] + pkeSettings.stats.last_deltas[2]);
+ if ((currentTimePoint - lastLogTimePoint).count() > std::chrono::nanoseconds::period::den) {
+ lastLogTimePoint = currentTimePoint;
+ fprintf(stdout, "TPS: ~%.03f - actual:%ld - presents:%ld\n", pkeSettings.stats.tick_rate, tickCount, renderCount);
+ fflush(stdout);
+ tickCount = 0;
+ renderCount = 0;
+ }
- } catch (const std::exception &exc) {
- fprintf(stderr, "Game_Main EXCEPTION: %s\n", exc.what());
- } catch (const char *err) {
- fprintf(stderr, "Game_Main UNHANDLED EXCEPTION: %s\n", err);
- } catch (...) {
- fprintf(stderr, "Game_Main UNHANDLED EXCEPTION\n");
+ pkeSettings.isGameRunning = !glfwWindowShouldClose(window);
}
-GAME_SHUTDOWN:
+
+ fprintf(stdout, "[%s] pke_game_main_run Exiting.\n", __FILE__);
+}
+
+void pke_game_main_teardown() {
+ fprintf(stdout, "[%s] pke_game_main_teardown Entering.\n", __FILE__);
+
fprintf(stdout, "Game_Main SHUTDOWN INITIATED\n");
#ifndef NDEBUG
// TODO debug print buckets before shutdown
#endif
+ vkDeviceWaitIdle(vkDevice);
for (long i = 0; i < LoadedPkePlugins.next; ++i) {
if (LoadedPkePlugins[i].OnTeardown) {
LoadedPkePlugins[i].OnTeardown();
@@ -310,17 +288,26 @@ GAME_SHUTDOWN:
pk_ev_teardown();
Game_Teardown();
// TODO debug print buckets after shutdown
- fprintf(stdout, "Game_Main Exiting\n");
+
+ fprintf(stdout, "[%s] pke_game_main_teardown Exiting.\n", __FILE__);
+}
+
+void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
+
+ pke_game_main_init(windowProps, executablePath, nullptr, 0);
+
+ pke_game_main_load();
+
+ pke_game_main_run();
+
+ pke_game_main_teardown();
+
}
void Game_Init() {
pkeSettings.mem_bkt.game = pk_mem_bucket_create("game", 1UL << 26, PK_MEMBUCKET_FLAG_NONE);
pkeSettings.mem_bkt.game_transient = pk_mem_bucket_create("game-transient", 1UL << 26, PK_MEMBUCKET_FLAG_TRANSIENT);
pk_mem_bucket_set_client_mem_bucket(pkeSettings.mem_bkt.game);
-
- for (uint64_t i = 0; i < consoleBufferCount; ++i) {
- memset(consoleBuffer[i], '\0', consoleLineLength);
- }
}
void Game_Teardown() {
diff --git a/src/game.hpp b/src/game.hpp
index b879364..b599c24 100644
--- a/src/game.hpp
+++ b/src/game.hpp
@@ -1,12 +1,14 @@
#ifndef PKE_GAME_HPP
#define PKE_GAME_HPP
+#include "plugin-types.hpp"
#include "window-types.hpp"
void Game_Main(PKEWindowProperties windowProps, const char *executablePath);
-void Game_Init();
-void Game_Tick(double delta);
-void Game_Teardown();
-void Game_RecordImGui();
+
+void pke_game_main_init(PKEWindowProperties windowProps, const char *executablePath, PKEPluginInterface *interfaces = nullptr, unsigned int n_interfaces = 0);
+void pke_game_main_load();
+void pke_game_main_run();
+void pke_game_main_teardown();
#endif /* PKE_GAME_HPP */
diff --git a/src/window.cpp b/src/window.cpp
index 7a627d5..b93d8ab 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -165,6 +165,12 @@ UniformBufferObject UBO{
VkDeviceMemory uniformBufferMemory;
VkDeviceSize paddedUboBufferSize;
+// console
+const int64_t consoleBufferCount = 30;
+const int64_t consoleLineLength = 128;
+char consoleBuffer[consoleBufferCount][consoleLineLength];
+int64_t consoleBufferIndex = 0;
+
// public
VkBuffer *UniformBuffers;
DebugHitbox pkeDebugHitbox{};
@@ -3511,6 +3517,39 @@ void pkvk_transition_image_layout(VkCommandBuffer command_buffer,
vkCmdPipelineBarrier(command_buffer, src_stage_mask, dst_stage_mask, 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);
}
+void RecordImGui() {
+ static bool scrollToBottom = true;
+ if (!ImGui::Begin("Console", &pkeSettings.editorSettings.isShowingConsole)) {
+ ImGui::End();
+ return;
+ }
+ ImVec2 region = ImGui::GetContentRegionAvail();
+ region.y -= 27;
+ if (ImGui::BeginListBox("##ConsoleHistory", region)) {
+ for (int64_t i = consoleBufferIndex + 1; i < consoleBufferCount; ++i) {
+ ImGui::Text("%s", consoleBuffer[i]);
+ }
+ for (int64_t i = 0; i < consoleBufferIndex; ++i) {
+ ImGui::Text("%s", consoleBuffer[i]);
+ }
+ if (scrollToBottom) ImGui::SetScrollHereY(1);
+ scrollToBottom = false;
+ ImGui::EndListBox();
+ }
+ ImGui::Separator();
+ if (ImGui::InputText("##ConsoleInput", consoleBuffer[consoleBufferIndex], consoleLineLength, ImGuiInputTextFlags_EnterReturnsTrue)) {
+ // TODO parse and execute.
+ scrollToBottom = true;
+ consoleBufferIndex = (consoleBufferIndex + 1) % consoleBufferCount;
+ memset(consoleBuffer[consoleBufferIndex], '\0', consoleLineLength);
+ }
+ auto focusedFlags = (ImGuiFocusedFlags_ChildWindows);
+ if (ImGui::IsWindowFocused(focusedFlags) && !ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemHovered() && !ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseClicked(ImGuiMouseButton_Left, true)) {
+ ImGui::SetKeyboardFocusHere(-1);
+ }
+ ImGui::End();
+}
+
void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
uint32_t i, counter;
bool b;
@@ -3933,10 +3972,12 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
}
}
// TODO move this 'any' check to happen on plugin load and store in global?
+ // Note that drawing imgui requires a plugin is intentional
if (any) {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
+ RecordImGui();
for (uint32_t i = 0; i < LoadedPkePlugins.next; ++i) {
if (LoadedPkePlugins[i].OnImGuiRender != nullptr) {
LoadedPkePlugins[i].OnImGuiRender();
@@ -4214,6 +4255,10 @@ void CreateWindow(PKEWindowProperties wp) {
CreateImGui();
DetermineMonitor();
+
+ for (uint64_t i = 0; i < consoleBufferCount; ++i) {
+ memset(consoleBuffer[i], '\0', consoleLineLength);
+ }
}
void DestroyWindow() {
diff --git a/tests/pke-test-load-unload.cpp b/tests/pke-test-load-unload.cpp
index 61d901c..27c588a 100644
--- a/tests/pke-test-load-unload.cpp
+++ b/tests/pke-test-load-unload.cpp
@@ -23,6 +23,8 @@ extern pk_arr_t<EntityHandle> entitiesYetToBeRemoved;
static pk_membucket *bkt;
static pke_level *level_01;
+void Game_Tick(double);
+
void print_entities_marked_for_removal() {
bool b;
pk_iter_t<Entity_Base*> iter{};