#ifndef GAME_ROOT_HPP #define GAME_ROOT_HPP #include #include #include #include #include #include #include #include "game_mode.hpp" #include "level.hpp" namespace godot { class PlayerInput; class IPlayer; class SpawnPoint3D; class GameRoot : public Node { GDCLASS(GameRoot, Node); static void _bind_methods(); public: static GameRoot *get_singleton(); static bool has_singleton(); virtual void _enter_tree() override; virtual void _exit_tree() override; void player_connected(); void player_disconnected(uint32_t player_id); bool initialize_player(IPlayer *player, uint32_t id); void reset_game_mode(); protected: void grab_singleton(); 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; 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; Level3D *load_level(Ref level); Level3D *load_level_at(Ref level, Transform3D at); void register_spawn_point(SpawnPoint3D *spawn_point); void unregister_spawn_point(SpawnPoint3D *spawn_point); 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{}; HashSet spawn_points{}; Ref first_boot_level{}; }; } #endif // !GAME_ROOT_HPP