summaryrefslogtreecommitdiff
path: root/modules/gdnative/nativescript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdnative/nativescript')
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp1
-rw-r--r--modules/gdnative/nativescript/api_generator.h1
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp171
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp366
-rw-r--r--modules/gdnative/nativescript/nativescript.h41
-rw-r--r--modules/gdnative/nativescript/register_types.cpp2
-rw-r--r--modules/gdnative/nativescript/register_types.h1
7 files changed, 539 insertions, 44 deletions
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 687aa66219..4012e821bb 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "api_generator.h"
#ifdef TOOLS_ENABLED
diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/gdnative/nativescript/api_generator.h
index 23fd0377ad..de234b2f0d 100644
--- a/modules/gdnative/nativescript/api_generator.h
+++ b/modules/gdnative/nativescript/api_generator.h
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef API_GENERATOR_H
#define API_GENERATOR_H
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index c9434c404e..ace2ecac5c 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "nativescript/godot_nativescript.h"
#include "class_db.h"
@@ -105,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();
}
@@ -124,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();
}
@@ -149,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();
}
@@ -200,6 +201,170 @@ 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_global_type_tag(int p_idx, const char *p_name, const void *p_type_tag) {
+ NativeScriptLanguage::get_singleton()->set_global_type_tag(p_idx, StringName(p_name), p_type_tag);
+}
+
+const void GDAPI *godot_nativescript_get_global_type_tag(int p_idx, const char *p_name) {
+ return NativeScriptLanguage::get_singleton()->get_global_type_tag(p_idx, StringName(p_name));
+}
+
+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()) {
+ return NULL;
+ } else {
+ NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr());
+ if (!script) {
+ return NULL;
+ }
+
+ if (script->get_script_desc())
+ return script->get_script_desc()->type_tag;
+ }
+
+ return NULL;
+}
+
+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);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 823d794f72..cf8977f3ea 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "nativescript.h"
#include "gdnative/gdnative.h"
@@ -54,12 +55,6 @@
#include "editor/editor_node.h"
#endif
-//
-//
-// Script stuff
-//
-//
-
void NativeScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_class_name", "class_name"), &NativeScript::set_class_name);
ClassDB::bind_method(D_METHOD("get_class_name"), &NativeScript::get_class_name);
@@ -67,6 +62,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");
@@ -357,14 +357,13 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
NativeScriptDesc *script_data = get_script_desc();
Set<StringName> existing_properties;
+ List<PropertyInfo>::Element *original_back = p_list->back();
while (script_data) {
- List<PropertyInfo>::Element *insert_position = p_list->front();
- bool insert_before = true;
+ List<PropertyInfo>::Element *insert_position = original_back;
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
if (!existing_properties.has(E.key())) {
- insert_position = insert_before ? p_list->insert_before(insert_position, E.get().info) : p_list->insert_after(insert_position, E.get().info);
- insert_before = false;
+ insert_position = p_list->insert_after(insert_position, E.get().info);
existing_properties.insert(E.key());
}
}
@@ -372,6 +371,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()) {
@@ -397,6 +476,11 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::Call
owner = memnew(Reference);
}
+ if (!owner) {
+ r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return Variant();
+ }
+
Reference *r = Object::cast_to<Reference>(owner);
if (r) {
ref = REF(r);
@@ -437,12 +521,6 @@ NativeScript::~NativeScript() {
#endif
}
- //
- //
- // ScriptInstance stuff
- //
- //
-
#define GET_SCRIPT_DESC() script->get_script_desc()
void NativeScriptInstance::_ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount) {
@@ -604,7 +682,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 {
@@ -781,17 +859,48 @@ NativeScriptInstance::~NativeScriptInstance() {
}
}
-//
-//
-// ScriptingLanguage stuff
-//
-//
-
NativeScriptLanguage *NativeScriptLanguage::singleton;
-void NativeScriptLanguage::_unload_stuff() {
+void NativeScriptLanguage::_unload_stuff(bool p_reload) {
+
+ Map<String, Ref<GDNative> > erase_and_unload;
+
for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) {
- for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) {
+
+ String lib_path = L->key();
+ Map<StringName, NativeScriptDesc> classes = L->get();
+
+ if (p_reload) {
+
+ Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Ref<GDNative> gdn;
+
+ if (E) {
+ gdn = E->get();
+ }
+
+ bool should_reload = false;
+
+ if (gdn.is_valid()) {
+ Ref<GDNativeLibrary> lib = gdn->get_library();
+ if (lib.is_valid()) {
+ should_reload = lib->is_reloadable();
+ }
+ }
+
+ if (!should_reload) {
+ continue;
+ }
+ }
+
+ Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Ref<GDNative> gdn;
+
+ if (E) {
+ gdn = E->get();
+ }
+
+ for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
// free property stuff first
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
@@ -815,12 +924,34 @@ void NativeScriptLanguage::_unload_stuff() {
if (C->get().destroy_func.free_func)
C->get().destroy_func.free_func(C->get().destroy_func.method_data);
}
+
+ erase_and_unload.insert(lib_path, gdn);
+ }
+
+ for (Map<String, Ref<GDNative> >::Element *E = erase_and_unload.front(); E; E = E->next()) {
+ String lib_path = E->key();
+ Ref<GDNative> gdn = E->get();
+
+ library_classes.erase(lib_path);
+
+ 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);
+ }
+ }
}
}
NativeScriptLanguage::NativeScriptLanguage() {
NativeScriptLanguage::singleton = this;
#ifndef NO_THREADS
+ has_objects_to_register = false;
mutex = Mutex::create();
#endif
}
@@ -829,12 +960,14 @@ NativeScriptLanguage::~NativeScriptLanguage() {
for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- L->get()->terminate();
- NSL->library_classes.clear();
- NSL->library_gdnatives.clear();
- NSL->library_script_users.clear();
+ if (L->get().is_valid())
+ L->get()->terminate();
}
+ NSL->library_classes.clear();
+ NSL->library_gdnatives.clear();
+ NSL->library_script_users.clear();
+
#ifndef NO_THREADS
memdelete(mutex);
#endif
@@ -896,7 +1029,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
return Ref<NativeScript>(s);
}
bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
- return false;
+ return true;
}
Script *NativeScriptLanguage::create_script() const {
@@ -976,6 +1109,140 @@ 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]) {
+
+ const void *global_type_tag = global_type_tags[p_idx].get(p_object->get_class_name());
+
+ // 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, global_type_tag, (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;
+}
+
+void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag) {
+ if (!global_type_tags.has(p_idx)) {
+ global_type_tags.insert(p_idx, HashMap<StringName, const void *>());
+ }
+
+ HashMap<StringName, const void *> &tags = global_type_tags[p_idx];
+
+ tags.set(p_class_name, p_type_tag);
+}
+
+const void *NativeScriptLanguage::get_global_type_tag(int p_idx, StringName p_class_name) const {
+ if (!global_type_tags.has(p_idx))
+ return NULL;
+
+ const HashMap<StringName, const void *> &tags = global_type_tags[p_idx];
+
+ const void *tag = tags.get(p_class_name);
+
+ return tag;
+}
+
#ifndef NO_THREADS
void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) {
MutexLock lock(mutex);
@@ -1050,6 +1317,11 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
// library_gdnatives is modified only from the main thread, so it's safe not to use mutex here
for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) {
+
+ if (L->get().is_null()) {
+ continue;
+ }
+
if (L->get()->is_initialized()) {
void *proc_ptr;
@@ -1107,11 +1379,21 @@ void NativeReloadNode::_notification(int p_what) {
#ifndef NO_THREADS
MutexLock lock(NSL->mutex);
#endif
- NSL->_unload_stuff();
+ NSL->_unload_stuff(true);
+
for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- L->get()->terminate();
- NSL->library_classes.erase(L->key());
+ Ref<GDNative> gdn = L->get();
+
+ if (gdn.is_null()) {
+ continue;
+ }
+
+ if (!gdn->get_library()->is_reloadable()) {
+ continue;
+ }
+
+ gdn->terminate();
}
unloaded = true;
@@ -1128,21 +1410,27 @@ void NativeReloadNode::_notification(int p_what) {
Set<StringName> libs_to_remove;
for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- if (!L->get()->initialize()) {
+ Ref<GDNative> gdn = L->get();
+
+ if (gdn.is_null()) {
+ continue;
+ }
+
+ if (!gdn->get_library()->is_reloadable()) {
+ continue;
+ }
+
+ if (!gdn->initialize()) {
libs_to_remove.insert(L->key());
continue;
}
NSL->library_classes.insert(L->key(), Map<StringName, NativeScriptDesc>());
- void *args[1] = {
- (void *)&L->key()
- };
-
// here the library registers all the classes and stuff.
void *proc_ptr;
- Error err = L->get()->get_symbol(L->get()->get_library()->get_symbol_prefix() + "nativescript_init", proc_ptr);
+ Error err = gdn->get_symbol(gdn->get_library()->get_symbol_prefix() + "nativescript_init", proc_ptr);
if (err != OK) {
ERR_PRINT(String("No godot_nativescript_init in \"" + L->key() + "\" found").utf8().get_data());
} else {
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 5eefdf1567..68a8126a32 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
@@ -35,6 +36,7 @@
#include "core/self_list.h"
#include "io/resource_loader.h"
#include "io/resource_saver.h"
+#include "oa_hash_map.h"
#include "ordered_hash_map.h"
#include "os/thread_safe.h"
#include "scene/main/node.h"
@@ -52,6 +54,7 @@ struct NativeScriptDesc {
godot_instance_method method;
MethodInfo info;
int rpc_mode;
+ String documentation;
};
struct Property {
godot_property_set_func setter;
@@ -59,12 +62,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
@@ -74,6 +81,8 @@ struct NativeScriptDesc {
godot_instance_create_func create_func;
godot_instance_destroy_func destroy_func;
+ const void *type_tag;
+
bool is_tool;
inline NativeScriptDesc() :
@@ -81,7 +90,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));
}
@@ -153,6 +164,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();
@@ -203,8 +219,9 @@ class NativeScriptLanguage : public ScriptLanguage {
private:
static NativeScriptLanguage *singleton;
+ int lang_idx;
- void _unload_stuff();
+ void _unload_stuff(bool p_reload = false);
#ifndef NO_THREADS
Mutex *mutex;
@@ -221,6 +238,11 @@ private:
void call_libraries_cb(const StringName &name);
+ Vector<Pair<bool, godot_instance_binding_functions> > binding_functions;
+ Set<Vector<void *> *> binding_instances;
+
+ Map<int, HashMap<StringName, const void *> > global_type_tags;
+
public:
// These two maps must only be touched on the main thread
Map<String, Map<StringName, NativeScriptDesc> > library_classes;
@@ -231,6 +253,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";
@@ -249,6 +273,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();
@@ -292,6 +318,17 @@ 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);
+
+ void set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag);
+ const void *get_global_type_tag(int p_idx, StringName p_class_name) const;
};
inline NativeScriptDesc *NativeScript::get_script_desc() const {
diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp
index d7d2c11d54..9a0e764391 100644
--- a/modules/gdnative/nativescript/register_types.cpp
+++ b/modules/gdnative/nativescript/register_types.cpp
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "register_types.h"
#include "io/resource_loader.h"
@@ -46,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);
diff --git a/modules/gdnative/nativescript/register_types.h b/modules/gdnative/nativescript/register_types.h
index 66cd4c33bb..7389010f8e 100644
--- a/modules/gdnative/nativescript/register_types.h
+++ b/modules/gdnative/nativescript/register_types.h
@@ -27,5 +27,6 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
void register_nativescript_types();
void unregister_nativescript_types();