Skip to content

Added ClassDB::bind_static_vararg_method() to bind static variadic functions. #1248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions include/godot_cpp/core/class_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ class ClassDB {
template <class M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);

template <class M>
static MethodBind *bind_static_vararg_method(uint32_t p_flags, StringName p_class, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);

static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
Expand Down Expand Up @@ -288,6 +291,37 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
return bind;
}

template <class M>
MethodBind *ClassDB::bind_static_vararg_method(uint32_t p_flags, StringName p_class, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_COND_V(!bind, nullptr);

bind->set_name(p_name);
bind->set_default_arguments(p_default_args);
bind->set_instance_class(p_class);

std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
if (type_it == classes.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
}

ClassInfo &type = type_it->second;

if (type.method_map.find(p_name) != type.method_map.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Binding duplicate method: {0}::{1}.").format(Array::make(p_class, p_method)));
}

// register our method bind within our plugin
type.method_map[p_name] = bind;

// and register with godot
bind_method_godot(type.name, bind);

return bind;
}

#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
Expand Down
114 changes: 114 additions & 0 deletions include/godot_cpp/core/method_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,120 @@ MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExten
return a;
}

template <class Derived, class R, bool should_returns>
class MethodBindVarArgBaseS : public MethodBind {
protected:
R(*function)
(const Variant **, GDExtensionInt, GDExtensionCallError &);
std::vector<PropertyInfo> arguments;

public:
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg < 0) {
return _gen_return_type_info();
} else if ((size_t)(p_arg) < arguments.size()) {
return arguments[p_arg];
} else {
return make_property_info(Variant::Type::NIL, "vararg", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
}

virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
return static_cast<GDExtensionVariantType>(gen_argument_type_info(p_arg).type);
}

virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int) const {
return GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
}

virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const {
ERR_FAIL(); // Can't call.
}

MethodBindVarArgBaseS(
R (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
function(p_function) {
set_vararg(true);
set_argument_count(p_method_info.arguments.size());
if (p_method_info.arguments.size()) {
arguments = p_method_info.arguments;

std::vector<StringName> names;
names.reserve(p_method_info.arguments.size());
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
names.push_back(p_method_info.arguments[i].name);
}
set_argument_names(names);
}
generate_argument_types((int)p_method_info.arguments.size());
set_return(should_returns);
set_static(true);
}

~MethodBindVarArgBaseS() {}

private:
PropertyInfo _gen_return_type_info() const {
return reinterpret_cast<const Derived *>(this)->_gen_return_type_info_impl();
}
};

class MethodBindVarArgTS : public MethodBindVarArgBaseS<MethodBindVarArgTS, void, false> {
friend class MethodBindVarArgBaseS<MethodBindVarArgTS, void, false>;

public:
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
(void)p_instance; // unused
MethodBindVarArgBaseS<MethodBindVarArgTS, void, false>::function((const Variant **)p_args, p_argument_count, r_error);
return {};
}

MethodBindVarArgTS(
void (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
MethodBindVarArgBaseS<MethodBindVarArgTS, void, false>(p_function, p_method_info, p_return_nil_is_variant) {
}

private:
PropertyInfo _gen_return_type_info_impl() const {
return {};
}
};

MethodBind *create_vararg_method_bind(void (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant);

template <class R>
class MethodBindVarArgTRS : public MethodBindVarArgBaseS<MethodBindVarArgTRS<R>, R, true> {
friend class MethodBindVarArgBaseS<MethodBindVarArgTRS, R, true>;

public:
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
call_with_variant_args_static_dv(MethodBindVarArgBaseS<MethodBindVarArgTRS<R>, R, true>::function, p_args, p_argument_count, r_error);
return {};
}

MethodBindVarArgTRS(
void (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
MethodBindVarArgBaseS<MethodBindVarArgTRS<R>, R, true>(p_function, p_method_info, p_return_nil_is_variant) {
}

private:
PropertyInfo _gen_return_type_info_impl() const {
return {};
}
};

template <class R>
MethodBind *create_vararg_method_bind(R (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTRS<R>)(p_function, p_info, p_return_nil_is_variant));
return a;
}

#ifndef TYPED_METHOD_BIND
class _gde_UnexistingClass;
#define MB_T _gde_UnexistingClass
Expand Down
5 changes: 5 additions & 0 deletions src/core/method_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,9 @@ MethodBind::~MethodBind() {
}
}

MethodBind *create_vararg_method_bind(void (*p_function)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTS)(p_function, p_info, p_return_nil_is_variant));
return a;
}

} // namespace godot