From 2ffff669f557351e85423e9edbc7a0e6520b613e Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Mon, 3 Jul 2023 12:51:54 -0500 Subject: [PATCH] Implement typed dictionaries --- binding_generator.py | 72 ++++++ include/godot_cpp/core/type_info.hpp | 201 +++++++++++++++ include/godot_cpp/godot.hpp | 1 + .../godot_cpp/variant/typed_dictionary.hpp | 238 ++++++++++++++++++ src/godot.cpp | 2 + src/variant/packed_arrays.cpp | 6 + test/project/main.gd | 7 +- test/src/example.cpp | 19 ++ test/src/example.h | 2 + 9 files changed, 546 insertions(+), 2 deletions(-) create mode 100644 include/godot_cpp/variant/typed_dictionary.hpp diff --git a/binding_generator.py b/binding_generator.py index 71afe047e..b8b76ba93 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -672,6 +672,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl for include in fully_used_classes: if include == "TypedArray": includes.append("godot_cpp/variant/typed_array.hpp") + elif include == "TypedDictionary": + includes.append("godot_cpp/variant/typed_dictionary.hpp") else: includes.append(f"godot_cpp/{get_include_path(include)}") @@ -1022,6 +1024,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl if class_name == "Dictionary": result.append("\tconst Variant &operator[](const Variant &p_key) const;") result.append("\tVariant &operator[](const Variant &p_key);") + result.append( + "\tvoid set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script);" + ) result.append("};") @@ -1438,6 +1443,32 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): fully_used_classes.add(array_type_name) else: used_classes.add(array_type_name) + elif type_name.startswith("typeddictionary::"): + fully_used_classes.add("TypedDictionary") + dict_type_name = type_name.replace("typeddictionary::", "") + if dict_type_name.startswith("const "): + dict_type_name = dict_type_name[6:] + dict_type_names = dict_type_name.split(";") + dict_type_name = dict_type_names[0] + if dict_type_name.endswith("*"): + dict_type_name = dict_type_name[:-1] + if is_included(dict_type_name, class_name): + if is_enum(dict_type_name): + fully_used_classes.add(get_enum_class(dict_type_name)) + elif "default_value" in argument: + fully_used_classes.add(dict_type_name) + else: + used_classes.add(dict_type_name) + dict_type_name = dict_type_names[2] + if dict_type_name.endswith("*"): + dict_type_name = dict_type_name[:-1] + if is_included(dict_type_name, class_name): + if is_enum(dict_type_name): + fully_used_classes.add(get_enum_class(dict_type_name)) + elif "default_value" in argument: + fully_used_classes.add(dict_type_name) + else: + used_classes.add(dict_type_name) elif is_enum(type_name): fully_used_classes.add(get_enum_class(type_name)) elif "default_value" in argument: @@ -1467,6 +1498,32 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): fully_used_classes.add(array_type_name) else: used_classes.add(array_type_name) + elif type_name.startswith("typeddictionary::"): + fully_used_classes.add("TypedDictionary") + dict_type_name = type_name.replace("typeddictionary::", "") + if dict_type_name.startswith("const "): + dict_type_name = dict_type_name[6:] + dict_type_names = dict_type_name.split(";") + dict_type_name = dict_type_names[0] + if dict_type_name.endswith("*"): + dict_type_name = dict_type_name[:-1] + if is_included(dict_type_name, class_name): + if is_enum(dict_type_name): + fully_used_classes.add(get_enum_class(dict_type_name)) + elif is_variant(dict_type_name): + fully_used_classes.add(dict_type_name) + else: + used_classes.add(dict_type_name) + dict_type_name = dict_type_names[2] + if dict_type_name.endswith("*"): + dict_type_name = dict_type_name[:-1] + if is_included(dict_type_name, class_name): + if is_enum(dict_type_name): + fully_used_classes.add(get_enum_class(dict_type_name)) + elif is_variant(dict_type_name): + fully_used_classes.add(dict_type_name) + else: + used_classes.add(dict_type_name) elif is_enum(type_name): fully_used_classes.add(get_enum_class(type_name)) elif is_variant(type_name): @@ -1600,6 +1657,8 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us for included in fully_used_classes: if included == "TypedArray": includes.append("godot_cpp/variant/typed_array.hpp") + elif included == "TypedDictionary": + includes.append("godot_cpp/variant/typed_dictionary.hpp") else: includes.append(f"godot_cpp/{get_include_path(included)}") @@ -2688,6 +2747,7 @@ def is_variant(type_name): or type_name in builtin_classes or type_name == "Nil" or type_name.startswith("typedarray::") + or type_name.startswith("typeddictionary::") ) @@ -2727,6 +2787,8 @@ def is_included(type_name, current_type): """ if type_name.startswith("typedarray::"): return True + if type_name.startswith("typeddictionary::"): + return True to_include = get_enum_class(type_name) if is_enum(type_name) else type_name if to_include == current_type or is_pod_type(to_include): return False @@ -2765,6 +2827,12 @@ def correct_typed_array(type_name): return type_name +def correct_typed_dictionary(type_name): + if type_name.startswith("typeddictionary::"): + return type_name.replace("typeddictionary::", "TypedDictionary<").replace(";", ", ") + ">" + return type_name + + def correct_type(type_name, meta=None, use_alias=True): type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"} if meta is not None: @@ -2778,6 +2846,8 @@ def correct_type(type_name, meta=None, use_alias=True): return type_conversion[type_name] if type_name.startswith("typedarray::"): return type_name.replace("typedarray::", "TypedArray<") + ">" + if type_name.startswith("typeddictionary::"): + return type_name.replace("typeddictionary::", "TypedDictionary<").replace(";", ", ") + ">" if is_enum(type_name): if is_bitfield(type_name): base_class = get_enum_class(type_name) @@ -2924,6 +2994,8 @@ def get_default_value_for_type(type_name): return "false" if type_name.startswith("typedarray::"): return f"{correct_type(type_name)}()" + if type_name.startswith("typeddictionary::"): + return f"{correct_type(type_name)}()" if is_enum(type_name): return f"{correct_type(type_name)}(0)" if is_variant(type_name): diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index b78f7e73b..d847598a3 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -413,6 +414,206 @@ MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING) #undef MAKE_TYPED_ARRAY_INFO +template +struct PtrToArg> { + _FORCE_INLINE_ static TypedDictionary convert(const void *p_ptr) { + return TypedDictionary(*reinterpret_cast(p_ptr)); + } + typedef Dictionary EncodeT; + _FORCE_INLINE_ static void encode(TypedDictionary p_val, void *p_ptr) { + *(Dictionary *)p_ptr = p_val; + } +}; + +template +struct PtrToArg &> { + typedef Dictionary EncodeT; + _FORCE_INLINE_ static TypedDictionary + convert(const void *p_ptr) { + return TypedDictionary(*reinterpret_cast(p_ptr)); + } +}; + +template +struct GetTypeInfo> { + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static())); + } +}; + +template +struct GetTypeInfo &> { + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static())); + } +}; + +#define MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \ + template \ + struct GetTypeInfo> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \ + } \ + }; \ + template \ + struct GetTypeInfo &> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \ + } \ + }; \ + template \ + struct GetTypeInfo> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \ + } \ + }; \ + template \ + struct GetTypeInfo &> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \ + } \ + }; + +#define MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \ + template <> \ + struct GetTypeInfo> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \ + m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \ + } \ + }; \ + template <> \ + struct GetTypeInfo &> { \ + static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \ + static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \ + vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \ + m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \ + } \ + }; + +#define MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \ + /* MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING) */ + +#define MAKE_TYPED_DICTIONARY_INFO(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \ + MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type) + +MAKE_TYPED_DICTIONARY_INFO_NIL(Variant, Variant::NIL) +MAKE_TYPED_DICTIONARY_INFO(bool, Variant::BOOL) +MAKE_TYPED_DICTIONARY_INFO(uint8_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(int8_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(uint16_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(int16_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(uint32_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(int32_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(uint64_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(int64_t, Variant::INT) +MAKE_TYPED_DICTIONARY_INFO(float, Variant::FLOAT) +MAKE_TYPED_DICTIONARY_INFO(double, Variant::FLOAT) +MAKE_TYPED_DICTIONARY_INFO(String, Variant::STRING) +MAKE_TYPED_DICTIONARY_INFO(Vector2, Variant::VECTOR2) +MAKE_TYPED_DICTIONARY_INFO(Vector2i, Variant::VECTOR2I) +MAKE_TYPED_DICTIONARY_INFO(Rect2, Variant::RECT2) +MAKE_TYPED_DICTIONARY_INFO(Rect2i, Variant::RECT2I) +MAKE_TYPED_DICTIONARY_INFO(Vector3, Variant::VECTOR3) +MAKE_TYPED_DICTIONARY_INFO(Vector3i, Variant::VECTOR3I) +MAKE_TYPED_DICTIONARY_INFO(Transform2D, Variant::TRANSFORM2D) +MAKE_TYPED_DICTIONARY_INFO(Plane, Variant::PLANE) +MAKE_TYPED_DICTIONARY_INFO(Quaternion, Variant::QUATERNION) +MAKE_TYPED_DICTIONARY_INFO(AABB, Variant::AABB) +MAKE_TYPED_DICTIONARY_INFO(Basis, Variant::BASIS) +MAKE_TYPED_DICTIONARY_INFO(Transform3D, Variant::TRANSFORM3D) +MAKE_TYPED_DICTIONARY_INFO(Color, Variant::COLOR) +MAKE_TYPED_DICTIONARY_INFO(StringName, Variant::STRING_NAME) +MAKE_TYPED_DICTIONARY_INFO(NodePath, Variant::NODE_PATH) +MAKE_TYPED_DICTIONARY_INFO(RID, Variant::RID) +MAKE_TYPED_DICTIONARY_INFO(Callable, Variant::CALLABLE) +MAKE_TYPED_DICTIONARY_INFO(Signal, Variant::SIGNAL) +MAKE_TYPED_DICTIONARY_INFO(Dictionary, Variant::DICTIONARY) +MAKE_TYPED_DICTIONARY_INFO(Array, Variant::ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) +MAKE_TYPED_DICTIONARY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY) +/* +MAKE_TYPED_DICTIONARY_INFO(IPAddress, Variant::STRING) +*/ + +#undef MAKE_TYPED_DICTIONARY_INFO +#undef MAKE_TYPED_DICTIONARY_INFO_NIL +#undef MAKE_TYPED_DICTIONARY_INFO_EXPANDED +#undef MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT + #define CLASS_INFO(m_type) (GetTypeInfo::get_class_info()) } // namespace godot diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 61dbb9606..f41043946 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -158,6 +158,7 @@ extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref; extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed; extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index; extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const; +extern "C" GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed; extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call; extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall; extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy; diff --git a/include/godot_cpp/variant/typed_dictionary.hpp b/include/godot_cpp/variant/typed_dictionary.hpp new file mode 100644 index 000000000..e7f35352c --- /dev/null +++ b/include/godot_cpp/variant/typed_dictionary.hpp @@ -0,0 +1,238 @@ +/**************************************************************************/ +/* typed_dictionary.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_TYPED_DICTIONARY_HPP +#define GODOT_TYPED_DICTIONARY_HPP + +#include +#include + +namespace godot { + +template +class TypedDictionary : public Dictionary { +public: + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign a dictionary with a different element type."); + Dictionary::operator=(p_dictionary); + } + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : + TypedDictionary(Dictionary(p_variant)) { + } + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { + set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant()); + if (is_same_typed(p_dictionary)) { + Dictionary::operator=(p_dictionary); + } else { + assign(p_dictionary); + } + } + _FORCE_INLINE_ TypedDictionary() { + set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant()); + } +}; + +//specialization for the rest of variant types + +#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \ + template \ + class TypedDictionary : public Dictionary { \ + public: \ + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ + Dictionary::operator=(p_dictionary); \ + } \ + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ + TypedDictionary(Dictionary(p_variant)) { \ + } \ + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ + set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ + if (is_same_typed(p_dictionary)) { \ + Dictionary::operator=(p_dictionary); \ + } else { \ + assign(p_dictionary); \ + } \ + } \ + _FORCE_INLINE_ TypedDictionary() { \ + set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ + } \ + }; \ + template \ + class TypedDictionary : public Dictionary { \ + public: \ + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ + Dictionary::operator=(p_dictionary); \ + } \ + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ + TypedDictionary(Dictionary(p_variant)) { \ + } \ + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ + set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ + if (is_same_typed(p_dictionary)) { \ + Dictionary::operator=(p_dictionary); \ + } else { \ + assign(p_dictionary); \ + } \ + } \ + _FORCE_INLINE_ TypedDictionary() { \ + set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ + } \ + }; + +#define MAKE_TYPED_DICTIONARY_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \ + template <> \ + class TypedDictionary : public Dictionary { \ + public: \ + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ + Dictionary::operator=(p_dictionary); \ + } \ + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ + TypedDictionary(Dictionary(p_variant)) { \ + } \ + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ + set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \ + if (is_same_typed(p_dictionary)) { \ + Dictionary::operator=(p_dictionary); \ + } else { \ + assign(p_dictionary); \ + } \ + } \ + _FORCE_INLINE_ TypedDictionary() { \ + set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \ + } \ + }; + +#define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \ + /*MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING)*/ + +#define MAKE_TYPED_DICTIONARY(m_type, m_variant_type) \ + MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \ + MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) + +MAKE_TYPED_DICTIONARY_NIL(Variant, Variant::NIL) +MAKE_TYPED_DICTIONARY(bool, Variant::BOOL) +MAKE_TYPED_DICTIONARY(uint8_t, Variant::INT) +MAKE_TYPED_DICTIONARY(int8_t, Variant::INT) +MAKE_TYPED_DICTIONARY(uint16_t, Variant::INT) +MAKE_TYPED_DICTIONARY(int16_t, Variant::INT) +MAKE_TYPED_DICTIONARY(uint32_t, Variant::INT) +MAKE_TYPED_DICTIONARY(int32_t, Variant::INT) +MAKE_TYPED_DICTIONARY(uint64_t, Variant::INT) +MAKE_TYPED_DICTIONARY(int64_t, Variant::INT) +MAKE_TYPED_DICTIONARY(float, Variant::FLOAT) +MAKE_TYPED_DICTIONARY(double, Variant::FLOAT) +MAKE_TYPED_DICTIONARY(String, Variant::STRING) +MAKE_TYPED_DICTIONARY(Vector2, Variant::VECTOR2) +MAKE_TYPED_DICTIONARY(Vector2i, Variant::VECTOR2I) +MAKE_TYPED_DICTIONARY(Rect2, Variant::RECT2) +MAKE_TYPED_DICTIONARY(Rect2i, Variant::RECT2I) +MAKE_TYPED_DICTIONARY(Vector3, Variant::VECTOR3) +MAKE_TYPED_DICTIONARY(Vector3i, Variant::VECTOR3I) +MAKE_TYPED_DICTIONARY(Transform2D, Variant::TRANSFORM2D) +MAKE_TYPED_DICTIONARY(Plane, Variant::PLANE) +MAKE_TYPED_DICTIONARY(Quaternion, Variant::QUATERNION) +MAKE_TYPED_DICTIONARY(AABB, Variant::AABB) +MAKE_TYPED_DICTIONARY(Basis, Variant::BASIS) +MAKE_TYPED_DICTIONARY(Transform3D, Variant::TRANSFORM3D) +MAKE_TYPED_DICTIONARY(Color, Variant::COLOR) +MAKE_TYPED_DICTIONARY(StringName, Variant::STRING_NAME) +MAKE_TYPED_DICTIONARY(NodePath, Variant::NODE_PATH) +MAKE_TYPED_DICTIONARY(RID, Variant::RID) +MAKE_TYPED_DICTIONARY(Callable, Variant::CALLABLE) +MAKE_TYPED_DICTIONARY(Signal, Variant::SIGNAL) +MAKE_TYPED_DICTIONARY(Dictionary, Variant::DICTIONARY) +MAKE_TYPED_DICTIONARY(Array, Variant::ARRAY) +MAKE_TYPED_DICTIONARY(PackedByteArray, Variant::PACKED_BYTE_ARRAY) +MAKE_TYPED_DICTIONARY(PackedInt32Array, Variant::PACKED_INT32_ARRAY) +MAKE_TYPED_DICTIONARY(PackedInt64Array, Variant::PACKED_INT64_ARRAY) +MAKE_TYPED_DICTIONARY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) +MAKE_TYPED_DICTIONARY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) +MAKE_TYPED_DICTIONARY(PackedStringArray, Variant::PACKED_STRING_ARRAY) +MAKE_TYPED_DICTIONARY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) +MAKE_TYPED_DICTIONARY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) +MAKE_TYPED_DICTIONARY(PackedColorArray, Variant::PACKED_COLOR_ARRAY) +MAKE_TYPED_DICTIONARY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) +/* +MAKE_TYPED_DICTIONARY(IPAddress, Variant::STRING) +*/ + +#undef MAKE_TYPED_DICTIONARY +#undef MAKE_TYPED_DICTIONARY_NIL +#undef MAKE_TYPED_DICTIONARY_EXPANDED +#undef MAKE_TYPED_DICTIONARY_WITH_OBJECT + +} // namespace godot + +#endif // GODOT_TYPED_DICTIONARY_HPP diff --git a/src/godot.cpp b/src/godot.cpp index f6d0d43c1..68da08f7f 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -164,6 +164,7 @@ GDExtensionInterfaceArrayRef gdextension_interface_array_ref = nullptr; GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed = nullptr; GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index = nullptr; GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const = nullptr; +GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed = nullptr; GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call = nullptr; GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall = nullptr; GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy = nullptr; @@ -443,6 +444,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(array_set_typed, GDExtensionInterfaceArraySetTyped); LOAD_PROC_ADDRESS(dictionary_operator_index, GDExtensionInterfaceDictionaryOperatorIndex); LOAD_PROC_ADDRESS(dictionary_operator_index_const, GDExtensionInterfaceDictionaryOperatorIndexConst); + LOAD_PROC_ADDRESS(dictionary_set_typed, GDExtensionInterfaceDictionarySetTyped); LOAD_PROC_ADDRESS(object_method_bind_call, GDExtensionInterfaceObjectMethodBindCall); LOAD_PROC_ADDRESS(object_method_bind_ptrcall, GDExtensionInterfaceObjectMethodBindPtrcall); LOAD_PROC_ADDRESS(object_destroy, GDExtensionInterfaceObjectDestroy); diff --git a/src/variant/packed_arrays.cpp b/src/variant/packed_arrays.cpp index 4384f7adc..8fe8a7338 100644 --- a/src/variant/packed_arrays.cpp +++ b/src/variant/packed_arrays.cpp @@ -246,4 +246,10 @@ Variant &Dictionary::operator[](const Variant &p_key) { return *var; } +void Dictionary::set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script) { + // p_key_type/p_value_type are not Variant::Type so that header doesn't depend on . + internal::gdextension_interface_dictionary_set_typed((GDExtensionTypePtr *)this, (GDExtensionVariantType)p_key_type, (GDExtensionConstStringNamePtr)&p_key_class_name, (GDExtensionConstVariantPtr)&p_key_script, + (GDExtensionVariantType)p_value_type, (GDExtensionConstStringNamePtr)&p_value_class_name, (GDExtensionConstVariantPtr)&p_value_script); +} + } // namespace godot diff --git a/test/project/main.gd b/test/project/main.gd index b2625b9a0..386d1883f 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -81,10 +81,13 @@ func _ready(): # Array and Dictionary assert_equal(example.test_array(), [1, 2]) - assert_equal(example.test_tarray(), [ Vector2(1, 2), Vector2(2, 3) ]) - assert_equal(example.test_dictionary(), {"hello": "world", "foo": "bar"}) + assert_equal(example.test_tarray(), [Vector2(1, 2), Vector2(2, 3)]) var array: Array[int] = [1, 2, 3] assert_equal(example.test_tarray_arg(array), 6) + assert_equal(example.test_dictionary(), { "hello": "world", "foo": "bar" }) + assert_equal(example.test_tdictionary(), { Vector2(1, 2): Vector2i(2, 3) }) + var dictionary: Dictionary[String, int] = { "1": 1, "2": 2, "3": 3 } + assert_equal(example.test_tdictionary_arg(dictionary), 6) example.callable_bind() assert_equal(custom_signal_emitted, ["bound", 11]) diff --git a/test/src/example.cpp b/test/src/example.cpp index 8075f551d..692d00477 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -199,6 +199,8 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg); ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray); ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary); + ClassDB::bind_method(D_METHOD("test_tdictionary_arg", "dictionary"), &Example::test_tdictionary_arg); + ClassDB::bind_method(D_METHOD("test_tdictionary"), &Example::test_tdictionary); ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument); ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops); ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility); @@ -551,6 +553,23 @@ Dictionary Example::test_dictionary() const { return dict; } +int Example::test_tdictionary_arg(const TypedDictionary &p_dictionary) { + int sum = 0; + TypedArray values = p_dictionary.values(); + for (int i = 0; i < p_dictionary.size(); i++) { + sum += (int)values[i]; + } + return sum; +} + +TypedDictionary Example::test_tdictionary() const { + TypedDictionary dict; + + dict[Vector2(1, 2)] = Vector2i(2, 3); + + return dict; +} + Example *Example::test_node_argument(Example *p_node) const { return p_node; } diff --git a/test/src/example.h b/test/src/example.h index 6d88cf111..a28deffe0 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -129,6 +129,8 @@ class Example : public Control { int test_tarray_arg(const TypedArray &p_array); TypedArray test_tarray() const; Dictionary test_dictionary() const; + int test_tdictionary_arg(const TypedDictionary &p_dictionary); + TypedDictionary test_tdictionary() const; Example *test_node_argument(Example *p_node) const; String test_string_ops() const; String test_str_utility() const;