diff --git a/game_root.cpp b/game_root.cpp index 9cd20b8..bfb3e7d 100644 --- a/game_root.cpp +++ b/game_root.cpp @@ -112,6 +112,7 @@ Level3D *GameRoot3D::load_level_at(Ref level, Transform3D at) { return nullptr; } this->levels.insert(level->get_path(), instance); + instance->connect("tree_exited", callable_mp(this, &GameRoot3D::level_unloaded).bind(level->get_path())); // store and add to tree at desired transform // if this is the first level containing a game mode currently active use it's gamemode as a prototype bool const switch_game_mode{this->game_mode.is_null()}; @@ -120,7 +121,7 @@ Level3D *GameRoot3D::load_level_at(Ref level, Transform3D at) { } this->add_child(instance); instance->set_global_transform(at); - if(switch_game_mode) { + if(switch_game_mode && this->game_mode.is_valid()) { for(KeyValue> const &kvp : this->players) { this->place_player_at_spawnpoint(kvp.value.second); } @@ -128,6 +129,19 @@ Level3D *GameRoot3D::load_level_at(Ref level, Transform3D at) { return instance; } +void GameRoot3D::unload_all_levels() { + HashMap levels = this->get_levels(); + for(KeyValue &kvp : levels) + kvp.value->call_deferred("queue_free"); + this->get_levels().clear(); + this->reset_game_mode(); +} + +void GameRoot3D::replace_levels(Ref scene) { + this->unload_all_levels(); + this->load_level(scene); +} + void GameRoot3D::register_spawn_point(SpawnPoint3D *spawn_point) { if(this->spawn_points.has(spawn_point)) { UtilityFunctions::push_error("Duplicate attempt to register spawnpoint '", spawn_point->get_path(), "'"); @@ -258,6 +272,10 @@ IPlayer *GameRoot3D::spawn_player(uint32_t id) { return player; } +void GameRoot3D::level_unloaded(StringName scene_path) { + this->levels.erase(scene_path); +} + bool GameRoot3D::is_valid_level(Ref &level) { if(level.is_null() || !level.is_valid() || !level->can_instantiate()) { UtilityFunctions::push_error("Can't load level from invalid packed scene"); diff --git a/game_root.hpp b/game_root.hpp index d35894f..79c795a 100644 --- a/game_root.hpp +++ b/game_root.hpp @@ -49,6 +49,8 @@ public: // load a level, only works if 'level' is a valid scene where the root Node can cast to 'Level3D' // sets the level's root node's global transform Level3D *load_level_at(Ref level, Transform3D at); + void unload_all_levels(); + void replace_levels(Ref level); // register a spawnpoint for use when spawning players void register_spawn_point(SpawnPoint3D *spawn_point); @@ -74,6 +76,7 @@ protected: void release_singleton(); uint32_t find_empty_player_slot() const; IPlayer *spawn_player(uint32_t id); + void level_unloaded(StringName scene_path); static bool is_valid_level(Ref &level); protected: static GameRoot3D *singleton_instance;