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.cpp2
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp4
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp254
-rw-r--r--modules/gdnative/nativescript/nativescript.h36
4 files changed, 280 insertions, 16 deletions
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 4012e821bb..70ca8d68b8 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -110,7 +110,6 @@ struct ClassAPI {
bool is_singleton;
bool is_instanciable;
// @Unclear
- bool is_creatable;
bool is_reference;
List<MethodAPI> methods;
@@ -385,7 +384,6 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n");
source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n");
// @Unclear
- // source.push_back(String("\t\t\"createable\": ") + (api.is_creatable ? "true" : "false") + ",\n");
source.push_back("\t\t\"constants\": {\n");
for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) {
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index ace2ecac5c..72606c8340 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -365,6 +365,10 @@ void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object
return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object);
}
+void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) {
+ NativeScriptLanguage::get_singleton()->profiling_add_data(StringName(p_signature), p_time);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index d6abbc1bcf..3f88fabebd 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -62,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("set_script_class_name", "class_name"), &NativeScript::set_script_class_name);
+ ClassDB::bind_method(D_METHOD("get_script_class_name"), &NativeScript::get_script_class_name);
+ ClassDB::bind_method(D_METHOD("set_script_class_icon_path", "icon_path"), &NativeScript::set_script_class_icon_path);
+ ClassDB::bind_method(D_METHOD("get_script_class_icon_path"), &NativeScript::get_script_class_icon_path);
+
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);
@@ -69,6 +74,9 @@ void NativeScript::_bind_methods() {
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_GROUP("Script Class", "script_class_");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new"));
}
@@ -131,6 +139,22 @@ Ref<GDNativeLibrary> NativeScript::get_library() const {
return library;
}
+void NativeScript::set_script_class_name(String p_type) {
+ script_class_name = p_type;
+}
+
+String NativeScript::get_script_class_name() const {
+ return script_class_name;
+}
+
+void NativeScript::set_script_class_icon_path(String p_icon_path) {
+ script_class_icon_path = p_icon_path;
+}
+
+String NativeScript::get_script_class_icon_path() const {
+ return script_class_icon_path;
+}
+
bool NativeScript::can_instance() const {
NativeScriptDesc *script_data = get_script_desc();
@@ -149,7 +173,10 @@ Ref<Script> NativeScript::get_base_script() const {
if (!script_data)
return Ref<Script>();
- Ref<NativeScript> ns = Ref<NativeScript>(NSL->create_script());
+ NativeScript *script = (NativeScript *)NSL->create_script();
+ Ref<NativeScript> ns = Ref<NativeScript>(script);
+ ERR_FAIL_COND_V(!ns.is_valid(), Ref<Script>());
+
ns->set_class_name(script_data->base);
ns->set_library(get_library());
return ns;
@@ -553,12 +580,17 @@ bool NativeScriptInstance::set(const StringName &p_name, const Variant &p_value)
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };
- E->get().method.method((godot_object *)owner,
+ godot_variant result;
+ result = E->get().method.method((godot_object *)owner,
E->get().method.method_data,
userdata,
2,
(godot_variant **)args);
- return true;
+ bool handled = *(Variant *)&result;
+ godot_variant_destroy(&result);
+ if (handled) {
+ return true;
+ }
}
script_data = script_data->base_data;
@@ -593,10 +625,9 @@ bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
(godot_variant **)args);
r_ret = *(Variant *)&result;
godot_variant_destroy(&result);
- if (r_ret.get_type() == Variant::NIL) {
- return false;
+ if (r_ret.get_type() != Variant::NIL) {
+ return true;
}
- return true;
}
script_data = script_data->base_data;
@@ -697,11 +728,21 @@ Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p
Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
if (E) {
godot_variant result;
+
+#ifdef DEBUG_ENABLED
+ current_method_call = p_method;
+#endif
+
result = E->get().method.method((godot_object *)owner,
E->get().method.method_data,
userdata,
p_argcount,
(godot_variant **)p_args);
+
+#ifdef DEBUG_ENABLED
+ current_method_call = "";
+#endif
+
Variant res = *(Variant *)&result;
godot_variant_destroy(&result);
r_error.error = Variant::CallError::CALL_OK;
@@ -716,6 +757,15 @@ Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p
}
void NativeScriptInstance::notification(int p_notification) {
+#ifdef DEBUG_ENABLED
+ if (p_notification == MainLoop::NOTIFICATION_CRASH) {
+ if (current_method_call != StringName("")) {
+ ERR_PRINTS("NativeScriptInstance detected crash on method: " + current_method_call);
+ current_method_call = "";
+ }
+ }
+#endif
+
Variant value = p_notification;
const Variant *args[1] = { &value };
call_multilevel("_notification", args, 1);
@@ -960,6 +1010,10 @@ NativeScriptLanguage::NativeScriptLanguage() {
has_objects_to_register = false;
mutex = Mutex::create();
#endif
+
+#ifdef DEBUG_ENABLED
+ profiling = false;
+#endif
}
NativeScriptLanguage::~NativeScriptLanguage() {
@@ -1034,7 +1088,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
s->set_class_name(p_class_name);
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 {
+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, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
return true;
}
@@ -1102,17 +1156,105 @@ void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_
}
void NativeScriptLanguage::profiling_start() {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ profile_data.clear();
+ profiling = true;
+#endif
}
void NativeScriptLanguage::profiling_stop() {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ profiling = false;
+#endif
}
int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+ int current = 0;
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ if (current >= p_info_max)
+ break;
+
+ p_info_arr[current].call_count = d->get().call_count;
+ p_info_arr[current].self_time = d->get().self_time;
+ p_info_arr[current].total_time = d->get().total_time;
+ p_info_arr[current].signature = d->get().signature;
+ current++;
+ }
+
+ return current;
+#else
return 0;
+#endif
}
int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+ int current = 0;
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ if (current >= p_info_max)
+ break;
+
+ if (d->get().last_frame_call_count) {
+ p_info_arr[current].call_count = d->get().last_frame_call_count;
+ p_info_arr[current].self_time = d->get().last_frame_self_time;
+ p_info_arr[current].total_time = d->get().last_frame_total_time;
+ p_info_arr[current].signature = d->get().signature;
+ current++;
+ }
+ }
+
+ return current;
+#else
return 0;
+#endif
+}
+
+void NativeScriptLanguage::profiling_add_data(StringName p_signature, uint64_t p_time) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ Map<StringName, ProfileData>::Element *d = profile_data.find(p_signature);
+ if (d) {
+ d->get().call_count += 1;
+ d->get().total_time += p_time;
+ d->get().frame_call_count += 1;
+ d->get().frame_total_time += p_time;
+ } else {
+ ProfileData data;
+
+ data.signature = p_signature;
+ data.call_count = 1;
+ data.self_time = 0;
+ data.total_time = p_time;
+ data.frame_call_count = 1;
+ data.frame_self_time = 0;
+ data.frame_total_time = p_time;
+ data.last_frame_call_count = 0;
+ data.last_frame_self_time = 0;
+ data.last_frame_total_time = 0;
+
+ profile_data.insert(p_signature, data);
+ }
+#endif
}
int NativeScriptLanguage::register_binding_functions(godot_instance_binding_functions p_binding_functions) {
@@ -1135,8 +1277,8 @@ int NativeScriptLanguage::register_binding_functions(godot_instance_binding_func
}
// set the functions
- binding_functions[idx].first = true;
- binding_functions[idx].second = p_binding_functions;
+ binding_functions.write[idx].first = true;
+ binding_functions.write[idx].second = p_binding_functions;
return idx;
}
@@ -1151,7 +1293,7 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
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;
+ binding_functions.write[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);
@@ -1177,7 +1319,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec
binding_data->resize(p_idx + 1);
for (int i = old_size; i <= p_idx; i++) {
- (*binding_data)[i] = NULL;
+ (*binding_data).write[i] = NULL;
}
}
@@ -1186,7 +1328,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec
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);
+ (*binding_data).write[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];
@@ -1199,7 +1341,7 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) {
binding_data->resize(binding_functions.size());
for (int i = 0; i < binding_functions.size(); i++) {
- (*binding_data)[i] = NULL;
+ (*binding_data).write[i] = NULL;
}
binding_instances.insert(binding_data);
@@ -1228,6 +1370,54 @@ void NativeScriptLanguage::free_instance_binding_data(void *p_data) {
delete &binding_data;
}
+void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_object) {
+
+ void *data = p_object->get_script_instance_binding(lang_idx);
+
+ if (!data)
+ return;
+
+ Vector<void *> &binding_data = *(Vector<void *> *)data;
+
+ for (int i = 0; i < binding_data.size(); i++) {
+ if (!binding_data[i])
+ continue;
+
+ if (!binding_functions[i].first)
+ continue;
+
+ if (binding_functions[i].second.refcount_incremented_instance_binding) {
+ binding_functions[i].second.refcount_incremented_instance_binding(binding_data[i], p_object);
+ }
+ }
+}
+
+bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_object) {
+
+ void *data = p_object->get_script_instance_binding(lang_idx);
+
+ if (!data)
+ return true;
+
+ Vector<void *> &binding_data = *(Vector<void *> *)data;
+
+ bool can_die = true;
+
+ for (int i = 0; i < binding_data.size(); i++) {
+ if (!binding_data[i])
+ continue;
+
+ if (!binding_functions[i].first)
+ continue;
+
+ if (binding_functions[i].second.refcount_decremented_instance_binding) {
+ can_die = can_die && binding_functions[i].second.refcount_decremented_instance_binding(binding_data[i], p_object);
+ }
+ }
+
+ return can_die;
+}
+
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 *>());
@@ -1355,6 +1545,24 @@ void NativeScriptLanguage::frame() {
has_objects_to_register = false;
}
#endif
+
+#ifdef DEBUG_ENABLED
+ {
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ d->get().last_frame_call_count = d->get().frame_call_count;
+ d->get().last_frame_self_time = d->get().frame_self_time;
+ d->get().last_frame_total_time = d->get().frame_total_time;
+ d->get().frame_call_count = 0;
+ d->get().frame_self_time = 0;
+ d->get().frame_total_time = 0;
+ }
+ }
+#endif
+
call_libraries_cb(_frame_call_name);
}
@@ -1370,6 +1578,26 @@ void NativeScriptLanguage::thread_exit() {
#endif // NO_THREADS
+bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const {
+ return p_type == "NativeScript";
+}
+
+String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
+ Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript");
+ if (script.is_valid()) {
+ if (r_base_type)
+ *r_base_type = script->get_instance_base_type();
+ if (r_icon_path)
+ *r_icon_path = script->get_script_class_icon_path();
+ return script->get_script_class_name();
+ }
+ if (r_base_type)
+ *r_base_type = String();
+ if (r_icon_path)
+ *r_icon_path = String();
+ return String();
+}
+
void NativeReloadNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification);
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index b47962dc37..ebfe36fd94 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -118,6 +118,9 @@ class NativeScript : public Script {
String class_name;
+ String script_class_name;
+ String script_class_icon_path;
+
#ifndef NO_THREADS
Mutex *owners_lock;
#endif
@@ -135,6 +138,11 @@ public:
void set_library(Ref<GDNativeLibrary> p_library);
Ref<GDNativeLibrary> get_library() const;
+ void set_script_class_name(String p_type);
+ String get_script_class_name() const;
+ void set_script_class_icon_path(String p_icon_path);
+ String get_script_class_icon_path() const;
+
virtual bool can_instance() const;
virtual Ref<Script> get_base_script() const; //for script inheritance
@@ -181,6 +189,9 @@ class NativeScriptInstance : public ScriptInstance {
Object *owner;
Ref<NativeScript> script;
+#ifdef DEBUG_ENABLED
+ StringName current_method_call;
+#endif
void _ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount);
@@ -243,6 +254,22 @@ private:
Map<int, HashMap<StringName, const void *> > global_type_tags;
+ struct ProfileData {
+ StringName signature;
+ uint64_t call_count;
+ uint64_t self_time;
+ uint64_t total_time;
+ uint64_t frame_call_count;
+ uint64_t frame_self_time;
+ uint64_t frame_total_time;
+ uint64_t last_frame_call_count;
+ uint64_t last_frame_self_time;
+ uint64_t last_frame_total_time;
+ };
+
+ Map<StringName, ProfileData> profile_data;
+ bool profiling;
+
public:
// These two maps must only be touched on the main thread
Map<String, Map<StringName, NativeScriptDesc> > library_classes;
@@ -292,7 +319,7 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool 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;
+ virtual bool 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -326,9 +353,16 @@ public:
virtual void *alloc_instance_binding_data(Object *p_object);
virtual void free_instance_binding_data(void *p_data);
+ virtual void refcount_incremented_instance_binding(Object *p_object);
+ virtual bool refcount_decremented_instance_binding(Object *p_object);
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;
+
+ virtual bool handles_global_class_type(const String &p_type) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const;
+
+ void profiling_add_data(StringName p_signature, uint64_t p_time);
};
inline NativeScriptDesc *NativeScript::get_script_desc() const {