Jelajahi Sumber

Merge pull request #16514 from karroffel/nativescript-extension-1

add NativeScript extension 1
Thomas Herzog 7 tahun lalu
induk
melakukan
68f277477b

+ 43 - 15
modules/gdnative/SCsub

@@ -66,19 +66,30 @@ def _build_gdnative_api_struct_header(api):
 
 
     out += ['};', '']
     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;',
             '\tunsigned int type;',
             '\tgodot_gdnative_api_version version;',
             '\tgodot_gdnative_api_version version;',
             '\tconst godot_gdnative_api_struct *next;'
             '\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']])
             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 += [
     out += [
         'typedef struct godot_gdnative_core_api_struct {',
         '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[] = {']
     out += ['', 'const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {']
 
 

+ 37 - 1
modules/gdnative/doc_classes/NativeScript.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?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>
 	</brief_description>
 	</brief_description>
 	<description>
 	<description>
@@ -9,10 +9,46 @@
 	<demos>
 	<demos>
 	</demos>
 	</demos>
 	<methods>
 	<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">
 		<method name="new" qualifiers="vararg">
 			<return type="Object">
 			<return type="Object">
 			</return>
 			</return>
 			<description>
 			<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>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</methods>

+ 101 - 0
modules/gdnative/gdnative_api.json

@@ -5,6 +5,7 @@
       "major": 1,
       "major": 1,
       "minor": 0
       "minor": 0
     },
     },
