2024-05-29 21:05:39 +00:00
|
|
|
#ifndef UTILS_GAME_ROOT_HPP
|
|
|
|
#define UTILS_GAME_ROOT_HPP
|
2024-03-13 15:08:37 +00:00
|
|
|
|
2024-03-17 13:49:35 +00:00
|
|
|
#include "game_mode.hpp"
|
2024-05-29 15:36:17 +00:00
|
|
|
#include "game_state.hpp"
|
2024-03-17 13:49:35 +00:00
|
|
|
#include "level.hpp"
|
2024-03-13 15:08:37 +00:00
|
|
|
#include <godot_cpp/classes/node.hpp>
|
2024-03-17 13:49:35 +00:00
|
|
|
#include <godot_cpp/classes/packed_scene.hpp>
|
2024-05-28 14:28:36 +00:00
|
|
|
#include <godot_cpp/classes/random_number_generator.hpp>
|
2024-03-13 15:08:37 +00:00
|
|
|
#include <godot_cpp/templates/hash_map.hpp>
|
|
|
|
#include <godot_cpp/templates/hash_set.hpp>
|
|
|
|
#include <godot_cpp/templates/pair.hpp>
|
|
|
|
#include <godot_cpp/templates/pair.hpp>
|
2024-03-17 13:49:35 +00:00
|
|
|
#include <godot_cpp/templates/vector.hpp>
|
2024-03-13 15:08:37 +00:00
|
|
|
|
2024-05-28 14:28:36 +00:00
|
|
|
namespace gd = godot;
|
|
|
|
|
|
|
|
namespace utils {
|
2024-03-13 15:08:37 +00:00
|
|
|
class PlayerInput;
|
|
|
|
class IPlayer;
|
|
|
|
class SpawnPoint3D;
|
|
|
|
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! The root of a game.
|
|
|
|
*
|
|
|
|
* A game root node that manages levels and input devices.
|
|
|
|
* Can be loaded at any point in a game's life, but suggested is setting this as the root of the boot scene.
|
|
|
|
*/
|
2024-05-28 14:28:36 +00:00
|
|
|
class GameRoot3D : public gd::Node {
|
|
|
|
GDCLASS(GameRoot3D, gd::Node);
|
2024-03-13 15:08:37 +00:00
|
|
|
static void _bind_methods();
|
|
|
|
public:
|
2024-05-29 15:36:17 +00:00
|
|
|
//! get the current active singleton instance of GameRoot
|
2024-05-06 09:03:00 +00:00
|
|
|
static GameRoot3D *get_singleton();
|
2024-05-29 15:36:17 +00:00
|
|
|
//! returns true if there is currently a singleton active for GameRoot
|
2024-03-13 15:08:37 +00:00
|
|
|
static bool has_singleton();
|
|
|
|
|
|
|
|
virtual void _enter_tree() override;
|
2024-05-06 09:03:00 +00:00
|
|
|
virtual void _ready() override;
|
2024-03-13 15:08:37 +00:00
|
|
|
virtual void _exit_tree() override;
|
|
|
|
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Instantiate a new PlayerInput.
|
|
|
|
*
|
|
|
|
* Does not automatically spawn a new player, but does notify game mode.
|
|
|
|
*/
|
2024-03-16 21:12:11 +00:00
|
|
|
void player_input_connected();
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Force-disconnect a player
|
|
|
|
*
|
|
|
|
* Calls queue_free on the IPlayer instance
|
|
|
|
*/
|
2024-03-17 13:49:35 +00:00
|
|
|
void remove_player(uint32_t player_id);
|
|
|
|
// calls remove_player for every used player input slot
|
|
|
|
void remove_all_players();
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! 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
|
|
|
|
*/
|
2024-03-16 12:02:36 +00:00
|
|
|
bool initialize_player(IPlayer *player, uint32_t id);
|
2024-03-13 15:08:37 +00:00
|
|
|
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Un-set game mode.
|
2024-05-30 13:07:17 +00:00
|
|
|
* Shorthand for `set_game_mode(Ref<PackedScene>())`
|
2024-05-29 15:36:17 +00:00
|
|
|
*/
|
2024-03-13 15:08:37 +00:00
|
|
|
void reset_game_mode();
|
|
|
|
|
2024-05-29 15:36:17 +00:00
|
|
|
//! shorthand for load_level(level, Transform3D())
|
2024-05-28 14:28:36 +00:00
|
|
|
Level3D *load_level(gd::Ref<gd::PackedScene> level);
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Load a level, only works if 'level' is a valid scene where the root Node can cast to 'Level3D'.
|
|
|
|
*
|
|
|
|
* \param at Sets the root node's global transform.
|
|
|
|
*/
|
2024-05-28 14:28:36 +00:00
|
|
|
Level3D *load_level_at(gd::Ref<gd::PackedScene> level, gd::Transform3D at);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Unload all currently loaded levels.
|
2024-05-21 13:57:55 +00:00
|
|
|
void unload_all_levels();
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Replace all currently loaded levels with a new level.
|
|
|
|
*
|
|
|
|
* Shorthand for
|
|
|
|
* ```
|
|
|
|
* unload_all_levels();
|
|
|
|
* load_level(level);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-05-28 14:28:36 +00:00
|
|
|
void replace_levels(gd::Ref<gd::PackedScene> level);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Register a spawnpoint for use when spawning players
|
2024-03-13 15:08:37 +00:00
|
|
|
void register_spawn_point(SpawnPoint3D *spawn_point);
|
2024-03-16 21:12:11 +00:00
|
|
|
// remove a spawnpoint so it can't be used to spawn players
|
2024-03-13 15:08:37 +00:00
|
|
|
void unregister_spawn_point(SpawnPoint3D *spawn_point);
|
2024-04-16 09:45:46 +00:00
|
|
|
void place_player_at_spawnpoint(IPlayer *player);
|
2024-05-21 09:56:41 +00:00
|
|
|
void player_despawned(uint32_t id);
|
2024-03-13 15:08:37 +00:00
|
|
|
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Override the current gamemode.
|
|
|
|
*
|
|
|
|
* Replaces game mode requires destroying and respawning all players
|
|
|
|
*/
|
2024-05-30 13:07:17 +00:00
|
|
|
void set_game_mode(gd::Ref<gd::PackedScene> prototype);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! get the current active game mode.
|
|
|
|
GameMode *get_game_mode() const;
|
|
|
|
//! Get the current active game state.
|
|
|
|
GameState *get_game_state() const;
|
|
|
|
/*! Returns all currently active levels.
|
|
|
|
*
|
|
|
|
* Levels are identified by their packed scene path.
|
|
|
|
*/
|
2024-05-28 14:28:36 +00:00
|
|
|
gd::HashMap<gd::StringName, Level3D *> &get_levels();
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Get the player instance associated with id.
|
2024-05-23 13:55:47 +00:00
|
|
|
IPlayer *get_player(uint32_t id);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Get all players in a list.
|
2024-05-28 14:28:36 +00:00
|
|
|
gd::Vector<IPlayer*> get_players();
|
2024-05-29 15:36:17 +00:00
|
|
|
void set_first_boot_level(gd::Ref<gd::PackedScene> level);
|
|
|
|
gd::Ref<gd::PackedScene> get_first_boot_level() const;
|
|
|
|
void set_game_state_prototype(gd::Ref<GameState> game_state);
|
|
|
|
gd::Ref<GameState> get_game_state_prototype() const;
|
2024-05-30 13:42:53 +00:00
|
|
|
gd::RandomNumberGenerator &get_rng();
|
2024-03-16 12:02:36 +00:00
|
|
|
protected:
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Attempt to make 'this' the current singleton instance.
|
2024-05-06 09:03:00 +00:00
|
|
|
void grab_singleton();
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Attempt to stop being the active singleton instance.
|
|
|
|
*
|
|
|
|
* Only works if the current singleton is 'this'.
|
|
|
|
*/
|
2024-05-06 09:03:00 +00:00
|
|
|
void release_singleton();
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Find a Player Input device not yet associated with a player.
|
2024-05-06 09:03:00 +00:00
|
|
|
uint32_t find_empty_player_slot() const;
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Spawn a player to be associated with id.
|
2024-05-06 09:03:00 +00:00
|
|
|
IPlayer *spawn_player(uint32_t id);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Callback for a level exiting the tree.
|
2024-05-28 14:28:36 +00:00
|
|
|
void level_unloaded(gd::StringName scene_path);
|
2024-05-29 15:36:17 +00:00
|
|
|
//! Check if a scene is a valid level.
|
2024-05-28 14:28:36 +00:00
|
|
|
static bool is_valid_level(gd::Ref<gd::PackedScene> &level);
|
2024-05-29 15:36:17 +00:00
|
|
|
private:
|
2024-05-06 09:03:00 +00:00
|
|
|
static GameRoot3D *singleton_instance;
|
2024-05-30 13:42:53 +00:00
|
|
|
/*! Next available player ID.
|
|
|
|
*
|
|
|
|
* Default is 1 because 0 is the "invalid" player id.
|
|
|
|
*/
|
|
|
|
uint32_t next_player_id{1};
|
|
|
|
/*! All players by id by input device.
|
|
|
|
*
|
|
|
|
* `get_players()`
|
|
|
|
*/
|
|
|
|
gd::HashMap<uint32_t, gd::Pair<PlayerInput*, IPlayer*>> players{};
|
|
|
|
/*! Global random number generator.
|
|
|
|
*
|
|
|
|
* `&get_rng()`
|
|
|
|
*/
|
|
|
|
gd::RandomNumberGenerator rng{};
|
|
|
|
/*! All currently active levels.
|
|
|
|
*
|
|
|
|
* Each identified by their resource paths.
|
|
|
|
*
|
|
|
|
* `&get_levels()`
|
|
|
|
*/
|
|
|
|
gd::HashMap<gd::StringName, Level3D*> levels{};
|
|
|
|
/*! All currently available spawn points.
|
|
|
|
*/
|
|
|
|
gd::Vector<SpawnPoint3D*> spawn_points{};
|
|
|
|
/*! Current active gamemode.
|
|
|
|
*
|
|
|
|
* Replaced when a level is loaded that references a different game mode.
|
|
|
|
*
|
|
|
|
* `*get_game_mode()`
|
|
|
|
*/
|
|
|
|
GameMode *game_mode{};
|
2024-05-29 15:36:17 +00:00
|
|
|
/*! Active game state.
|
|
|
|
*
|
|
|
|
* Will be assigned loaded save data, or game_state_prototype if no save data is found.
|
2024-05-30 13:42:53 +00:00
|
|
|
*
|
|
|
|
* `*get_game_mode()`
|
2024-05-29 15:36:17 +00:00
|
|
|
*/
|
|
|
|
gd::Ref<GameState> game_state{};
|
2024-05-30 13:42:53 +00:00
|
|
|
/*! The level to boot into on startup.
|
|
|
|
*
|
|
|
|
* `get_first_boot_level()` `set_first_boot_level(value)`
|
|
|
|
*/
|
|
|
|
gd::Ref<gd::PackedScene> first_boot_level{};
|
|
|
|
/*! The default game state data.
|
|
|
|
*
|
|
|
|
* Duplicated and assigned to game_state if no save data is available.
|
|
|
|
*
|
|
|
|
* `get_game_state_prototype()` `set_game_state_prototype(value)`
|
|
|
|
*/
|
|
|
|
gd::Ref<GameState> game_state_prototype{};
|
2024-03-13 15:08:37 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-05-29 21:05:39 +00:00
|
|
|
#endif // !UTILS_GAME_ROOT_HPP
|