add initial NativeScript 1.1 extension

This commit adds new functionality to NativeScript, namely:

 - ability to set and get documentation for classes, methods,
   signals and properties

 - ability to set names and type information to method arguments

 - ability to set and get type tags for nativescripts

 - ability to register instance binding data management functions

 - ability to use instance binding data
This commit is contained in:
karroffel 2018-02-09 15:04:41 +01:00
parent 2fb66df669
commit 0b2afa24b8
7 changed files with 592 additions and 6 deletions

View file

@ -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>

View file

@ -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",

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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 {

View file

@ -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);