feat: GameMode is now a Node rather than Resource
This commit is contained in:
		
							parent
							
								
									ec2c3fd835
								
							
						
					
					
						commit
						2ac9e8399f
					
				| 
						 | 
					@ -10,9 +10,6 @@ void GameMode::_bind_methods() {
 | 
				
			||||||
    GDPROPERTY_HINTED(player_scene, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
 | 
					    GDPROPERTY_HINTED(player_scene, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GameMode::_begin() {}
 | 
					 | 
				
			||||||
void GameMode::_end() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void GameMode::set_player_scene(gd::Ref<gd::PackedScene> scene) {
 | 
					void GameMode::set_player_scene(gd::Ref<gd::PackedScene> scene) {
 | 
				
			||||||
    this->player_scene = scene;
 | 
					    this->player_scene = scene;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,24 +1,21 @@
 | 
				
			||||||
#ifndef UTILS_GAME_MODE_HPP
 | 
					#ifndef UTILS_GAME_MODE_HPP
 | 
				
			||||||
#define UTILS_GAME_MODE_HPP
 | 
					#define UTILS_GAME_MODE_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <godot_cpp/classes/node.hpp>
 | 
				
			||||||
#include <godot_cpp/classes/packed_scene.hpp>
 | 
					#include <godot_cpp/classes/packed_scene.hpp>
 | 
				
			||||||
#include <godot_cpp/classes/resource.hpp>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace gd = godot;
 | 
					namespace gd = godot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace utils {
 | 
					namespace utils {
 | 
				
			||||||
/*! Stores session-relevant data.
 | 
					/*! Stores session-relevant data.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Contains any data that is only needed for the duration of the current session/match. Use GameState instead if you want data to be saved between sessions.
 | 
					 * Inheriting classes are intended to keep only data that is relevant for the duration of the current session/match. Use GameState instead if you want data to be saved between sessions.
 | 
				
			||||||
 * Will be destroyed when a level is loaded that does not match the same game mode class.
 | 
					 * Will be destroyed when a level is loaded that does not match the same game mode class.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class GameMode : public gd::Resource {
 | 
					class GameMode : public gd::Node {
 | 
				
			||||||
    GDCLASS(GameMode, gd::Resource);
 | 
					    GDCLASS(GameMode, gd::Node);
 | 
				
			||||||
    static void _bind_methods();
 | 
					    static void _bind_methods();
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    virtual void _begin(); //!< Called when the match begins.
 | 
					 | 
				
			||||||
    virtual void _end(); //!< Called when the match is ending.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void set_player_scene(gd::Ref<gd::PackedScene> scene);
 | 
					    void set_player_scene(gd::Ref<gd::PackedScene> scene);
 | 
				
			||||||
    gd::Ref<gd::PackedScene> get_player_scene() const;
 | 
					    gd::Ref<gd::PackedScene> get_player_scene() const;
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@ bool GameRoot3D::initialize_player(IPlayer *player, uint32_t id) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GameRoot3D::reset_game_mode() {
 | 
					void GameRoot3D::reset_game_mode() {
 | 
				
			||||||
    this->set_game_mode(gd::Ref<GameMode>());
 | 
					    this->set_game_mode(nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Level3D *GameRoot3D::load_level(gd::Ref<gd::PackedScene> level) {
 | 
					Level3D *GameRoot3D::load_level(gd::Ref<gd::PackedScene> level) {
 | 
				
			||||||
| 
						 | 
					@ -116,13 +116,15 @@ Level3D *GameRoot3D::load_level_at(gd::Ref<gd::PackedScene> level, gd::Transform
 | 
				
			||||||
    instance->connect("tree_exited", callable_mp(this, &GameRoot3D::level_unloaded).bind(level->get_path()));
 | 
					    instance->connect("tree_exited", callable_mp(this, &GameRoot3D::level_unloaded).bind(level->get_path()));
 | 
				
			||||||
    // store and add to tree at desired transform
 | 
					    // 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
 | 
					    // 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()};
 | 
					    gd::Ref<gd::PackedScene> game_mode_prototype{instance->get_game_mode_prototype()};
 | 
				
			||||||
 | 
					    bool const switch_game_mode{this->game_mode->get_scene_file_path() != game_mode_prototype->get_path()};
 | 
				
			||||||
    if(switch_game_mode) {
 | 
					    if(switch_game_mode) {
 | 
				
			||||||
        this->set_game_mode(instance->get_game_mode_prototype());
 | 
					        this->set_game_mode(instance->get_game_mode_prototype());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this->add_child(instance);
 | 
					    this->add_child(instance);
 | 
				
			||||||
    instance->set_global_transform(at);
 | 
					    instance->set_global_transform(at);
 | 
				
			||||||
    if(switch_game_mode && this->game_mode.is_valid()) {
 | 
					    // set initial player positions if new player were spawned due to game mode switch
 | 
				
			||||||
 | 
					    if(switch_game_mode && this->game_mode != nullptr) {
 | 
				
			||||||
        for(gd::KeyValue<uint32_t, gd::Pair<PlayerInput *, IPlayer *>> const &kvp : this->players) {
 | 
					        for(gd::KeyValue<uint32_t, gd::Pair<PlayerInput *, IPlayer *>> const &kvp : this->players) {
 | 
				
			||||||
            this->place_player_at_spawnpoint(kvp.value.second);
 | 
					            this->place_player_at_spawnpoint(kvp.value.second);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -172,19 +174,21 @@ void GameRoot3D::player_despawned(uint32_t id) {
 | 
				
			||||||
    pair.first->clear_listeners();
 | 
					    pair.first->clear_listeners();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GameRoot3D::set_game_mode(gd::Ref<GameMode> prototype) {
 | 
					void GameRoot3D::set_game_mode(gd::Ref<gd::PackedScene> prototype) {
 | 
				
			||||||
    this->remove_all_players();
 | 
					    this->remove_all_players();
 | 
				
			||||||
    // allow "unsetting" the gamemode by passing an invalid gamemode
 | 
					    if(this->game_mode != nullptr)
 | 
				
			||||||
    // shorthand for this behaviour is reset_game_mode
 | 
					        this->game_mode->queue_free();
 | 
				
			||||||
    if(prototype.is_null() || !prototype.is_valid()) {
 | 
					    if(prototype.is_null() || !prototype.is_valid())
 | 
				
			||||||
        if(!this->game_mode.is_null() && this->game_mode.is_valid())
 | 
					        return; // allow "unsetting" the gamemode by passing an invalid gamemode
 | 
				
			||||||
            this->game_mode->_end();
 | 
					    // Detect passing of valid scene that is an invalid game mode
 | 
				
			||||||
        this->game_mode.unref();
 | 
					    if(!gd::ClassDB::is_parent_class(prototype->get_state()->get_node_type(0), "GameMode")) {
 | 
				
			||||||
 | 
					        gd::UtilityFunctions::push_error("Attempted to load non-gamemode scene as gamemode");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // shallow clone the game mode prototype ..
 | 
					    // instantiate the game mode as a child
 | 
				
			||||||
    this->game_mode = prototype->duplicate(false);
 | 
					    this->game_mode = Object::cast_to<GameMode>(prototype->instantiate());
 | 
				
			||||||
    this->game_mode->_begin();
 | 
					    this->add_child(game_mode);
 | 
				
			||||||
 | 
					    // instantiate players
 | 
				
			||||||
    if(this->game_mode->get_player_scene().is_valid()) {
 | 
					    if(this->game_mode->get_player_scene().is_valid()) {
 | 
				
			||||||
        uint32_t new_player_id = this->find_empty_player_slot();
 | 
					        uint32_t new_player_id = this->find_empty_player_slot();
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
| 
						 | 
					@ -197,7 +201,7 @@ void GameRoot3D::set_game_mode(gd::Ref<GameMode> prototype) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GameMode *GameRoot3D::get_game_mode() const {
 | 
					GameMode *GameRoot3D::get_game_mode() const {
 | 
				
			||||||
    return this->game_mode.ptr();
 | 
					    return this->game_mode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GameState *GameRoot3D::get_game_state() const {
 | 
					GameState *GameRoot3D::get_game_state() const {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@ public:
 | 
				
			||||||
    bool initialize_player(IPlayer *player, uint32_t id);
 | 
					    bool initialize_player(IPlayer *player, uint32_t id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*! Un-set game mode.
 | 
					    /*! Un-set game mode.
 | 
				
			||||||
     * Shorthand for set_game_mode(Ref<GameMode>())
 | 
					     * Shorthand for `set_game_mode(Ref<PackedScene>())`
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void reset_game_mode();
 | 
					    void reset_game_mode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,7 @@ public:
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Replaces game mode requires destroying and respawning all players
 | 
					     * Replaces game mode requires destroying and respawning all players
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void set_game_mode(gd::Ref<GameMode> prototype);
 | 
					    void set_game_mode(gd::Ref<gd::PackedScene> prototype);
 | 
				
			||||||
    //! get the current active game mode.
 | 
					    //! get the current active game mode.
 | 
				
			||||||
    GameMode *get_game_mode() const;
 | 
					    GameMode *get_game_mode() const;
 | 
				
			||||||
    //! Get the current active game state.
 | 
					    //! Get the current active game state.
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ private:
 | 
				
			||||||
    gd::RandomNumberGenerator rng{}; //!< Global random number generator.
 | 
					    gd::RandomNumberGenerator rng{}; //!< Global random number generator.
 | 
				
			||||||
    gd::HashMap<gd::StringName, Level3D*> levels{}; //!< all currently active levels identified by their resource paths.
 | 
					    gd::HashMap<gd::StringName, Level3D*> levels{}; //!< all currently active levels identified by their resource paths.
 | 
				
			||||||
    gd::Vector<SpawnPoint3D*> spawn_points{}; //!< all currently available spawn points.
 | 
					    gd::Vector<SpawnPoint3D*> spawn_points{}; //!< all currently available spawn points.
 | 
				
			||||||
    gd::Ref<GameMode> game_mode{}; //!< current active gamemode.
 | 
					    GameMode *game_mode{}; //!< current active gamemode.
 | 
				
			||||||
    /*! Active game state.
 | 
					    /*! Active game state.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Will be assigned loaded save data, or game_state_prototype if no save data is found.
 | 
					     * Will be assigned loaded save data, or game_state_prototype if no save data is found.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								level.cpp
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								level.cpp
									
									
									
									
									
								
							| 
						 | 
					@ -1,17 +1,24 @@
 | 
				
			||||||
#include "level.hpp"
 | 
					#include "level.hpp"
 | 
				
			||||||
 | 
					#include "godot_cpp/core/class_db.hpp"
 | 
				
			||||||
#include "utils/godot_macros.hpp"
 | 
					#include "utils/godot_macros.hpp"
 | 
				
			||||||
 | 
					#include <godot_cpp/classes/scene_state.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace utils {
 | 
					namespace utils {
 | 
				
			||||||
void Level3D::_bind_methods() {
 | 
					void Level3D::_bind_methods() {
 | 
				
			||||||
#define CLASSNAME Level3D
 | 
					#define CLASSNAME Level3D
 | 
				
			||||||
    GDPROPERTY_HINTED(game_mode_prototype, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "GameMode");
 | 
					    GDPROPERTY_HINTED(game_mode_prototype, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Level3D::set_game_mode_prototype(gd::Ref<GameMode> prototype) {
 | 
					void Level3D::set_game_mode_prototype(gd::Ref<gd::PackedScene> prototype) {
 | 
				
			||||||
 | 
					    if(prototype.is_null() || !prototype.is_valid())
 | 
				
			||||||
 | 
					        this->game_mode_prototype = gd::Ref<gd::PackedScene>(nullptr);
 | 
				
			||||||
 | 
					    else if(!gd::ClassDB::is_parent_class(prototype->get_state()->get_node_type(0), "GameMode"))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
        this->game_mode_prototype = prototype;
 | 
					        this->game_mode_prototype = prototype;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gd::Ref<GameMode> Level3D::get_game_mode_prototype() const {
 | 
					gd::Ref<gd::PackedScene> Level3D::get_game_mode_prototype() const {
 | 
				
			||||||
    return this->game_mode_prototype;
 | 
					    return this->game_mode_prototype;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,10 @@ class Level3D : public gd::Node3D {
 | 
				
			||||||
    GDCLASS(Level3D, gd::Node3D);
 | 
					    GDCLASS(Level3D, gd::Node3D);
 | 
				
			||||||
    static void _bind_methods();
 | 
					    static void _bind_methods();
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    void set_game_mode_prototype(gd::Ref<GameMode> prototype);
 | 
					    void set_game_mode_prototype(gd::Ref<gd::PackedScene> prototype);
 | 
				
			||||||
    gd::Ref<GameMode> get_game_mode_prototype() const;
 | 
					    gd::Ref<gd::PackedScene> get_game_mode_prototype() const;
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    gd::Ref<GameMode> game_mode_prototype{}; //!< The starting state of the game mode to instantiate if this is the "leading" level.
 | 
					    gd::Ref<gd::PackedScene> game_mode_prototype{}; //!< The starting state of the game mode to instantiate if this is the "leading" level.
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue