Skip to content

Commit 0e3bc39

Browse files
committed
Fully register class on register_class call
1 parent fad6329 commit 0e3bc39

File tree

4 files changed

+122
-122
lines changed

4 files changed

+122
-122
lines changed

include/godot_cpp/core/class_db.hpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <godot_cpp/core/object.hpp>
4040

4141
#include <list>
42+
#include <set>
4243
#include <string>
4344
#include <unordered_map>
4445
#include <vector>
@@ -82,23 +83,19 @@ class ClassDB {
8283
const char *parent_name = nullptr;
8384
GDNativeInitializationLevel level = GDNATIVE_INITIALIZATION_SCENE;
8485
std::unordered_map<std::string, MethodBind *> method_map;
85-
std::unordered_map<std::string, MethodInfo> signal_map;
86-
std::list<MethodBind *> method_order;
87-
GDExtensionClassInstancePtr (*constructor)(void *data);
86+
std::set<std::string> signal_names;
8887
std::unordered_map<std::string, GDNativeExtensionClassCallVirtual> virtual_methods;
89-
void (*destructor)(void *data, GDExtensionClassInstancePtr ptr);
90-
void (*object_instance)(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance);
91-
std::unordered_map<std::string, PropertySetGet> property_setget;
92-
std::list<PropertyInfo> property_list;
93-
std::unordered_map<std::string, std::pair<std::string, GDNativeInt>> constant_map; // String in pair is enum name.
94-
std::list<std::string> constant_order;
88+
std::set<std::string> property_names;
89+
std::set<std::string> constant_names;
9590
ClassInfo *parent_ptr = nullptr;
9691
};
9792

9893
private:
9994
static std::unordered_map<std::string, ClassInfo> classes;
10095

10196
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
97+
static void initialize_class(const ClassInfo &cl);
98+
static void bind_method_godot(const char *p_class_name, MethodBind *p_method);
10299

103100
public:
104101
template <class T>
@@ -112,7 +109,7 @@ class ClassDB {
112109
static void add_property_subgroup(const char *p_class, const char *p_name, const char *p_prefix);
113110
static void add_property(const char *p_class, const PropertyInfo &p_pinfo, const char *p_setter, const char *p_getter, int p_index = -1);
114111
static void add_signal(const char *p_class, const MethodInfo &p_signal);
115-
static void bind_integer_constant(const char *p_class, const char *p_enum, const char *p_name, GDNativeInt p_constant);
112+
static void bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value);
116113
static void bind_virtual_method(const char *p_class, const char *p_method, GDNativeExtensionClassCallVirtual p_call);
117114

118115
static MethodBind *get_method(const char *p_class, const char *p_method);
@@ -139,18 +136,40 @@ class ClassDB {
139136

140137
template <class T>
141138
void ClassDB::register_class() {
139+
// Register this class within our plugin
142140
ClassInfo cl;
143141
cl.name = T::get_class_static();
144142
cl.parent_name = T::get_parent_class_static();
145143
cl.level = current_level;
146-
cl.constructor = T::create;
147-
cl.destructor = T::free;
148-
cl.object_instance = T::set_object_instance;
149144
classes[cl.name] = cl;
150145
if (classes.find(cl.parent_name) != classes.end()) {
151146
cl.parent_ptr = &classes[cl.parent_name];
152147
}
148+
149+
// Register this class with Godot
150+
GDNativeExtensionClassCreationInfo class_info = {
151+
nullptr, // GDNativeExtensionClassSet set_func;
152+
nullptr, // GDNativeExtensionClassGet get_func;
153+
nullptr, // GDNativeExtensionClassGetPropertyList get_property_list_func;
154+
nullptr, // GDNativeExtensionClassFreePropertyList free_property_list_func;
155+
nullptr, // GDNativeExtensionClassNotification notification_func;
156+
nullptr, // GDNativeExtensionClassToString to_string_func;
157+
nullptr, // GDNativeExtensionClassReference reference_func;
158+
nullptr, // GDNativeExtensionClassUnreference
159+
T::create, // GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
160+
T::free, // GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
161+
T::set_object_instance, // GDNativeExtensionClassObjectInstance object_instance_func; /* this one is mandatory */
162+
&ClassDB::get_virtual_func, // GDNativeExtensionClassGetVirtual get_virtual_func;
163+
(void *)cl.name, //void *class_userdata;
164+
};
165+
166+
internal::interface->classdb_register_extension_class(internal::library, cl.name, cl.parent_name, &class_info);
167+
168+
// call bind_methods etc. to register all members of the class
153169
T::initialize_class();
170+
171+
// now register our class within ClassDB within Godot
172+
initialize_class(classes[cl.name]);
154173
}
155174

156175
template <class N, class M>
@@ -183,8 +202,11 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, const char *p_name, M
183202
ERR_FAIL_V_MSG(nullptr, "Binding duplicate method.");
184203
}
185204

