diff --git a/game_root.cpp b/game_root.cpp index e0b5ce2..e082933 100644 --- a/game_root.cpp +++ b/game_root.cpp @@ -34,7 +34,7 @@ bool GameRoot::has_singleton() { void GameRoot::_enter_tree() { GDGAMEONLY(); // TODO: Replace this with detecting input devices if(this->players.is_empty()) { - this->player_connected(); + this->player_input_connected(); } this->grab_singleton(); } @@ -43,14 +43,14 @@ void GameRoot::_exit_tree() { GDGAMEONLY(); this->release_singleton(); } -void GameRoot::player_connected() { +void GameRoot::player_input_connected() { PlayerInput *input = memnew(PlayerInput); this->add_child(input); this->players.insert(this->next_player_id++, {input, nullptr}); this->emit_signal(StringName("player_connected"), input); } -void GameRoot::player_disconnected(uint32_t player_id) { +void GameRoot::player_removed(uint32_t player_id) { if(!this->players.has(player_id)) return; this->players.get(player_id).second = nullptr; @@ -106,13 +106,15 @@ void GameRoot::set_game_mode(Ref prototype) { node->queue_free(); } } + // allow "unsetting" the gamemode by passing an invalid gamemode + // shorthand for this behaviour is reset_game_mode if(prototype.is_null() || !prototype.is_valid()) { this->game_mode.unref(); return; } - // create new gamemode instance + // shallow clone the game mode prototype .. this->game_mode = prototype->duplicate(false); - // copy the game state from the prototype + // .. except for the game state, which should be cloned as well this->game_mode->set_game_state(prototype->get_game_state()->duplicate(false)); uint32_t new_player_id = this->find_empty_player_slot(); do { diff --git a/game_root.hpp b/game_root.hpp index bee96a2..b632b6b 100644 --- a/game_root.hpp +++ b/game_root.hpp @@ -20,22 +20,34 @@ class GameRoot : public Node { GDCLASS(GameRoot, Node); static void _bind_methods(); public: + // get the current active singleton instance of GameRoot static GameRoot *get_singleton(); + // returns true if there is currently a singleton active for GameRoot static bool has_singleton(); virtual void _enter_tree() override; virtual void _exit_tree() override; - void player_connected(); - void player_disconnected(uint32_t player_id); + void player_input_connected(); + // force-disconnect a player + // calls queue_free on the IPlayer instance + void player_removed(uint32_t player_id); + // initialize and register a player instance bool initialize_player(IPlayer *player, uint32_t id); + // shorthand for set_game_mode(Ref()) + // unsets the gamemode void reset_game_mode(); + // override the current gamemode + // force-respawns all players + void set_game_mode(Ref prototype); protected: + // attempt to make 'this' the current singleton instance void grab_singleton(); + // attempt to stop being the active singleton instance + // only works if the current singleton is 'this' void release_singleton(); uint32_t find_empty_player_slot() const; - void set_game_mode(Ref prototype); virtual IPlayer *spawn_player(uint32_t id); protected: static GameRoot *singleton_instance; @@ -50,17 +62,22 @@ class GameRoot3D : public GameRoot { static void _bind_methods(); public: virtual void _ready() override; + // shorthand for load_level(level, Transform3D()) Level3D *load_level(Ref level); + // 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); + // register a spawnpoint for use when spawning players void register_spawn_point(SpawnPoint3D *spawn_point); + // remove a spawnpoint so it can't be used to spawn players void unregister_spawn_point(SpawnPoint3D *spawn_point); + // ----- getter / setters ----- void set_first_boot_level(Ref level); Ref get_first_boot_level() const; protected: virtual IPlayer *spawn_player(uint32_t id) override; -private: static bool is_valid_level(Ref &level); private: HashMap levels{};