#ifndef GAME_ROOT_HPP #define GAME_ROOT_HPP #include "game_mode.hpp" #include "level.hpp" #include #include #include #include #include #include #include namespace godot { class PlayerInput; class IPlayer; class SpawnPoint3D; 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_input_connected(); // force-disconnect a player // calls queue_free on the IPlayer instance void remove_player(uint32_t player_id); // calls remove_player for every used player input slot void remove_all_players(); // initialize and register a player instance // the player will be added to the tree and AFTER setup_player_input will be called // this way the player can initialize before setting up input 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); Ref get_game_mode() const; Ref get_game_state() const; 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; virtual IPlayer *spawn_player(uint32_t id); protected: static GameRoot *singleton_instance; uint32_t next_player_id{1}; // 0 is the "invalid" player id HashMap> players{}; Ref game_mode{}; }; class GameRoot3D : public GameRoot { GDCLASS(GameRoot3D, 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; static bool is_valid_level(Ref &level); private: HashMap levels{}; HashSet spawn_points{}; Ref first_boot_level{}; }; } #endif // !GAME_ROOT_HPP