205+
// register our method bind within our plugin
186206
type.method_map[p_name] = bind;
187-
type.method_order.push_back(bind);
207+
208+
// and register with godot
209+
bind_method_godot(type.name, bind);
188210

189211
return bind;
190212
}

src/core/class_db.cpp

Lines changed: 77 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,21 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1) {
5555
void ClassDB::add_property_group(const char *p_class, const char *p_name, const char *p_prefix) {
5656
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), "Trying to add property to non-existing class.");
5757

58-
ClassInfo &info = classes[p_class];
59-
60-
info.property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
58+
internal::interface->classdb_register_extension_class_property_group(internal::library, p_class, p_name, p_prefix);
6159
}
6260

6361
void ClassDB::add_property_subgroup(const char *p_class, const char *p_name, const char *p_prefix) {
6462
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), "Trying to add property to non-existing class.");
6563

66-
ClassInfo &info = classes[p_class];
67-
68-
info.property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP));
64+
internal::interface->classdb_register_extension_class_property_subgroup(internal::library, p_class, p_name, p_prefix);
6965
}
7066

7167
void ClassDB::add_property(const char *p_class, const PropertyInfo &p_pinfo, const char *p_setter, const char *p_getter, int p_index) {
7268
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), "Trying to add property to non-existing class.");
7369

7470
ClassInfo &info = classes[p_class];
7571

76-
ERR_FAIL_COND_MSG(info.property_setget.find(p_pinfo.name) != info.property_setget.end(), "Property already exists in class.");
72+
ERR_FAIL_COND_MSG(info.property_names.find(p_pinfo.name) != info.property_names.end(), "Property already exists in class.");
7773

