diff options
author | David Snopek <dsnopek@gmail.com> | 2023-10-21 18:32:45 -0500 |
---|---|---|
committer | David Snopek <dsnopek@gmail.com> | 2023-11-06 00:09:06 -0600 |
commit | d33bd47219314e825d1130e646bc34f52fe65600 (patch) | |
tree | a3807017aeaefffa6bcda77f1fcebef436de4047 /src | |
parent | 2dfe7929de31e52258380e414cce6978c1c94344 (diff) | |
download | redot-cpp-d33bd47219314e825d1130e646bc34f52fe65600.tar.gz |
Add `CallableCustom` that devs can use in their GDExtensions
Diffstat (limited to 'src')
-rw-r--r-- | src/godot.cpp | 2 | ||||
-rw-r--r-- | src/variant/callable_custom.cpp | 113 | ||||
-rw-r--r-- | src/variant/callable_method_pointer.cpp | 16 |
3 files changed, 121 insertions, 10 deletions
diff --git a/src/godot.cpp b/src/godot.cpp index 7579cfd..70c5978 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -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; @@ -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); diff --git a/src/variant/callable_custom.cpp b/src/variant/callable_custom.cpp new file mode 100644 index 0000000..e0540fa --- /dev/null +++ b/src/variant/callable_custom.cpp @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* callable_custom.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#include <godot_cpp/variant/callable_custom.hpp> + +#include <godot_cpp/core/object.hpp> +#include <godot_cpp/variant/callable.hpp> + +namespace godot { + +static void callable_custom_call(void *p_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) { + CallableCustom *callable_custom = (CallableCustom *)p_userdata; + callable_custom->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error); +} + +static GDExtensionBool callable_custom_is_valid(void *p_userdata) { + CallableCustom *callable_custom = (CallableCustom *)p_userdata; + return callable_custom->is_valid(); +} + +static void callable_custom_free(void *p_userdata) { + CallableCustom *callable_custom = (CallableCustom *)p_userdata; + memdelete(callable_custom); +} + +static uint32_t callable_custom_hash(void *p_userdata) { + CallableCustom *callable_custom = (CallableCustom *)p_userdata; + return callable_custom->hash(); +} + +static void callable_custom_to_string(void *p_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { + CallableCustom *callable_custom = (CallableCustom *)p_userdata; + *((String *)r_out) = callable_custom->get_as_text(); + *r_is_valid = true; +} + +static GDExtensionBool callable_custom_equal_func(void *p_a, void *p_b) { + CallableCustom *a = (CallableCustom *)p_a; + CallableCustom *b = (CallableCustom *)p_b; + CallableCustom::CompareEqualFunc func_a = a->get_compare_equal_func(); + CallableCustom::CompareEqualFunc func_b = b->get_compare_equal_func(); + if (func_a != func_b) { + return false; + } + return func_a(a, b); +} + +static GDExtensionBool callable_custom_less_than_func(void *p_a, void *p_b) { + CallableCustom *a = (CallableCustom *)p_a; + CallableCustom *b = (CallableCustom *)p_b; + CallableCustom::CompareEqualFunc func_a = a->get_compare_less_func(); + CallableCustom::CompareEqualFunc func_b = b->get_compare_less_func(); + if (func_a != func_b) { + // Just compare the addresses. + return p_a < p_b; + } + return func_a(a, b); +} + +bool CallableCustom::is_valid() const { + // The same default implementation as in Godot. + return ObjectDB::get_instance(get_object()); +} + +Callable::Callable(CallableCustom *p_callable_custom) { + GDExtensionCallableCustomInfo info = {}; + info.callable_userdata = p_callable_custom; + info.token = internal::token; + info.object_id = p_callable_custom->get_object(); + info.call_func = &callable_custom_call; + info.is_valid_func = &callable_custom_is_valid; + info.free_func = &callable_custom_free; + info.hash_func = &callable_custom_hash; + info.equal_func = &callable_custom_equal_func; + info.less_than_func = &callable_custom_less_than_func; + info.to_string_func = &callable_custom_to_string; + + ::godot::internal::gdextension_interface_callable_custom_create(_native_ptr(), &info); +} + +CallableCustom *Callable::get_custom() const { + CallableCustomBase *callable_custom = (CallableCustomBase *)::godot::internal::gdextension_interface_callable_custom_get_userdata(_native_ptr(), internal::token); + return dynamic_cast<CallableCustom *>(callable_custom); +} + +} // namespace godot diff --git a/src/variant/callable_method_pointer.cpp b/src/variant/callable_method_pointer.cpp index ea43632..10f2920 100644 --- a/src/variant/callable_method_pointer.cpp +++ b/src/variant/callable_method_pointer.cpp @@ -30,31 +30,27 @@ #include <godot_cpp/variant/callable_method_pointer.hpp> -//#include <godot_cpp/godot.hpp> - namespace godot { -static void call_custom_callable(void *userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) { +static void custom_callable_mp_call(void *userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) { CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)userdata; callable_method_pointer->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error); } -static void free_custom_callable(void *userdata) { +static void custom_callable_mp_free(void *userdata) { CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)userdata; memdelete(callable_method_pointer); } namespace internal { -Callable create_custom_callable(CallableCustomMethodPointerBase *p_callable_method_pointer) { - Object *object = p_callable_method_pointer->get_object(); - +Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer) { GDExtensionCallableCustomInfo info = {}; info.callable_userdata = p_callable_method_pointer; info.token = internal::token; - info.object_id = object ? object->get_instance_id() : 0; - info.call_func = &call_custom_callable; - info.free_func = &free_custom_callable; + info.object_id = p_callable_method_pointer->get_object(); + info.call_func = &custom_callable_mp_call; + info.free_func = &custom_callable_mp_free; Callable callable; ::godot::internal::gdextension_interface_callable_custom_create(callable._native_ptr(), &info); |