diff options
-rw-r--r-- | modules/gdnative/SCsub | 58 | ||||
-rw-r--r-- | modules/gdnative/doc_classes/NativeScript.xml | 38 | ||||
-rw-r--r-- | modules/gdnative/gdnative_api.json | 101 | ||||
-rw-r--r-- | modules/gdnative/include/nativescript/godot_nativescript.h | 46 | ||||
-rw-r--r-- | modules/gdnative/nativescript/godot_nativescript.cpp | 164 | ||||
-rw-r--r-- | modules/gdnative/nativescript/nativescript.cpp | 216 | ||||
-rw-r--r-- | modules/gdnative/nativescript/nativescript.h | 32 | ||||
-rw-r--r-- | modules/gdnative/nativescript/register_types.cpp | 1 |
8 files changed, 635 insertions, 21 deletions
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index c92c3f30a2..fd9df2673b 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -66,19 +66,30 @@ def _build_gdnative_api_struct_header(api): out += ['};', ''] - for name in api['extensions']: - out += [ - 'typedef struct godot_gdnative_ext_' + name + '_api_struct {', + + def generate_extension_struct(name, ext, include_version=True): + ret_val = [] + if ext['next']: + ret_val += generate_extension_struct(name, ext['next']) + + ret_val += [ + 'typedef struct godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct {', '\tunsigned int type;', '\tgodot_gdnative_api_version version;', '\tconst godot_gdnative_api_struct *next;' ] - for funcdef in api['extensions'][name]['api']: + for funcdef in ext['api']: args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']]) - out.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args)) + ret_val.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args)) + + ret_val += ['} godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct;', ''] + + return ret_val - out += ['} godot_gdnative_ext_' + name + '_api_struct;', ''] + + for name in api['extensions']: + out += generate_extension_struct(name, api['extensions'][name], False) out += [ 'typedef struct godot_gdnative_core_api_struct {', @@ -113,18 +124,35 @@ def _build_gdnative_api_struct_source(api): '' ] - for name in api['extensions']: - out += [ - 'extern const godot_gdnative_ext_' + name + '_api_struct api_extension_' + name + '_struct = {', - '\tGDNATIVE_EXT_' + api['extensions'][name]['type'] + ',', - '\t{' + str(api['extensions'][name]['version']['major']) + ', ' + str(api['extensions'][name]['version']['minor']) + '},', - '\tNULL,' + def get_extension_struct_name(name, ext, include_version=True): + return 'godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct' + + def get_extension_struct_instance_name(name, ext, include_version=True): + return 'api_extension_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_struct' + + def get_extension_struct_definition(name, ext, include_version=True): + + ret_val = [] + + if ext['next']: + ret_val += get_extension_struct_definition(name, ext['next']) + + ret_val += [ + 'extern const ' + get_extension_struct_name(name, ext, include_version) + ' ' + get_extension_struct_instance_name(name, ext, include_version) + ' = {', + '\tGDNATIVE_EXT_' + ext['type'] + ',', + '\t{' + str(ext['version']['major']) + ', ' + str(ext['version']['minor']) + '},', + '\t' + ('NULL' if not ext['next'] else ('(const godot_gdnative_api_struct *)&' + get_extension_struct_instance_name(name, ext['next']))) + ',' ] - for funcdef in api['extensions'][name]['api']: - out.append('\t%s,' % funcdef['name']) + for funcdef in ext['api']: + ret_val.append('\t%s,' % funcdef['name']) + + ret_val += ['};\n'] - out += ['};\n'] + return ret_val + + for name in api['extensions']: + out += get_extension_struct_definition(name, api['extensions'][name], False) out += ['', 'const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {'] diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index f713e4112e..6a71cd8d4d 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NativeScript" inherits="Script" category="Core" version="3.0-stable"> +<class name="NativeScript" inherits="Script" category="Core" version="3.1-dev"> <brief_description> </brief_description> <description> @@ -9,10 +9,46 @@ <demos> </demos> <methods> + <method name="get_class_documentation" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_class_documentation[/code]. + </description> + </method> + <method name="get_method_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="method" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_method_documentation[/code]. + </description> + </method> + <method name="get_property_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_property_documentation[/code]. + </description> + </method> + <method name="get_signal_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="signal_name" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_signal_documentation[/code]. + </description> + </method> <method name="new" qualifiers="vararg"> <return type="Object"> </return> <description> + Constructs a new object of the base type with a script of this type already attached. + [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. </description> </method> </methods> diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 59a9c0b090..57fdb13b3a 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -5,6 +5,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_color_new_rgba", @@ -5762,6 +5763,104 @@ "major": 1, "minor": 0 }, + "next": { + "type": "NATIVESCRIPT", + "version": { + "major": 1, + "minor": 1 + }, + "next": null, + "api": [ + { + "name": "godot_nativescript_set_method_argument_information", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_function_name"], + ["int", "p_num_args"], + ["const godot_method_arg *", "p_args"] + ] + }, + { + "name": "godot_nativescript_set_class_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_method_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_function_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_property_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_path"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_signal_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_signal_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_type_tag", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const void *", "p_type_tag"] + ] + }, + { + "name": "godot_nativescript_get_type_tag", + "return_type": "const void *", + "arguments": [ + ["const godot_object *", "p_object"] + ] + }, + { + "name": "godot_nativescript_register_instance_binding_data_functions", + "return_type": "int", + "arguments": [ + ["godot_instance_binding_functions", "p_binding_functions"] + ] + }, + { + "name": "godot_nativescript_unregister_instance_binding_data_functions", + "return_type": "void", + "arguments": [ + ["int", "p_idx"] + ] + }, + { + "name": "godot_nativescript_get_instance_binding_data", + "return_type": "void *", + "arguments": [ + ["int", "p_idx"], + ["godot_object *", "p_object"] + ] + } + ] + }, "api": [ { "name": "godot_nativescript_register_class", @@ -5832,6 +5931,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_pluginscript_register_language", @@ -5848,6 +5948,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_arvr_register_interface", diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h index 11017ae78d..747328bc41 100644 --- a/modules/gdnative/include/nativescript/godot_nativescript.h +++ b/modules/gdnative/include/nativescript/godot_nativescript.h @@ -185,6 +185,52 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance); +/* + * + * + * NativeScript 1.1 + * + * + */ + +// method registering with argument names + +typedef struct { + godot_string name; + + godot_variant_type type; + godot_property_hint hint; + godot_string hint_string; +} godot_method_arg; + +void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args); + +// documentation + +void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation); +void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation); +void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation); +void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation); + +// type tag API + +void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag); +const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object); + +// instance binding API + +typedef struct { + void *(*alloc_instance_binding_data)(void *, godot_object *); + void (*free_instance_binding_data)(void *, void *); + void *data; + void (*free_func)(void *); +} godot_instance_binding_functions; + +int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions); +void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx); + +void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object); + #ifdef __cplusplus } #endif diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp index b4f7e1555e..aea595d0f0 100644 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ b/modules/gdnative/nativescript/godot_nativescript.cpp @@ -106,7 +106,7 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -125,7 +125,7 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -150,7 +150,7 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -201,6 +201,164 @@ void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) { return NULL; } +/* + * + * + * NativeScript 1.1 + * + * + */ + +void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add argument information for a method on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); + if (!method) { + ERR_EXPLAIN("Attempted to add argument information to non-existent method!"); + ERR_FAIL(); + } + + MethodInfo *method_information = &method->get().info; + + List<PropertyInfo> args; + + for (int i = 0; i < p_num_args; i++) { + godot_method_arg arg = p_args[i]; + String name = *(String *)&arg.name; + String hint_string = *(String *)&arg.hint_string; + + Variant::Type type = (Variant::Type)arg.type; + PropertyHint hint = (PropertyHint)arg.hint; + + args.push_back(PropertyInfo(type, p_name, hint, hint_string)); + } + + method_information->arguments = args; +} + +void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a non-existent class!"); + ERR_FAIL(); + } + + E->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a method on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); + if (!method) { + ERR_EXPLAIN("Attempted to add documentatino to non-existent method!"); + ERR_FAIL(); + } + + method->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a property on a non-existent class!"); + ERR_FAIL(); + } + + OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = E->get().properties.find(p_path); + if (!property) { + ERR_EXPLAIN("Attempted to add documentation to non-existent property!"); + ERR_FAIL(); + } + + property.get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a signal on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Signal>::Element *signal = E->get().signals_.find(p_signal_name); + if (!signal) { + ERR_EXPLAIN("Attempted to add documentation to non-existent signal!"); + ERR_FAIL(); + } + + signal->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to set type tag on a non-existent class!"); + ERR_FAIL(); + } + + E->get().type_tag = p_type_tag; +} + +const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object) { + + const Object *o = (Object *)p_object; + + if (!o->get_script_instance()) { + ERR_EXPLAIN("Attempted to get type tag on an object without a script!"); + ERR_FAIL_V(NULL); + } else { + NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr()); + if (!script) { + ERR_EXPLAIN("Attempted to get type tag on an object without a nativescript attached"); + ERR_FAIL_V(NULL); + } + + if (script->get_script_desc()) + return script->get_script_desc()->type_tag; + } + + return NULL; +} + #ifdef __cplusplus } #endif + +int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions) { + return NativeScriptLanguage::get_singleton()->register_binding_functions(p_binding_functions); +} + +void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx) { + NativeScriptLanguage::get_singleton()->unregister_binding_functions(p_idx); +} + +void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) { + return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object); +} diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index aaa7d634d1..f2e9bef467 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -68,6 +68,11 @@ void NativeScript::_bind_methods() { ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library); ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library); + ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation); + ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation); + ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation); + ClassDB::bind_method(D_METHOD("get_property_documentation", "path"), &NativeScript::get_property_documentation); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); @@ -373,6 +378,86 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } +String NativeScript::get_class_documentation() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get class documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + return script_data->documentation; +} + +String NativeScript::get_method_documentation(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get method documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *method = script_data->methods.find(p_method); + + if (method) { + return method->get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get method documentation for non-existent method"); + ERR_FAIL_V(""); +} + +String NativeScript::get_signal_documentation(const StringName &p_signal_name) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get signal documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + Map<StringName, NativeScriptDesc::Signal>::Element *signal = script_data->signals_.find(p_signal_name); + + if (signal) { + return signal->get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get signal documentation for non-existent signal"); + ERR_FAIL_V(""); +} + +String NativeScript::get_property_documentation(const StringName &p_path) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get property documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = script_data->properties.find(p_path); + + if (property) { + return property.get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get property documentation for non-existent signal"); + ERR_FAIL_V(""); +} + Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { if (lib_path.empty() || class_name.empty() || library.is_null()) { @@ -610,7 +695,7 @@ Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, } void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - script->get_method_list(p_list); + script->get_script_method_list(p_list); } bool NativeScriptInstance::has_method(const StringName &p_method) const { @@ -824,6 +909,25 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) { } } + Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path); + Ref<GDNative> gdn; + + if (E) { + gdn = E->get(); + } + + if (gdn.is_valid() && gdn->get_library().is_valid()) { + Ref<GDNativeLibrary> lib = gdn->get_library(); + void *terminate_fn; + Error err = gdn->get_symbol(lib->get_symbol_prefix() + _terminate_call_name, terminate_fn, true); + + if (err == OK) { + void (*terminate)(void *) = (void (*)(void *))terminate_fn; + + terminate((void *)&lib_path); + } + } + for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) { // free property stuff first @@ -1011,6 +1115,116 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in return 0; } +int NativeScriptLanguage::register_binding_functions(godot_instance_binding_functions p_binding_functions) { + + // find index + + int idx = -1; + + for (int i = 0; i < binding_functions.size(); i++) { + if (!binding_functions[i].first) { + // free, we'll take it + idx = i; + break; + } + } + + if (idx == -1) { + idx = binding_functions.size(); + binding_functions.resize(idx + 1); + } + + // set the functions + binding_functions[idx].first = true; + binding_functions[idx].second = p_binding_functions; + + return idx; +} + +void NativeScriptLanguage::unregister_binding_functions(int p_idx) { + ERR_FAIL_INDEX(p_idx, binding_functions.size()); + + for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) { + Vector<void *> &binding_data = *E->get(); + + if (binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data) + binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]); + } + + binding_functions[p_idx].first = false; + + if (binding_functions[p_idx].second.free_func) + binding_functions[p_idx].second.free_func(binding_functions[p_idx].second.data); +} + +void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) { + ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), NULL); + + if (!binding_functions[p_idx].first) { + ERR_EXPLAIN("Tried to get binding data for a nativescript binding that does not exist"); + ERR_FAIL_V(NULL); + } + + Vector<void *> *binding_data = (Vector<void *> *)p_object->get_script_instance_binding(lang_idx); + + if (!binding_data) + return NULL; // should never happen. + + if (binding_data->size() <= p_idx) { + // okay, add new elements here. + int old_size = binding_data->size(); + + binding_data->resize(p_idx + 1); + + for (int i = old_size; i <= p_idx; i++) { + (*binding_data)[i] = NULL; + } + } + + if (!(*binding_data)[p_idx]) { + // no binding data yet, soooooo alloc new one \o/ + (*binding_data)[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, (godot_object *)p_object); + } + + return (*binding_data)[p_idx]; +} + +void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { + + Vector<void *> *binding_data = new Vector<void *>; + + binding_data->resize(binding_functions.size()); + + for (int i = 0; i < binding_functions.size(); i++) { + (*binding_data)[i] = NULL; + } + + binding_instances.insert(binding_data); + + return (void *)binding_data; +} + +void NativeScriptLanguage::free_instance_binding_data(void *p_data) { + + if (!p_data) + return; + + Vector<void *> &binding_data = *(Vector<void *> *)p_data; + + for (int i = 0; i < binding_data.size(); i++) { + if (!binding_data[i]) + continue; + + if (binding_functions[i].first && binding_functions[i].second.free_instance_binding_data) { + binding_functions[i].second.free_instance_binding_data(binding_functions[i].second.data, binding_data[i]); + } + } + + binding_instances.erase(&binding_data); + + delete &binding_data; +} + #ifndef NO_THREADS void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) { MutexLock lock(mutex); diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index ac94c84bc4..17b6ddc747 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -53,6 +53,7 @@ struct NativeScriptDesc { godot_instance_method method; MethodInfo info; int rpc_mode; + String documentation; }; struct Property { godot_property_set_func setter; @@ -60,12 +61,16 @@ struct NativeScriptDesc { PropertyInfo info; Variant default_value; int rset_mode; + String documentation; }; struct Signal { MethodInfo signal; + String documentation; }; + String documentation; + Map<StringName, Method> methods; OrderedHashMap<StringName, Property> properties; Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals @@ -75,6 +80,8 @@ struct NativeScriptDesc { godot_instance_create_func create_func; godot_instance_destroy_func destroy_func; + const void *type_tag; + bool is_tool; inline NativeScriptDesc() : @@ -82,7 +89,9 @@ struct NativeScriptDesc { properties(), signals_(), base(), - base_native_type() { + base_native_type(), + documentation(), + type_tag(NULL) { zeromem(&create_func, sizeof(godot_instance_create_func)); zeromem(&destroy_func, sizeof(godot_instance_destroy_func)); } @@ -154,6 +163,11 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const; virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + String get_class_documentation() const; + String get_method_documentation(const StringName &p_method) const; + String get_signal_documentation(const StringName &p_signal_name) const; + String get_property_documentation(const StringName &p_path) const; + Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); NativeScript(); @@ -204,6 +218,7 @@ class NativeScriptLanguage : public ScriptLanguage { private: static NativeScriptLanguage *singleton; + int lang_idx; void _unload_stuff(bool p_reload = false); @@ -222,6 +237,9 @@ private: void call_libraries_cb(const StringName &name); + Vector<Pair<bool, godot_instance_binding_functions> > binding_functions; + Set<Vector<void *> *> binding_instances; + public: // These two maps must only be touched on the main thread Map<String, Map<StringName, NativeScriptDesc> > library_classes; @@ -232,6 +250,8 @@ public: const StringName _init_call_type = "nativescript_init"; const StringName _init_call_name = "nativescript_init"; + const StringName _terminate_call_name = "nativescript_terminate"; + const StringName _noarg_call_type = "nativescript_no_arg"; const StringName _frame_call_name = "nativescript_frame"; @@ -250,6 +270,8 @@ public: void _hacky_api_anchor(); + _FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; } + #ifndef NO_THREADS virtual void thread_enter(); virtual void thread_exit(); @@ -293,6 +315,14 @@ public: virtual void profiling_stop(); virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); + + int register_binding_functions(godot_instance_binding_functions p_binding_functions); + void unregister_binding_functions(int p_idx); + + void *get_instance_binding_data(int p_idx, Object *p_object); + + virtual void *alloc_instance_binding_data(Object *p_object); + virtual void free_instance_binding_data(void *p_data); }; inline NativeScriptDesc *NativeScript::get_script_desc() const { diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index cb55a13b3e..9a0e764391 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -47,6 +47,7 @@ void register_nativescript_types() { ClassDB::register_class<NativeScript>(); + native_script_language->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(native_script_language); resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); |