7874
MethodBind *setter = nullptr;
7975
if (p_setter) {
@@ -94,7 +90,18 @@ void ClassDB::add_property(const char *p_class, const PropertyInfo &p_pinfo, con
9490
ERR_FAIL_COND_MSG(exp_args != getter->get_argument_count(), "Getter method must not take any argument.");
9591
}
9692

97-
info.property_list.push_back(p_pinfo);
93+
// register property with plugin
94+
info.property_names.insert(p_pinfo.name);
95+
96+
// register with Godot
97+
GDNativePropertyInfo prop_info = {
98+
(uint32_t)p_pinfo.type, //uint32_t type;
99+
p_pinfo.name, //const char *name;
100+
p_pinfo.class_name, //const char *class_name;
101+
p_pinfo.hint, // NONE //uint32_t hint;
102+
p_pinfo.hint_string, // const char *hint_string;
103+
p_pinfo.usage, // DEFAULT //uint32_t usage;
104+
};
98105

99106
PropertySetGet setget;
100107
setget.setter = p_setter;
@@ -104,7 +111,7 @@ void ClassDB::add_property(const char *p_class, const PropertyInfo &p_pinfo, con
104111
setget.index = p_index;
105112
setget.type = p_pinfo.type;
106113

107-
info.property_setget[p_pinfo.name] = setget;
114+
internal::interface->classdb_register_extension_class_property(internal::library, info.name, &prop_info, setget.setter, setget.getter);
108115
}
109116

110117
MethodBind *ClassDB::get_method(const char *p_class, const char *p_method) {
@@ -162,38 +169,83 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M
162169

163170
p_bind->set_argument_names(args);
164171

165-
type.method_order.push_back(p_bind);
172+
// register our method bind within our plugin
166173
type.method_map[method_name.name] = p_bind;
167174

175+
// and register with godot
176+
bind_method_godot(type.name, p_bind);
177+
168178
return p_bind;
169179
}
170180

181+
void ClassDB::bind_method_godot(const char *p_class_name, MethodBind *p_method) {
182+
GDNativeExtensionClassMethodInfo method_info = {
183+
p_method->get_name(), //const char *name;
184+
p_method, //void *method_userdata;
185+
MethodBind::bind_call, //GDNativeExtensionClassMethodCall call_func;
186+
MethodBind::bind_ptrcall, //GDNativeExtensionClassMethodPtrCall ptrcall_func;
187+
GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT, //uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
188+
(uint32_t)p_method->get_argument_count(), //uint32_t argument_count;
189+
(GDNativeBool)p_method->has_return(), //GDNativeBool has_return_value;
190+
MethodBind::bind_get_argument_type, //(GDNativeExtensionClassMethodGetArgumentType) get_argument_type_func;
191+
MethodBind::bind_get_argument_info, //GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
192+
MethodBind::bind_get_argument_metadata, //GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
193+
p_method->get_hint_flags(), //uint32_t default_argument_count;
194+
nullptr, //GDNativeVariantPtr *default_arguments;
195+
};
196+
internal::interface->classdb_register_extension_class_method(internal::library, p_class_name, &method_info);
197+
}
198+
171199
void ClassDB::add_signal(const char *p_class, const MethodInfo &p_signal) {
172200
std::unordered_map<std::string, ClassInfo>::iterator type_it = classes.find(p_class);
173201

174202
ERR_FAIL_COND_MSG(type_it == classes.end(), "Class doesn't exist.");
175203

176-
ClassInfo &base = type_it->second;
177-
ClassInfo *check = &base;
204+
ClassInfo &cl = type_it->second;
205+
206+
// Check if this signal is already register
207+
ClassInfo *check = &cl;
178208
while (check) {
179-
ERR_FAIL_COND_MSG(check->signal_map.find(p_signal.name) != check->signal_map.end(), String("Class '" + String(p_class) + "' already has signal '" + String(p_signal.name) + "'.").utf8().get_data());
209+
ERR_FAIL_COND_MSG(check->signal_names.find(p_signal.name) != check->signal_names.end(), String("Class '" + String(p_class) + "' already has signal '" + String(p_signal.name) + "'.").utf8().get_data());
180210
check = check->parent_ptr;
181211
}
182212

183-
base.signal_map[p_signal.name] = p_signal;
213+
// register our signal in our plugin
214+
cl.signal_names.insert(p_signal.name);
215+
216+
// register our signal in godot
217+
std::vector<GDNativePropertyInfo> parameters;
218+
parameters.reserve(p_signal.arguments.size());
219+
220+
for (const PropertyInfo &par : p_signal.arguments) {
221+
parameters.push_back(GDNativePropertyInfo{
222+
static_cast<uint32_t>(par.type), // uint32_t type;
223+
par.name, // const char *name;
224+
par.class_name, // const char *class_name;
225+
par.hint, // uint32_t hint;
226+
par.hint_string, // const char *hint_string;
227+
par.usage, // uint32_t usage;
228+
});
229+
}
230+
231+
internal::interface->classdb_register_extension_class_signal(internal::library, cl.name, p_signal.name, parameters.data(), parameters.size());
184232
}
185233

186-
void ClassDB::bind_integer_constant(const char *p_class, const char *p_enum, const char *p_name, GDNativeInt p_constant) {
187-
std::unordered_map<std::string, ClassInfo>::iterator type_it = classes.find(p_class);
234+
void ClassDB::bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value) {
235+
std::unordered_map<std::string, ClassInfo>::iterator type_it = classes.find(p_class_name);
188236

189237
ERR_FAIL_COND_MSG(type_it == classes.end(), "Class doesn't exist.");
190238

191239
ClassInfo &type = type_it->second;
192240

193-
ERR_FAIL_COND_MSG(type.constant_map.find(p_name) != type.constant_map.end(), "Constant already registered.");
241+
// check if it already exists
242+
ERR_FAIL_COND_MSG(type.constant_names.find(p_constant_name) != type.constant_names.end(), "Constant already registered.");
243+
244+
// register it with our plugin (purely to check for duplicates)
245+
type.constant_names.insert(p_constant_name);
194246

195-
type.constant_map[p_name] = std::pair<std::string, GDNativeInt>{ p_enum, p_constant };
196-
type.constant_order.push_back(p_name);
247+
// Register it with Godot
248+
internal::interface->classdb_register_extension_class_integer_constant(internal::library, p_class_name, p_enum_name, p_constant_name, p_constant_value);
197249
}
198250

199251
GDNativeExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, const char *p_name) {
@@ -225,95 +277,17 @@ void ClassDB::bind_virtual_method(const char *p_class, const char *p_method, GDN
225277
type.virtual_methods[p_method] = p_call;
226278
}
227279

280+
void ClassDB::initialize_class(const ClassInfo &p_cl) {
281+
}
282+
228283
void ClassDB::initialize(GDNativeInitializationLevel p_level) {
229284
for (const std::pair<std::string, ClassInfo> pair : classes) {
230285
const ClassInfo &cl = pair.second;
231286
if (cl.level != p_level) {
232287
continue;
233288
}
234289

235-
GDNativeExtensionClassCreationInfo class_info = {
236-
nullptr, // GDNativeExtensionClassSet set_func;
237-
nullptr, // GDNativeExtensionClassGet get_func;
238-
nullptr, // GDNativeExtensionClassGetPropertyList get_property_list_func;
239-
nullptr, // GDNativeExtensionClassFreePropertyList free_property_list_func;
240-
nullptr, // GDNativeExtensionClassNotification notification_func;
241-
nullptr, // GDNativeExtensionClassToString to_string_func;
242-
nullptr, // GDNativeExtensionClassReference reference_func;
243-
nullptr, // GDNativeExtensionClassUnreference
244-
cl.constructor, // GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
245-
cl.destructor, // GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
246-
cl.object_instance, // GDNativeExtensionClassObjectInstance object_instance_func; /* this one is mandatory */
247-
&ClassDB::get_virtual_func, // GDNativeExtensionClassGetVirtual get_virtual_func;
248-
(void *)cl.name, //void *class_userdata;
249-
};
250-
251-
internal::interface->classdb_register_extension_class(internal::library, cl.name, cl.parent_name, &class_info);
252-
253-
for (MethodBind *method : cl.method_order) {
254-
GDNativeExtensionClassMethodInfo method_info = {
255-
method->get_name(), //const char *name;
256-
method, //void *method_userdata;
257-
MethodBind::bind_call, //GDNativeExtensionClassMethodCall call_func;
258-
MethodBind::bind_ptrcall, //GDNativeExtensionClassMethodPtrCall ptrcall_func;
259-
GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT, //uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
260-
(uint32_t)method->get_argument_count(), //uint32_t argument_count;
261-
(GDNativeBool)method->has_return(), //GDNativeBool has_return_value;
262-
MethodBind::bind_get_argument_type, //(GDNativeExtensionClassMethodGetArgumentType) get_argument_type_func;
263-
MethodBind::bind_get_argument_info, //GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
264-
MethodBind::bind_get_argument_metadata, //GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
265-
method->get_hint_flags(), //uint32_t default_argument_count;
266-
nullptr, //GDNativeVariantPtr *default_arguments;
267-
};
268-
internal::interface->classdb_register_extension_class_method(internal::library, cl.name, &method_info);
269-
}
270-
271-
for (const PropertyInfo &property : cl.property_list) {
272-
GDNativePropertyInfo info = {
273-
(uint32_t)property.type, //uint32_t type;
274-
property.name, //const char *name;
275-
property.class_name, //const char *class_name;
276-
property.hint, // NONE //uint32_t hint;
277-
property.hint_string, // const char *hint_string;
278-
property.usage, // DEFAULT //uint32_t usage;
279-
};
280-
281-
if (info.usage == PROPERTY_USAGE_GROUP) {
282-
internal::interface->classdb_register_extension_class_property_group(internal::library, cl.name, info.name, info.hint_string);
283-
} else if (info.usage == PROPERTY_USAGE_SUBGROUP) {
284-
internal::interface->classdb_register_extension_class_property_subgroup(internal::library, cl.name, info.name, info.hint_string);
285-
} else {
286-
const PropertySetGet &setget = cl.property_setget.find(property.name)->second;
287-
288-
internal::interface->classdb_register_extension_class_property(internal::library, cl.name, &info, setget.setter, setget.getter);
289-
}
290-
}
291-
292-
for (const std::pair<std::string, MethodInfo> pair : cl.signal_map) {
293-
const MethodInfo &signal = pair.second;
294-
295-
std::vector<GDNativePropertyInfo> parameters;
296-
parameters.reserve(signal.arguments.size());
297-
298-
for (const PropertyInfo &par : signal.arguments) {
299-
parameters.push_back(GDNativePropertyInfo{
300-
static_cast<uint32_t>(par.type), // uint32_t type;
301-
par.name, // const char *name;
302-
par.class_name, // const char *class_name;
303-
par.hint, // uint32_t hint;
304-
par.hint_string, // const char *hint_string;
305-
par.usage, // uint32_t usage;
306-
});
307-
}
308-
309-
internal::interface->classdb_register_extension_class_signal(internal::library, cl.name, pair.first.c_str(), parameters.data(), parameters.size());
310-
}
311-
312-
for (std::string constant : cl.constant_order) {
313-
const std::pair<std::string, GDNativeInt> &def = cl.constant_map.find(constant)->second;
314-
315-
internal::interface->classdb_register_extension_class_integer_constant(internal::library, cl.name, def.first.c_str(), constant.c_str(), def.second);
316-
}
290+
// Nothing to do here for now...
317291
}
318292
}
319293

@@ -326,8 +300,8 @@ void ClassDB::deinitialize(GDNativeInitializationLevel p_level) {
326300

327301
internal::interface->classdb_unregister_extension_class(internal::library, cl.name);
328302

329-
for (MethodBind *method : cl.method_order) {
330-
memdelete(method);
303+
for (auto method : cl.method_map) {
304+
memdelete(method.second);
331305
}
332306
}
333307
}

test/demo/main.gd

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
extends Node
22

33
func _ready():
4-
# Connect signals.
5-
$Button.button_up.connect($Example.emit_custom_signal, ["Button", 42])
6-
$Example.custom_signal.connect(on_signal)
7-
4+
# Bind signals
5+
$Button.button_up.connect($Example.emit_custom_signal.bind("Button", 42))
6+
87
# Call methods.
98
$Example.simple_func()
109
($Example as Example).simple_const_func() # Force use of ptrcall
@@ -23,5 +22,5 @@ func _ready():
2322
prints("ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING)
2423
prints("CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM)
2524

26-
func on_signal(name, value):
25+
func _on_Example_custom_signal(name, value):
2726
prints("Example emitted:", name, value)

0 commit comments

Comments
 (0)