+    "next": null,
     "api": [
     "api": [
       {
       {
         "name": "godot_color_new_rgba",
         "name": "godot_color_new_rgba",
@@ -5762,6 +5763,104 @@
         "major": 1,
         "major": 1,
         "minor": 0
         "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": [
       "api": [
         {
         {
           "name": "godot_nativescript_register_class",
           "name": "godot_nativescript_register_class",
@@ -5832,6 +5931,7 @@
         "major": 1,
         "major": 1,
         "minor": 0
         "minor": 0
       },
       },
+      "next": null,
       "api": [
       "api": [
         {
         {
           "name": "godot_pluginscript_register_language",
           "name": "godot_pluginscript_register_language",
@@ -5848,6 +5948,7 @@
         "major": 1,
         "major": 1,
         "minor": 0
         "minor": 0
       },
       },
+      "next": null,
       "api": [
       "api": [
         {
         {
           "name": "godot_arvr_register_interface",
           "name": "godot_arvr_register_interface",

+ 46 - 0
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);
 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
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 161 - 3
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);
 	Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
 
 
 	if (!E) {
 	if (!E) {
-		ERR_EXPLAIN("Attempt to register method on non-existant class!");
+		ERR_EXPLAIN("Attempted to register method on non-existent class!");
 		ERR_FAIL();
 		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);
 	Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
 
 
 	if (!E) {
 	if (!E) {
-		ERR_EXPLAIN("Attempt to register method on non-existant class!");
+		ERR_EXPLAIN("Attempted to register method on non-existent class!");
 		ERR_FAIL();
 		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);
 	Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
 
 
 	if (!E) {
 	if (!E) {
-		ERR_EXPLAIN("Attempt to register method on non-existant class!");
+		ERR_EXPLAIN("Attempted to register method on non-existent class!");
 		ERR_FAIL();
 		ERR_FAIL();
 	}
 	}
 
 
@@ -201,6 +201,164 @@ void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) {
 	return NULL;
 	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
 #ifdef __cplusplus
 }
 }
 #endif
 #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);
+}

+ 215 - 1
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("set_library", "library"), &NativeScript::set_library);
 	ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_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::STRING, "class_name"), "set_class_name", "get_class_name");
 	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
 	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) {
 Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
 
 
 	if (lib_path.empty() || class_name.empty() || library.is_null()) {
 	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 {
 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 {
 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()) {
 		for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
 
 
 			// free property stuff first
 			// free property stuff first
@@ -1011,6 +1115,116 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in
 	return 0;
 	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
 #ifndef NO_THREADS
 void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) {
 void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) {
 	MutexLock lock(mutex);
 	MutexLock lock(mutex);

+ 31 - 1
modules/gdnative/nativescript/nativescript.h

@@ -53,6 +53,7 @@ struct NativeScriptDesc {
 		godot_instance_method method;
 		godot_instance_method method;
 		MethodInfo info;
 		MethodInfo info;
 		int rpc_mode;
 		int rpc_mode;
+		String documentation;
 	};
 	};
 	struct Property {
 	struct Property {
 		godot_property_set_func setter;
 		godot_property_set_func setter;
@@ -60,12 +61,16 @@ struct NativeScriptDesc {
 		PropertyInfo info;
 		PropertyInfo info;
 		Variant default_value;
 		Variant default_value;
 		int rset_mode;
 		int rset_mode;
+		String documentation;
 	};
 	};
 
 
 	struct Signal {
 	struct Signal {
 		MethodInfo signal;
 		MethodInfo signal;
+		String documentation;
 	};
 	};
 
 
+	String documentation;
+
 	Map<StringName, Method> methods;
 	Map<StringName, Method> methods;
 	OrderedHashMap<StringName, Property> properties;
 	OrderedHashMap<StringName, Property> properties;
 	Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
 	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_create_func create_func;
 	godot_instance_destroy_func destroy_func;
 	godot_instance_destroy_func destroy_func;
 
 
+	const void *type_tag;
+
 	bool is_tool;
 	bool is_tool;
 
 
 	inline NativeScriptDesc() :
 	inline NativeScriptDesc() :
@@ -82,7 +89,9 @@ struct NativeScriptDesc {
 			properties(),
 			properties(),
 			signals_(),
 			signals_(),
 			base(),
 			base(),
-			base_native_type() {
+			base_native_type(),
+			documentation(),
+			type_tag(NULL) {
 		zeromem(&create_func, sizeof(godot_instance_create_func));
 		zeromem(&create_func, sizeof(godot_instance_create_func));
 		zeromem(&destroy_func, sizeof(godot_instance_destroy_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_method_list(List<MethodInfo> *p_list) const;
 	virtual void get_script_property_list(List<PropertyInfo> *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);
 	Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
 
 
 	NativeScript();
 	NativeScript();
@@ -204,6 +218,7 @@ class NativeScriptLanguage : public ScriptLanguage {
 
 
 private:
 private:
 	static NativeScriptLanguage *singleton;
 	static NativeScriptLanguage *singleton;
+	int lang_idx;
 
 
 	void _unload_stuff(bool p_reload = false);
 	void _unload_stuff(bool p_reload = false);
 
 
@@ -222,6 +237,9 @@ private:
 
 
 	void call_libraries_cb(const StringName &name);
 	void call_libraries_cb(const StringName &name);
 
 
+	Vector<Pair<bool, godot_instance_binding_functions> > binding_functions;
+	Set<Vector<void *> *> binding_instances;
+
 public:
 public:
 	// These two maps must only be touched on the main thread
 	// These two maps must only be touched on the main thread
 	Map<String, Map<StringName, NativeScriptDesc> > library_classes;
 	Map<String, Map<StringName, NativeScriptDesc> > library_classes;
@@ -232,6 +250,8 @@ public:
 	const StringName _init_call_type = "nativescript_init";
 	const StringName _init_call_type = "nativescript_init";
 	const StringName _init_call_name = "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 _noarg_call_type = "nativescript_no_arg";
 
 
 	const StringName _frame_call_name = "nativescript_frame";
 	const StringName _frame_call_name = "nativescript_frame";
@@ -250,6 +270,8 @@ public:
 
 
 	void _hacky_api_anchor();
 	void _hacky_api_anchor();
 
 
+	_FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; }
+
 #ifndef NO_THREADS
 #ifndef NO_THREADS
 	virtual void thread_enter();
 	virtual void thread_enter();
 	virtual void thread_exit();
 	virtual void thread_exit();
@@ -293,6 +315,14 @@ public:
 	virtual void profiling_stop();
 	virtual void profiling_stop();
 	virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
 	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);
 	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 {
 inline NativeScriptDesc *NativeScript::get_script_desc() const {

+ 1 - 0
modules/gdnative/nativescript/register_types.cpp

@@ -47,6 +47,7 @@ void register_nativescript_types() {
 
 
 	ClassDB::register_class<NativeScript>();
 	ClassDB::register_class<NativeScript>();
 
 
+	native_script_language->set_language_index(ScriptServer::get_language_count());
 	ScriptServer::register_language(native_script_language);
 	ScriptServer::register_language(native_script_language);
 
 
 	resource_saver_gdns = memnew(ResourceFormatSaverNativeScript);
 	resource_saver_gdns = memnew(ResourceFormatSaverNativeScript);