feat: swapped from godot:: to utils:: namespace

stripped
Sara 2024-05-28 16:28:36 +02:00
parent 54fcbcbb6b
commit 3cad3af3fe
17 changed files with 222 additions and 229 deletions

View File

@ -5,25 +5,25 @@
#include "utils/godot_macros.h"
#include "game_state.hpp"
namespace godot {
namespace utils {
void GameMode::_bind_methods() {
#define CLASSNAME GameMode
GDPROPERTY_HINTED(game_state, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GameState");
GDPROPERTY_HINTED(player_scene, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
GDPROPERTY_HINTED(game_state, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "GameState");
GDPROPERTY_HINTED(player_scene, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
}
void GameMode::_begin() {}
void GameMode::_end() {}
void GameMode::set_player_scene(Ref<PackedScene> scene) {
void GameMode::set_player_scene(gd::Ref<gd::PackedScene> scene) {
this->player_scene = scene;
}
Ref<PackedScene> GameMode::get_player_scene() const {
gd::Ref<gd::PackedScene> GameMode::get_player_scene() const {
return this->player_scene;
}
void GameMode::set_game_state(Ref<GameState> state) {
void GameMode::set_game_state(gd::Ref<GameState> state) {
if(state.is_null() || !state.is_valid()) {
this->game_state.unref();
return;
@ -31,7 +31,7 @@ void GameMode::set_game_state(Ref<GameState> state) {
this->game_state = state;
}
Ref<GameState> GameMode::get_game_state() {
gd::Ref<GameState> GameMode::get_game_state() {
return this->game_state;
}
}

View File

@ -1,26 +1,28 @@
#ifndef GAME_MODE_H
#define GAME_MODE_H
#ifndef GAME_MODE_HPP
#define GAME_MODE_HPP
#include <godot_cpp/classes/packed_scene.hpp>
#include <godot_cpp/classes/resource.hpp>
#include "game_state.hpp"
namespace godot {
class GameMode : public Resource {
GDCLASS(GameMode, Resource);
namespace gd = godot;
namespace utils {
class GameMode : public gd::Resource {
GDCLASS(GameMode, gd::Resource);
static void _bind_methods();
public:
virtual void _begin();
virtual void _end();
void set_player_scene(Ref<PackedScene> scene);
Ref<PackedScene> get_player_scene() const;
void set_game_state(Ref<GameState> state);
Ref<GameState> get_game_state();
void set_player_scene(gd::Ref<gd::PackedScene> scene);
gd::Ref<gd::PackedScene> get_player_scene() const;
void set_game_state(gd::Ref<GameState> state);
gd::Ref<GameState> get_game_state();
private:
Ref<PackedScene> player_scene{};
Ref<GameState> game_state{};
gd::Ref<gd::PackedScene> player_scene{};
gd::Ref<GameState> game_state{};
};
}
#endif // !GAME_MODE_H
#endif // !GAME_MODE_HPP

View File

@ -4,6 +4,7 @@
#include "level.hpp"
#include "player.hpp"
#include "player_input.hpp"
#include "player.hpp"
#include "spawn_point.hpp"
#include <cstdint>
#include <godot_cpp/classes/global_constants.hpp>
@ -15,14 +16,14 @@
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
namespace godot {
namespace utils {
void GameRoot3D::_bind_methods() {
#define CLASSNAME GameRoot3D
GDFUNCTION(reset_game_mode);
GDPROPERTY_HINTED(first_boot_level, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
GDSIGNAL("player_connected", PropertyInfo(Variant::OBJECT, "player_input", PROPERTY_HINT_NODE_TYPE, "PlayerInput"));
GDSIGNAL("player_disconnected", PropertyInfo(Variant::OBJECT, "player_input", PROPERTY_HINT_NODE_TYPE, "PlayerInput"));
GDSIGNAL("player_spawned", PropertyInfo(Variant::OBJECT, "player_info", PROPERTY_HINT_NODE_TYPE, "Node"));
GDPROPERTY_HINTED(first_boot_level, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
GDSIGNAL("player_connected", gd::PropertyInfo(gd::Variant::OBJECT, "player_input", gd::PROPERTY_HINT_NODE_TYPE, "PlayerInput"));
GDSIGNAL("player_disconnected", gd::PropertyInfo(gd::Variant::OBJECT, "player_input", gd::PROPERTY_HINT_NODE_TYPE, "PlayerInput"));
GDSIGNAL("player_spawned", gd::PropertyInfo(gd::Variant::OBJECT, "player_info", gd::PROPERTY_HINT_NODE_TYPE, "Node"));
}
GameRoot3D *GameRoot3D::get_singleton() {
@ -53,16 +54,16 @@ void GameRoot3D::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);
this->emit_signal(gd::StringName("player_connected"), input);
}
void GameRoot3D::remove_player(uint32_t player_id) {
if(!this->players.has(player_id))
return;
// convert player object to node
Node *node = this->players.get(player_id).second->to_node();
gd::Node *node = this->players.get(player_id).second->to_node();
if(node == nullptr) {
UtilityFunctions::push_error("IPlayer::to_node failed for player with id '", player_id, "'");
gd::UtilityFunctions::push_error("IPlayer::to_node failed for player with id '", player_id, "'");
return;
}
node->queue_free();
@ -71,7 +72,7 @@ void GameRoot3D::remove_player(uint32_t player_id) {
void GameRoot3D::remove_all_players() {
// free all player instances in use
for(KeyValue<uint32_t, Pair<PlayerInput*, IPlayer*>> &pair : this->players) {
for(gd::KeyValue<uint32_t, gd::Pair<PlayerInput*, IPlayer*>> &pair : this->players) {
// skip unused player slots
if(pair.value.second == nullptr)
continue;
@ -84,7 +85,7 @@ bool GameRoot3D::initialize_player(IPlayer *player, uint32_t id) {
if(!this->players.has(id))
return false;
// register the player
Pair<PlayerInput*, IPlayer*> &found{this->players.get(id)};
gd::Pair<PlayerInput*, IPlayer*> &found{this->players.get(id)};
found.second = player;
// set player id
player->player_id = id;
@ -95,20 +96,20 @@ bool GameRoot3D::initialize_player(IPlayer *player, uint32_t id) {
}
void GameRoot3D::reset_game_mode() {
this->set_game_mode(Ref<GameMode>());
this->set_game_mode(gd::Ref<GameMode>());
}
Level3D *GameRoot3D::load_level(Ref<PackedScene> level) {
return this->load_level_at(level, Transform3D());
Level3D *GameRoot3D::load_level(gd::Ref<gd::PackedScene> level) {
return this->load_level_at(level, gd::Transform3D());
}
Level3D *GameRoot3D::load_level_at(Ref<PackedScene> level, Transform3D at) {
Level3D *GameRoot3D::load_level_at(gd::Ref<gd::PackedScene> level, gd::Transform3D at) {
if(!GameRoot3D::is_valid_level(level)) {
return nullptr;
}
Level3D *instance = Object::cast_to<Level3D>(level->instantiate());
if(instance == nullptr) {
UtilityFunctions::push_error("Unexpected failure to instantiate level scene '", level->get_path(), "'.");
gd::UtilityFunctions::push_error("Unexpected failure to instantiate level scene '", level->get_path(), "'.");
return nullptr;
}
this->levels.insert(level->get_path(), instance);
@ -122,7 +123,7 @@ Level3D *GameRoot3D::load_level_at(Ref<PackedScene> level, Transform3D at) {
this->add_child(instance);
instance->set_global_transform(at);
if(switch_game_mode && this->game_mode.is_valid()) {
for(KeyValue<uint32_t, 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);
}
}
@ -130,21 +131,21 @@ Level3D *GameRoot3D::load_level_at(Ref<PackedScene> level, Transform3D at) {
}
void GameRoot3D::unload_all_levels() {
HashMap<StringName, Level3D*> levels = this->get_levels();
for(KeyValue<StringName, Level3D*> &kvp : levels)
gd::HashMap<gd::StringName, Level3D*> levels = this->get_levels();
for(gd::KeyValue<gd::StringName, Level3D*> &kvp : levels)
kvp.value->call_deferred("queue_free");
this->get_levels().clear();
this->reset_game_mode();
}
void GameRoot3D::replace_levels(Ref<PackedScene> scene) {
void GameRoot3D::replace_levels(gd::Ref<gd::PackedScene> scene) {
this->unload_all_levels();
this->load_level(scene);
}
void GameRoot3D::register_spawn_point(SpawnPoint3D *spawn_point) {
if(this->spawn_points.has(spawn_point)) {
UtilityFunctions::push_error("Duplicate attempt to register spawnpoint '", spawn_point->get_path(), "'");
gd::UtilityFunctions::push_error("Duplicate attempt to register spawnpoint '", spawn_point->get_path(), "'");
return;
}
if(!this->spawn_points.has(spawn_point))
@ -153,7 +154,7 @@ void GameRoot3D::register_spawn_point(SpawnPoint3D *spawn_point) {
void GameRoot3D::unregister_spawn_point(SpawnPoint3D *spawn_point) {
if(!this->spawn_points.has(spawn_point)) {
UtilityFunctions::push_error("Attempt to unregister spawnpoint '", spawn_point->get_path(), "', which is not registered.");
gd::UtilityFunctions::push_error("Attempt to unregister spawnpoint '", spawn_point->get_path(), "', which is not registered.");
return;
}
this->spawn_points.erase(spawn_point);
@ -166,12 +167,12 @@ void GameRoot3D::place_player_at_spawnpoint(IPlayer *player) {
}
void GameRoot3D::player_despawned(uint32_t id) {
Pair<PlayerInput*, IPlayer*> &pair = this->players.get(id);
gd::Pair<PlayerInput*, IPlayer*> &pair = this->players.get(id);
pair.second = nullptr;
pair.first->clear_listeners();
}
void GameRoot3D::set_game_mode(Ref<GameMode> prototype) {
void GameRoot3D::set_game_mode(gd::Ref<GameMode> prototype) {
this->remove_all_players();
// allow "unsetting" the gamemode by passing an invalid gamemode
// shorthand for this behaviour is reset_game_mode
@ -197,33 +198,33 @@ void GameRoot3D::set_game_mode(Ref<GameMode> prototype) {
}
}
Ref<GameMode> GameRoot3D::get_game_mode() const {
gd::Ref<GameMode> GameRoot3D::get_game_mode() const {
return this->game_mode;
}
Ref<GameState> GameRoot3D::get_game_state() const {
gd::Ref<GameState> GameRoot3D::get_game_state() const {
return this->game_mode->get_game_state();
}
void GameRoot3D::set_first_boot_level(Ref<PackedScene> level) {
void GameRoot3D::set_first_boot_level(gd::Ref<gd::PackedScene> level) {
if(level.is_null() || !level.is_valid()) {
this->first_boot_level.unref();
return;
}
StringName const root_type = level->get_state()->get_node_type(0);
if(!ClassDB::is_parent_class(root_type, "Level3D")) {
UtilityFunctions::push_error("First boot level cannot be of type '", root_type, "'. First boot level has to inherit from Level3D");
gd::StringName const root_type = level->get_state()->get_node_type(0);
if(!gd::ClassDB::is_parent_class(root_type, "Level3D")) {
gd::UtilityFunctions::push_error("First boot level cannot be of type '", root_type, "'. First boot level has to inherit from Level3D");
this->first_boot_level.unref();
return;
}
this->first_boot_level = level;
}
Ref<PackedScene> GameRoot3D::get_first_boot_level() const {
gd::Ref<gd::PackedScene> GameRoot3D::get_first_boot_level() const {
return this->first_boot_level;
}
HashMap<StringName, Level3D *> &GameRoot3D::get_levels() {
gd::HashMap<gd::StringName, Level3D *> &GameRoot3D::get_levels() {
return this->levels;
}
@ -231,9 +232,9 @@ IPlayer *GameRoot3D::get_player(uint32_t id) {
return this->players[id].second;
}
Vector<IPlayer*> GameRoot3D::get_players() {
Vector<IPlayer*> players{};
for(KeyValue<uint32_t, Pair<PlayerInput*, IPlayer*>> pair : this->players) {
gd::Vector<IPlayer*> GameRoot3D::get_players() {
gd::Vector<IPlayer*> players{};
for(gd::KeyValue<uint32_t, gd::Pair<PlayerInput*, IPlayer*>> pair : this->players) {
players.push_back(pair.value.second);
}
return players;
@ -242,7 +243,7 @@ Vector<IPlayer*> GameRoot3D::get_players() {
void GameRoot3D::grab_singleton() {
if(GameRoot3D::has_singleton()) {
this->set_process_mode(PROCESS_MODE_DISABLED);
UtilityFunctions::push_error("More than one GameRoot instance active");
gd::UtilityFunctions::push_error("More than one GameRoot instance active");
} else {
GameRoot3D::singleton_instance = this;
}
@ -252,12 +253,12 @@ void GameRoot3D::release_singleton() {
if(GameRoot3D::singleton_instance == this) {
GameRoot3D::singleton_instance = nullptr;
} else {
UtilityFunctions::push_error("GameRoot instance attempted to release singleton while it is not the singleton instance");
gd::UtilityFunctions::push_error("GameRoot instance attempted to release singleton while it is not the singleton instance");
}
}
uint32_t GameRoot3D::find_empty_player_slot() const {
for(KeyValue<uint32_t, Pair<PlayerInput*, IPlayer*>> const &kvp : this->players) {
for(gd::KeyValue<uint32_t, gd::Pair<PlayerInput*, IPlayer*>> const &kvp : this->players) {
if(kvp.value.second == nullptr) {
return kvp.key;
}
@ -267,17 +268,17 @@ uint32_t GameRoot3D::find_empty_player_slot() const {
IPlayer *GameRoot3D::spawn_player(uint32_t id) {
if(id == 0) {
UtilityFunctions::push_error("Failed to find any valid player slot when spawning player");
gd::UtilityFunctions::push_error("Failed to find any valid player slot when spawning player");
return nullptr;
}
Node *player_node = this->game_mode->get_player_scene()->instantiate();
if(player_node == nullptr) {
UtilityFunctions::push_error("Failed to instantiate player scene '", this->game_mode->get_player_scene()->get_path(), "'");
gd::UtilityFunctions::push_error("Failed to instantiate player scene '", this->game_mode->get_player_scene()->get_path(), "'");
return nullptr;
}
IPlayer *player = dynamic_cast<IPlayer*>(player_node);
if(player == nullptr) {
UtilityFunctions::push_error("Player scene does not implement required IPlayer interface");
gd::UtilityFunctions::push_error("Player scene does not implement required IPlayer interface");
player_node->queue_free();
return nullptr;
}
@ -285,18 +286,18 @@ IPlayer *GameRoot3D::spawn_player(uint32_t id) {
return player;
}
void GameRoot3D::level_unloaded(StringName scene_path) {
void GameRoot3D::level_unloaded(gd::StringName scene_path) {
this->levels.erase(scene_path);
}
bool GameRoot3D::is_valid_level(Ref<PackedScene> &level) {
bool GameRoot3D::is_valid_level(gd::Ref<gd::PackedScene> &level) {
if(level.is_null() || !level.is_valid() || !level->can_instantiate()) {
UtilityFunctions::push_error("Can't load level from invalid packed scene");
gd::UtilityFunctions::push_error("Can't load level from invalid packed scene");
return false;
}
StringName const root_type = level->get_state()->get_node_type(0);
if(!ClassDB::is_parent_class(root_type, "Level3D")) {
UtilityFunctions::push_error("Can't load level with root type '", root_type, "'. Root node has to be of type Level3D");
gd::StringName const root_type = level->get_state()->get_node_type(0);
if(!gd::ClassDB::is_parent_class(root_type, "Level3D")) {
gd::UtilityFunctions::push_error("Can't load level with root type '", root_type, "'. Root node has to be of type Level3D");
return false;
}
return true;

View File

@ -2,23 +2,25 @@
#define GAME_ROOT_HPP
#include "game_mode.hpp"
#include "godot_cpp/classes/random_number_generator.hpp"
#include "level.hpp"
#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/classes/packed_scene.hpp>
#include <godot_cpp/classes/random_number_generator.hpp>
#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>
#include <godot_cpp/templates/vector.hpp>
namespace godot {
namespace gd = godot;
namespace utils {
class PlayerInput;
class IPlayer;
class SpawnPoint3D;
class GameRoot3D : public Node {
GDCLASS(GameRoot3D, Node);
class GameRoot3D : public gd::Node {
GDCLASS(GameRoot3D, gd::Node);
static void _bind_methods();
public:
// get the current active singleton instance of GameRoot
@ -46,12 +48,12 @@ public:
void reset_game_mode();
// shorthand for load_level(level, Transform3D())
Level3D *load_level(Ref<PackedScene> level);
Level3D *load_level(gd::Ref<gd::PackedScene> 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<PackedScene> level, Transform3D at);
Level3D *load_level_at(gd::Ref<gd::PackedScene> level, gd::Transform3D at);
void unload_all_levels();
void replace_levels(Ref<PackedScene> level);
void replace_levels(gd::Ref<gd::PackedScene> level);
// register a spawnpoint for use when spawning players
void register_spawn_point(SpawnPoint3D *spawn_point);
@ -63,14 +65,14 @@ public:
// ----- getter / setters -----
// override the current gamemode
// force-respawns all players
void set_game_mode(Ref<GameMode> prototype);
Ref<GameMode> get_game_mode() const;
Ref<GameState> get_game_state() const;
void set_first_boot_level(Ref<PackedScene> level);
Ref<PackedScene> get_first_boot_level() const;
HashMap<StringName, Level3D *> &get_levels();
void set_game_mode(gd::Ref<GameMode> prototype);
gd::Ref<GameMode> get_game_mode() const;
gd::Ref<GameState> get_game_state() const;
void set_first_boot_level(gd::Ref<gd::PackedScene> level);
gd::Ref<gd::PackedScene> get_first_boot_level() const;
gd::HashMap<gd::StringName, Level3D *> &get_levels();
IPlayer *get_player(uint32_t id);
Vector<IPlayer*> get_players();
gd::Vector<IPlayer*> get_players();
protected:
// attempt to make 'this' the current singleton instance
void grab_singleton();
@ -79,20 +81,20 @@ protected:
void release_singleton();
uint32_t find_empty_player_slot() const;
IPlayer *spawn_player(uint32_t id);
void level_unloaded(StringName scene_path);
static bool is_valid_level(Ref<PackedScene> &level);
void level_unloaded(gd::StringName scene_path);
static bool is_valid_level(gd::Ref<gd::PackedScene> &level);
protected:
static GameRoot3D *singleton_instance;
uint32_t next_player_id{1}; // 0 is the "invalid" player id
HashMap<uint32_t, Pair<PlayerInput*, IPlayer*>> players{};
Ref<GameMode> game_mode{};
gd::HashMap<uint32_t, gd::Pair<PlayerInput*, IPlayer*>> players{};
gd::Ref<GameMode> game_mode{};
private:
RandomNumberGenerator rng{};
HashMap<StringName, Level3D*> levels{};
Vector<SpawnPoint3D*> spawn_points{};
gd::RandomNumberGenerator rng{};
gd::HashMap<gd::StringName, Level3D*> levels{};
gd::Vector<SpawnPoint3D*> spawn_points{};
Ref<PackedScene> first_boot_level{};
gd::Ref<gd::PackedScene> first_boot_level{};
};
}

View File

@ -1,6 +1,8 @@
#include "game_state.hpp"
namespace godot {
using namespace godot;
namespace utils {
void GameState::_bind_methods() {
#define CLASSNAME GameState
}

View File

@ -1,10 +1,11 @@
#ifndef GAME_STATE_HPP
#define GAME_STATE_HPP
#include "godot_cpp/classes/resource.hpp"
namespace godot {
class GameState : public Resource {
GDCLASS(GameState, Resource);
#include <godot_cpp/classes/resource.hpp>
namespace utils {
class GameState : public godot::Resource {
GDCLASS(GameState, godot::Resource);
static void _bind_methods();
public:
};

View File

@ -4,37 +4,33 @@
#include "godot_cpp/classes/engine.hpp"
#include "godot_cpp/core/class_db.hpp"
#define MACRO_STRING_INNER(_Arg) #_Arg
#define MACRO_STRING(_Arg) MACRO_STRING_INNER(_Arg)
#define GDPROPERTY(_PropName, _PropType) \
ClassDB::bind_method(D_METHOD("get_" #_PropName), &CLASSNAME::get_##_PropName); \
ClassDB::bind_method(D_METHOD("set_" #_PropName, "value"), &CLASSNAME::set_##_PropName); \
ClassDB::add_property(MACRO_STRING(CLASSNAME), PropertyInfo(_PropType, #_PropName), "set_" #_PropName, \
"get_" #_PropName)
godot::ClassDB::bind_method(godot::D_METHOD("get_" #_PropName), &CLASSNAME::get_##_PropName); \
godot::ClassDB::bind_method(godot::D_METHOD("set_" #_PropName, "value"), &CLASSNAME::set_##_PropName); \
godot::ClassDB::add_property(MACRO_STRING(CLASSNAME), godot::PropertyInfo(_PropType, #_PropName), "set_" #_PropName, "get_" #_PropName)
#define GDPROPERTY_HINTED(_PropName, _PropType, ...) \
ClassDB::bind_method(D_METHOD("get_" #_PropName), &CLASSNAME::get_##_PropName); \
ClassDB::bind_method(D_METHOD("set_" #_PropName, "value"), &CLASSNAME::set_##_PropName); \
ClassDB::add_property(MACRO_STRING(CLASSNAME), PropertyInfo(_PropType, #_PropName, __VA_ARGS__), \
"set_" #_PropName, "get_" #_PropName)
godot::ClassDB::bind_method(godot::D_METHOD("get_" #_PropName), &CLASSNAME::get_##_PropName); \
godot::ClassDB::bind_method(godot::D_METHOD("set_" #_PropName, "value"), &CLASSNAME::set_##_PropName); \
godot::ClassDB::add_property(MACRO_STRING(CLASSNAME), godot::PropertyInfo(_PropType, #_PropName, __VA_ARGS__), "set_" #_PropName, "get_" #_PropName)
#define GDFUNCTION(_FnName) ClassDB::bind_method(D_METHOD(#_FnName), &CLASSNAME::_FnName)
#define GDFUNCTION(_FnName) godot::ClassDB::bind_method(godot::D_METHOD(#_FnName), &CLASSNAME::_FnName)
#define GDFUNCTION_ARGS(_FnName, ...) ClassDB::bind_method(D_METHOD(#_FnName, __VA_ARGS__), &CLASSNAME::_FnName)
#define GDFUNCTION_ARGS(_FnName, ...) godot::ClassDB::bind_method(godot::D_METHOD(#_FnName, __VA_ARGS__), &CLASSNAME::_FnName)
#define GDFUNCTION_STATIC(_FnName) \
ClassDB::bind_static_method(MACRO_STRING(CLASSNAME), D_METHOD(#_FnName), &CLASSNAME::_FnName)
#define GDFUNCTION_STATIC(_FnName) godot::ClassDB::bind_static_method(MACRO_STRING(CLASSNAME), godot::D_METHOD(#_FnName), &CLASSNAME::_FnName)
#define GDFUNCTION_STATIC_ARGS(_FnName, ...) \
ClassDB::bind_static_method(MACRO_STRING(CLASSNAME), D_METHOD(#_FnName, __VA_ARGS__), &CLASSNAME::_FnName)
#define GDFUNCTION_STATIC_ARGS(_FnName, ...) godot::ClassDB::bind_static_method(MACRO_STRING(CLASSNAME), godot::D_METHOD(#_FnName, __VA_ARGS__), &CLASSNAME::_FnName)
#define GDSIGNAL(...)\
ClassDB::add_signal(MACRO_STRING(CLASSNAME), MethodInfo(__VA_ARGS__))
#define GDSIGNAL(...) godot::ClassDB::add_signal(MACRO_STRING(CLASSNAME), godot::MethodInfo(__VA_ARGS__))
#define GDRESOURCETYPE(_Class) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, #_Class)
#define GDRESOURCETYPE(_Class) godot::vformat("%s/%s:%s", godot::Variant::OBJECT, godot::PROPERTY_HINT_RESOURCE_TYPE, #_Class)
#define GDEDITORONLY() if(!Engine::get_singleton()->is_editor_hint()) return;
#define GDGAMEONLY() if(Engine::get_singleton()->is_editor_hint()) return;
#define GDEDITORONLY() if(!godot::Engine::get_singleton()->is_editor_hint()) return;
#define GDGAMEONLY() if(godot::Engine::get_singleton()->is_editor_hint()) return;
#endif // !UC_GODOT_MACROS_H

View File

@ -1,33 +1,17 @@
#include "level.hpp"
#include "utils/godot_macros.h"
namespace godot {
namespace utils {
void Level3D::_bind_methods() {
#define CLASSNAME Level3D
GDPROPERTY_HINTED(game_mode_prototype, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GameMode");
GDPROPERTY_HINTED(game_mode_prototype, gd::Variant::OBJECT, gd::PROPERTY_HINT_RESOURCE_TYPE, "GameMode");
}
void Level3D::set_game_mode_prototype(Ref<GameMode> prototype) {
void Level3D::set_game_mode_prototype(gd::Ref<GameMode> prototype) {
this->game_mode_prototype = prototype;
}
Ref<GameMode> Level3D::get_game_mode_prototype() const {
gd::Ref<GameMode> Level3D::get_game_mode_prototype() const {
return this->game_mode_prototype;
}
#undef CLASSNAME // Level3D
void Level2D::_bind_methods() {
#define CLASSNAME Level3D
GDPROPERTY_HINTED(game_mode_prototype, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GameMode");
}
void Level2D::set_game_mode_prototype(Ref<GameMode> prototype) {
this->game_mode_prototype = prototype;
}
Ref<GameMode> Level2D::get_game_mode_prototype() const {
return this->game_mode_prototype;
}
}

View File

@ -1,32 +1,21 @@
#ifndef LEVEL_HPP
#define LEVEL_HPP
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/classes/node3d.hpp>
#include "game_mode.hpp"
#include <godot_cpp/classes/node3d.hpp>
namespace godot {
class Level3D : public Node3D {
GDCLASS(Level3D, Node3D);
namespace gd = godot;
namespace utils {
class Level3D : public gd::Node3D {
GDCLASS(Level3D, gd::Node3D);
static void _bind_methods();
public:
void set_game_mode_prototype(Ref<GameMode> prototype);
Ref<GameMode> get_game_mode_prototype() const;
void set_game_mode_prototype(gd::Ref<GameMode> prototype);
gd::Ref<GameMode> get_game_mode_prototype() const;
private:
Ref<GameMode> game_mode_prototype{};
gd::Ref<GameMode> game_mode_prototype{};
};
class Level2D : public Node2D {
GDCLASS(Level2D, Node2D);
static void _bind_methods();
public:
void set_game_mode_prototype(Ref<GameMode> prototype);
Ref<GameMode> get_game_mode_prototype() const;
private:
Ref<GameMode> game_mode_prototype{};
};
}
#endif // !LEVEL_HPP

View File

@ -1,6 +1,6 @@
#include "player.hpp"
namespace godot {
namespace utils {
uint32_t IPlayer::get_player_id() {
return this->player_id.value_or(0);
}

View File

@ -5,16 +5,19 @@
#include <optional>
#include <godot_cpp/variant/transform3d.hpp>
namespace godot {
namespace godot { class Node; }
namespace gd = godot;
namespace utils {
class PlayerInput;
class Node;
class IPlayer {
friend class GameRoot3D;
public:
virtual void setup_player_input(PlayerInput *input) = 0;
virtual Node *to_node() = 0;
virtual void spawn_at_position(Transform3D const &at) = 0;
virtual gd::Node *to_node() = 0;
virtual void spawn_at_position(gd::Transform3D const &at) = 0;
uint32_t get_player_id();

View File

@ -1,31 +1,32 @@
#include "player_input.hpp"
#include "godot_macros.h"
#include "godot_cpp/classes/input.hpp"
#include "godot_cpp/classes/input_event.hpp"
#include "godot_cpp/classes/input_event_mouse_motion.hpp"
#include "godot_cpp/variant/callable.hpp"
#include <algorithm>
#include <godot_cpp/classes/input.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/classes/input_event_mouse_motion.hpp>
#include <godot_cpp/variant/callable.hpp>
#include <optional>
namespace godot {
void PlayerInput::_bind_methods() {}
namespace utils {
void PlayerInput::_bind_methods() {
#define CLASSNAME PlayerInput
}
Vector2 PlayerInput::lastMouseMotion{0.f, 0.f};
gd::Vector2 PlayerInput::lastMouseMotion{0.f, 0.f};
bool PlayerInput::primaryExists{false};
PlayerInput::Listener::Listener(String positive, String negative, Callable callable)
PlayerInput::Listener::Listener(gd::String positive, gd::String negative, gd::Callable callable)
: actionNegative{negative}
, actionPositive{positive}
, callable{callable}
, isMouseEvent{positive.begins_with("_mouse_") || negative.begins_with("_mouse_")} {}
PlayerInput::Listener::Listener(String action, Callable callable)
: PlayerInput::Listener::Listener(action, String(), callable) {}
PlayerInput::Listener::Listener(gd::String action, gd::Callable callable)
: PlayerInput::Listener::Listener(action, gd::String(), callable) {}
std::optional<float> PlayerInput::Listener::evaluate_action(String const &action) {
Input *input = Input::get_singleton();
std::optional<float> PlayerInput::Listener::evaluate_action(gd::String const &action) {
gd::Input *input = gd::Input::get_singleton();
if(action.begins_with("_mouse_")) {
Vector2 vector = PlayerInput::get_last_mouse_motion();
gd::Vector2 vector = PlayerInput::get_last_mouse_motion();
if(action.ends_with("_up"))
return vector.y > 0.f ? vector.y : 0.f;
else if(action.ends_with("_down"))
@ -42,14 +43,14 @@ std::optional<float> PlayerInput::Listener::evaluate_action(String const &action
}
}
bool PlayerInput::Listener::has_changed(Ref<InputEvent> const &event) {
bool PlayerInput::Listener::has_changed(gd::Ref<gd::InputEvent> const &event) {
bool const mouse_changed{this->isMouseEvent && event->is_class("InputEventMouseMotion")};
bool const negative_changed{!this->actionNegative.is_empty() && event->is_action(this->actionNegative)};
bool const positive_changed{!this->actionPositive.is_empty() && event->is_action(this->actionPositive)};
return mouse_changed || negative_changed || positive_changed;
}
float PlayerInput::Listener::evaluate(Ref<InputEvent> const &event) {
float PlayerInput::Listener::evaluate(gd::Ref<gd::InputEvent> const &event) {
std::optional<float> positive = PlayerInput::Listener::evaluate_action(this->actionPositive);
std::optional<float> negative = PlayerInput::Listener::evaluate_action(this->actionNegative);
if(!positive.has_value() || !negative.has_value())
@ -60,13 +61,13 @@ float PlayerInput::Listener::evaluate(Ref<InputEvent> const &event) {
return (this->lastCached = newest);
}
bool PlayerInput::Listener::operator==(godot::PlayerInput::Listener const& b) {
bool PlayerInput::Listener::operator==(PlayerInput::Listener const& b) const {
return this->callable == b.callable
&& this->actionNegative == b.actionNegative
&& this->actionPositive == b.actionPositive;
}
Vector2 PlayerInput::get_last_mouse_motion() {
gd::Vector2 PlayerInput::get_last_mouse_motion() {
return PlayerInput::lastMouseMotion;
}
@ -86,10 +87,10 @@ void PlayerInput::_exit_tree() {
}
}
void PlayerInput::_unhandled_input(Ref<InputEvent> const &event) {
void PlayerInput::_unhandled_input(gd::Ref<gd::InputEvent> const &event) {
GDGAMEONLY();
if(this->isPrimary && event->is_class("InputEventMouseMotion"))
PlayerInput::lastMouseMotion = Object::cast_to<InputEventMouseMotion>(*event)->get_relative();
PlayerInput::lastMouseMotion = gd::Object::cast_to<gd::InputEventMouseMotion>(*event)->get_relative();
for(Listener& listener: this->listeners) {
if(listener.has_changed(event)) {
listener.evaluate(event);
@ -108,18 +109,16 @@ void PlayerInput::listen_to(Listener const& listener) {
void PlayerInput::stop_listening(Node *node) {
for(size_t i = 0; i < this->listeners.size(); ++i) {
Listener& l = this->listeners.at(i);
Listener l = this->listeners.get(i);
if(l.callable.get_object() == node) {
this->listeners.erase(this->listeners.begin() + i);
this->listeners.remove_at(i);
i--;
}
}
}
void PlayerInput::stop_listening(Listener const& listener) {
std::vector<Listener>::iterator itr = std::find(this->listeners.begin(), this->listeners.end(), listener);
if(itr != this->listeners.end())
this->listeners.erase(itr);
this->listeners.erase(listener);
}
void PlayerInput::clear_listeners() {

View File

@ -1,55 +1,60 @@
#ifndef PLAYER_INPUT_HPP
#define PLAYER_INPUT_HPP
#include <vector>
#include <optional>
#include "godot_cpp/classes/input.hpp"
#include "godot_cpp/classes/input_event.hpp"
#include "godot_cpp/classes/node.hpp"
#include "godot_cpp/variant/callable.hpp"
#include <godot_cpp/classes/input.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/variant/callable.hpp>
namespace godot {
class PlayerInput : public Node {
GDCLASS(PlayerInput, Node)
namespace gd = godot;
namespace utils {
/*! An event-driven input observer.
*
* Listen for events with `listen_to`, registering godot input action names to callbacks. It's possible to register an "axis" by registering a listener with a positive and negative action.
*/
class PlayerInput : public gd::Node {
GDCLASS(PlayerInput, gd::Node)
static void _bind_methods();
public:
// a listener is a combination of a positive and negative action and a listener function.
// listener functions use godot's Object::call function.
// So they require a Node instance and a function name.
// The expected signature is void(Ref<InputEvent>, float)
// actions can also be "special" actions prefixed with _.
// special actions include _mouse_up, _mouse_down, _mouse_left and _mouse_right
// which rather than checking action_is_down,
// will use PlayerInput::get_last_mouse_motion() to poll the current state.
/*! A PlayerInput action listener.
* A listener is a combination of a positive and negative action and a callable.
* The expected callable signature is `void (godot::Ref<godot::InputEvent> event, float value)`
* actions can also be "special" actions prefixed with `_`.
* Special actions include `_mouse_up`, `_mouse_down`, `_mouse_left`, and `_mouse_right`.
*/
struct Listener {
friend class PlayerInput;
private:
// the two actions, evaluated as positive - negative
String actionNegative{""};
String actionPositive{""};
gd::String actionNegative{""};
gd::String actionPositive{""};
// the last cached action, if the newest result matches this, the event will be considered
// duplicate and ignored (not passed to listener)
float lastCached{0.f};
Callable callable;
gd::Callable callable;
// if either actionNegative or actionPositive is a _mouse_ event this will be true
bool isMouseEvent{false};
public:
Listener(String positive, String negative, Callable callable);
Listener(String action, Callable callable);
Listener() = default;
Listener(gd::String positive, gd::String negative, gd::Callable callable);
Listener(gd::String action, gd::Callable callable);
// evaluate the current state of an action.
static std::optional<float> evaluate_action(String const &action);
static std::optional<float> evaluate_action(gd::String const &action);
// check if this event has any chance to result in a trigger, does not evaluate the event or
// poll current input state
bool has_changed(Ref<InputEvent> const &event);
bool has_changed(gd::Ref<gd::InputEvent> const &event);
// evaluate the event for changes to either actionPositive or actionNegative
float evaluate(Ref<InputEvent> const &event);
float evaluate(gd::Ref<gd::InputEvent> const &event);
bool operator==(godot::PlayerInput::Listener const& b);
bool operator==(PlayerInput::Listener const& b) const;
};
private:
// the last mouse motion, updated by the primary instance
static Vector2 lastMouseMotion;
static gd::Vector2 lastMouseMotion;
// does a primary instance exist
static bool primaryExists;
// is this the primary instance
@ -58,18 +63,18 @@ private:
bool isPrimary{false};
// current listeners for this instance
std::vector<Listener> listeners{};
gd::Vector<Listener> listeners{};
public:
static Vector2 get_last_mouse_motion();
static gd::Vector2 get_last_mouse_motion();
virtual void _enter_tree() override;
virtual void _exit_tree() override;
virtual void _unhandled_input(Ref<InputEvent> const &event) override;
virtual void _unhandled_input(gd::Ref<gd::InputEvent> const &event) override;
virtual void _process(double deltaTime) override;
void listen_to(Listener const& listener);
void listen_to(Listener const &listener);
void stop_listening(Node *node);
void stop_listening(Listener const& listener);
void stop_listening(Listener const &listener);
void clear_listeners();
};
}

View File

@ -1,17 +1,21 @@
#include "register_types.hpp"
#include <godot_cpp/core/class_db.hpp>
#include "game_root.hpp"
#include "game_mode.hpp"
#include "game_root.hpp"
#include "game_state.hpp"
#include "level.hpp"
#include "player_input.hpp"
#include "spawn_point.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
namespace gd = godot;
namespace utils {
void godot_cpp_utils_register_types() {
ClassDB::register_class<GameRoot3D>();
ClassDB::register_class<GameMode>();
ClassDB::register_class<GameState>();
ClassDB::register_class<Level3D>();
ClassDB::register_class<SpawnPoint3D>();
ClassDB::register_class<PlayerInput>();
gd::ClassDB::register_class<utils::GameMode>();
gd::ClassDB::register_class<utils::GameRoot3D>();
gd::ClassDB::register_class<utils::GameState>();
gd::ClassDB::register_class<utils::Level3D>();
gd::ClassDB::register_class<utils::PlayerInput>();
gd::ClassDB::register_class<utils::SpawnPoint3D>();
}
}

View File

@ -1,6 +1,8 @@
#ifndef UTILS_REGISTER_TYPES_HPP
#define UTILS_REGISTER_TYPES_HPP
namespace utils {
void godot_cpp_utils_register_types();
}
#endif // !UTILS_REGISTER_TYPES_HPP

View File

@ -1,12 +1,12 @@
#include "spawn_point.hpp"
#include "utils/game_root.hpp"
namespace godot {
namespace utils {
void SpawnPoint3D::_bind_methods() {
}
void SpawnPoint3D::_enter_tree() {
GameRoot3D *root = Object::cast_to<GameRoot3D>(GameRoot3D::get_singleton());
GameRoot3D *root = gd::Object::cast_to<GameRoot3D>(GameRoot3D::get_singleton());
if(root == nullptr) {
return;
}

View File

@ -1,10 +1,13 @@
#ifndef UTILS_SPAWN_POINT_HPP
#define UTILS_SPAWN_POINT_HPP
#include "godot_cpp/classes/node3d.hpp"
namespace godot {
class SpawnPoint3D : public Node3D {
GDCLASS(SpawnPoint3D, Node3D);
#include <godot_cpp/classes/node3d.hpp>
namespace gd = godot;
namespace utils {
class SpawnPoint3D : public gd::Node3D {
GDCLASS(SpawnPoint3D, gd::Node3D);
static void _bind_methods();
public:
virtual void _enter_tree() override;