Skip to content

Commit

Permalink
Merge pull request #1280 from dsnopek/callable-custom
Browse files Browse the repository at this point in the history
Add `CallableCustom` that devs can use in their GDExtensions
  • Loading branch information
dsnopek authored Nov 17, 2023
2 parents c4b7b08 + d33bd47 commit 4439a4a
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 53 deletions.
12 changes: 12 additions & 0 deletions binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):

for native_struct in api["native_structures"]:
struct_name = native_struct["name"]
if struct_name == "ObjectID":
continue
snake_struct_name = camel_to_snake(struct_name)

header_filename = include_gen_folder / "classes" / (snake_struct_name + ".hpp")
Expand Down Expand Up @@ -416,6 +418,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
if class_name == "Array":
result.append("#include <godot_cpp/variant/array_helpers.hpp>")

if class_name == "Callable":
result.append("#include <godot_cpp/variant/callable_custom.hpp>")

for include in fully_used_classes:
if include == "TypedArray":
result.append("#include <godot_cpp/variant/typed_array.hpp>")
Expand Down Expand Up @@ -525,6 +530,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append(f"\t{class_name}(const wchar_t *from);")
result.append(f"\t{class_name}(const char16_t *from);")
result.append(f"\t{class_name}(const char32_t *from);")
if class_name == "Callable":
result.append("\tCallable(CallableCustom *p_custom);")
result.append("\tCallableCustom *get_custom() const;")

if "constants" in builtin_api:
axis_constants_count = 0
Expand Down Expand Up @@ -1083,6 +1091,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
class_api["alias_for"] = "ClassDB"
engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]:
if native_struct["name"] == "ObjectID":
continue
engine_classes[native_struct["name"]] = False
native_structures.append(native_struct["name"])

Expand Down Expand Up @@ -1210,6 +1220,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):

for native_struct in api["native_structures"]:
struct_name = native_struct["name"]
if struct_name == "ObjectID":
continue
snake_struct_name = camel_to_snake(struct_name)

header_filename = include_gen_folder / (snake_struct_name + ".hpp")
Expand Down
24 changes: 2 additions & 22 deletions include/godot_cpp/core/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#include <godot_cpp/core/defs.hpp>

#include <godot_cpp/core/object_id.hpp>

#include <godot_cpp/core/property_info.hpp>

#include <godot_cpp/variant/variant.hpp>
Expand Down Expand Up @@ -106,28 +108,6 @@ MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args
arguments = { args... };
}

class ObjectID {
uint64_t id = 0;

public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }

_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }

_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }

_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};

class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
Expand Down
62 changes: 62 additions & 0 deletions include/godot_cpp/core/object_id.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**************************************************************************/
/* object_id.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#ifndef GODOT_OBJECT_ID_HPP
#define GODOT_OBJECT_ID_HPP

#include <godot_cpp/core/defs.hpp>

namespace godot {

class ObjectID {
uint64_t id = 0;

public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }

_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }

_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }

_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};

} // namespace godot

#endif // GODOT_OBJECT_ID_HPP
1 change: 1 addition & 0 deletions include/godot_cpp/godot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create;
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
extern "C" GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2;
Expand Down
64 changes: 64 additions & 0 deletions include/godot_cpp/variant/callable_custom.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**************************************************************************/
/* callable_custom.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#ifndef GODOT_CALLABLE_CUSTOM_HPP
#define GODOT_CALLABLE_CUSTOM_HPP

#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/variant/string_name.hpp>

namespace godot {

class Object;

class CallableCustomBase {
public:
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomBase() {}
};

class CallableCustom : public CallableCustomBase {
public:
typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);

virtual uint32_t hash() const = 0;
virtual String get_as_text() const = 0;
virtual CompareEqualFunc get_compare_equal_func() const = 0;
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual bool is_valid() const;
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
};

} // namespace godot

#endif // GODOT_CALLABLE_CUSTOM_HPP
38 changes: 17 additions & 21 deletions include/godot_cpp/variant/callable_method_pointer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,12 @@

namespace godot {

class CallableCustomMethodPointerBase {
public:
virtual Object *get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomMethodPointerBase() {}
class CallableCustomMethodPointerBase : public CallableCustomBase {
};

namespace internal {

Callable create_custom_callable(CallableCustomMethodPointerBase *p_callable_method_pointer);
Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer);

} // namespace internal

Expand All @@ -59,8 +55,8 @@ class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
void (T::*method)(P...);

public:
virtual Object *get_object() const override {
return instance;
virtual ObjectID get_object() const override {
return ObjectID(instance->get_instance_id());
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
Expand All @@ -77,7 +73,7 @@ template <class T, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_custom_callable(ccmp);
return ::godot::internal::create_callable_from_ccmp(ccmp);
}

//
Expand All @@ -91,8 +87,8 @@ class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
(P...);

public:
virtual Object *get_object() const override {
return instance;
virtual ObjectID get_object() const override {
return ObjectID(instance->get_instance_id());
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
Expand All @@ -109,7 +105,7 @@ template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_custom_callable(ccmp);
return ::godot::internal::create_callable_from_ccmp(ccmp);
}

//
Expand All @@ -123,8 +119,8 @@ class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
(P...) const;

public:
virtual Object *get_object() const override {
return instance;
virtual ObjectID get_object() const override {
return ObjectID(instance->get_instance_id());
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
Expand All @@ -141,7 +137,7 @@ template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_custom_callable(ccmp);
return ::godot::internal::create_callable_from_ccmp(ccmp);
}

//
Expand All @@ -153,8 +149,8 @@ class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase
void (*method)(P...);

public:
virtual Object *get_object() const override {
return nullptr;
virtual ObjectID get_object() const override {
return ObjectID();
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
Expand All @@ -171,7 +167,7 @@ template <class... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_custom_callable(ccmp);
return ::godot::internal::create_callable_from_ccmp(ccmp);
}

//
Expand All @@ -184,8 +180,8 @@ class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerB
(P...);

public:
virtual Object *get_object() const override {
return nullptr;
virtual ObjectID get_object() const override {
return ObjectID();
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
Expand All @@ -201,7 +197,7 @@ template <class R, class... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_custom_callable(ccmp);
return ::godot::internal::create_callable_from_ccmp(ccmp);
}

//
Expand Down
2 changes: 2 additions & 0 deletions src/godot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr;
GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id = nullptr;
GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id = nullptr;
GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create = nullptr;
GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata = nullptr;
GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object = nullptr;
GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr;
GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2 = nullptr;
Expand Down Expand Up @@ -390,6 +391,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId);
LOAD_PROC_ADDRESS(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId);
LOAD_PROC_ADDRESS(callable_custom_create, GDExtensionInterfaceCallableCustomCreate);
LOAD_PROC_ADDRESS(callable_custom_get_userdata, GDExtensionInterfaceCallableCustomGetUserData);
LOAD_PROC_ADDRESS(ref_get_object, GDExtensionInterfaceRefGetObject);
LOAD_PROC_ADDRESS(ref_set_object, GDExtensionInterfaceRefSetObject);
LOAD_PROC_ADDRESS(script_instance_create2, GDExtensionInterfaceScriptInstanceCreate2);
Expand Down
Loading

0 comments on commit 4439a4a

Please sign in to comment.