diff options
Diffstat (limited to 'modules')
81 files changed, 3518 insertions, 333 deletions
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index 6592d0ae1d..a6ae143947 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -12,6 +12,9 @@ gdn_env.add_source_files(env.modules_sources, "nativescript/*.cpp") gdn_env.Append(CPPPATH=['#modules/gdnative/include/']) +SConscript("nativearvr/SCsub") +SConscript("pluginscript/SCsub") + def _spaced(e): return e if e[-1] == '*' else e + ' ' @@ -22,7 +25,9 @@ def _build_gdnative_api_struct_header(api): '#define GODOT_GDNATIVE_API_STRUCT_H', '', '#include <gdnative/gdnative.h>', + '#include <nativearvr/godot_nativearvr.h>', '#include <nativescript/godot_nativescript.h>', + '#include <pluginscript/godot_pluginscript.h>', '', '#define GDNATIVE_API_INIT(options) do { extern const godot_gdnative_api_struct *_gdnative_wrapper_api_struct; _gdnative_wrapper_api_struct = options->api_struct; } while (0)', '', @@ -95,6 +100,7 @@ def _build_gdnative_wrapper_code(api): '', '#include <gdnative/gdnative.h>', '#include <nativescript/godot_nativescript.h>', + '#include <pluginscript/godot_pluginscript.h>', '', '#include <gdnative_api_struct.gen.h>', '', diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py index 9f57b9bb74..df3556249d 100644 --- a/modules/gdnative/config.py +++ b/modules/gdnative/config.py @@ -1,8 +1,12 @@ - def can_build(platform): return True - def configure(env): env.use_ptrcall = True + +def get_doc_classes(): + return ["GDNative", "GDNativeLibrary", "NativeScript", "ARVRInterfaceGDNative"] + +def get_doc_path(): + return "doc_classes" diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml new file mode 100644 index 0000000000..74f71ff603 --- /dev/null +++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.0.alpha.custom_build"> + <brief_description> + GDNative wrapper for an ARVR interface + </brief_description> + <description> + This is a wrapper class for GDNative implementations of the ARVR interface. To use a GDNative ARVR interface simply instantiate this object and set your GDNative library containing the ARVR interface implementation. + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="set_gdnative_library"> + <return type="void"> + </return> + <argument index="0" name="library" type="GDNativeLibrary"> + </argument> + <description> + Bind this GDNative library to our interface. The library must be a GDNative ARVR Interface for this to work. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml new file mode 100644 index 0000000000..ba813c4564 --- /dev/null +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="GDNative" inherits="Reference" category="Core" version="3.0.alpha.custom_build"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="call_native"> + <return type="Variant"> + </return> + <argument index="0" name="procedure_name" type="String"> + </argument> + <argument index="1" name="arguments" type="String"> + </argument> + <argument index="2" name="arg2" type="Array"> + </argument> + <description> + </description> + </method> + <method name="get_library"> + <return type="GDNativeLibrary"> + </return> + <description> + </description> + </method> + <method name="initialize"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="set_library"> + <return type="void"> + </return> + <argument index="0" name="library" type="GDNativeLibrary"> + </argument> + <description> + </description> + </method> + <method name="terminate"> + <return type="bool"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml new file mode 100644 index 0000000000..361c89e6b3 --- /dev/null +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.0.alpha.custom_build"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_active_library_path" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_library_path" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="platform" type="String"> + </argument> + <description> + </description> + </method> + <method name="is_singleton_gdnative" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="set_library_path"> + <return type="void"> + </return> + <argument index="0" name="platform" type="String"> + </argument> + <argument index="1" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_singleton_gdnative"> + <return type="void"> + </return> + <argument index="0" name="singleton" type="bool"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="singleton_gdnative" type="bool" setter="set_singleton_gdnative" getter="is_singleton_gdnative"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml new file mode 100644 index 0000000000..b040cfd966 --- /dev/null +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="NativeScript" inherits="Script" category="Core" version="3.0.alpha.custom_build"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_class_name" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_library" qualifiers="const"> + <return type="GDNativeLibrary"> + </return> + <description> + </description> + </method> + <method name="new" qualifiers="vararg"> + <return type="Object"> + </return> + <description> + </description> + </method> + <method name="set_class_name"> + <return type="void"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_library"> + <return type="void"> + </return> + <argument index="0" name="library" type="GDNativeLibrary"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="class_name" type="String" setter="set_class_name" getter="get_class_name"> + </member> + <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 373b98dc8b..3fc04a5498 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -199,10 +199,7 @@ void GDNative::_bind_methods() { ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize); ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate); - // TODO(karroffel): get_native_(raw_)call_types binding? - - // TODO(karroffel): make this a varargs function? - ClassDB::bind_method(D_METHOD("call_native", "procedure_name", "arguments"), &GDNative::call_native); + ClassDB::bind_method(D_METHOD("call_native", "calling_type", "procedure_name", "arguments"), &GDNative::call_native); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); } @@ -239,10 +236,7 @@ bool GDNative::initialize() { } void *library_init; - err = OS::get_singleton()->get_dynamic_library_symbol_handle( - native_handle, - init_symbol, - library_init); + err = get_symbol(init_symbol, library_init); if (err || !library_init) { OS::get_singleton()->close_dynamic_library(native_handle); @@ -277,11 +271,8 @@ bool GDNative::terminate() { } void *library_terminate; - Error error = OS::get_singleton()->get_dynamic_library_symbol_handle( - native_handle, - terminate_symbol, - library_terminate); - if (error) { + Error error = get_symbol(terminate_symbol, library_terminate); + if (error || !library_terminate) { OS::get_singleton()->close_dynamic_library(native_handle); native_handle = NULL; return true; @@ -313,10 +304,6 @@ void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, nat native_calls.insert(p_call_type, p_callback); } -void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) { - native_raw_calls.insert(p_raw_call_type, p_callback); -} - Vector<StringName> GDNativeCallRegistry::get_native_call_types() { Vector<StringName> call_types; call_types.resize(native_calls.size()); @@ -329,18 +316,6 @@ Vector<StringName> GDNativeCallRegistry::get_native_call_types() { return call_types; } -Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() { - Vector<StringName> call_types; - call_types.resize(native_raw_calls.size()); - - size_t idx = 0; - for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) { - call_types[idx] = E->key(); - } - - return call_types; -} - Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) { Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type); @@ -349,20 +324,34 @@ Variant GDNative::call_native(StringName p_native_call_type, StringName p_proced return Variant(); } - String procedure_name = p_procedure_name; - godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments); + void *procedure_handle; + + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + p_procedure_name, + procedure_handle); + + if (err != OK || procedure_handle == NULL) { + return Variant(); + } + + godot_variant result = E->get()(procedure_handle, (godot_array *)&p_arguments); return *(Variant *)&result; } -void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) { +Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle) { - Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type); - if (!E) { - ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data()); - return; + if (native_handle == NULL) { + ERR_PRINT("No valid library handle, can't get symbol from GDNative object"); + return ERR_CANT_OPEN; } - String procedure_name = p_procedure_name; - E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return); + Error result = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + p_procedure_name, + r_handle, + true); + + return result; } diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index 7bbad842eb..e44cc55a79 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -100,8 +100,7 @@ public: _FORCE_INLINE_ void set_singleton_gdnative(bool p_singleton) { singleton_gdnative = p_singleton; } }; -typedef godot_variant (*native_call_cb)(void *, godot_string *, godot_array *); -typedef void (*native_raw_call_cb)(void *, godot_string *, void *, int, void **, void *); +typedef godot_variant (*native_call_cb)(void *, godot_array *); struct GDNativeCallRegistry { static GDNativeCallRegistry *singleton; @@ -111,17 +110,13 @@ struct GDNativeCallRegistry { } inline GDNativeCallRegistry() - : native_calls(), - native_raw_calls() {} + : native_calls() {} Map<StringName, native_call_cb> native_calls; - Map<StringName, native_raw_call_cb> native_raw_calls; void register_native_call_type(StringName p_call_type, native_call_cb p_callback); - void register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback); Vector<StringName> get_native_call_types(); - Vector<StringName> get_native_raw_call_types(); }; class GDNative : public Reference { @@ -149,7 +144,8 @@ public: bool terminate(); Variant call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments = Array()); - void call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return); + + Error get_symbol(StringName p_procedure_name, void *&r_handle); }; #endif // GDNATIVE_H diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp index 9b715ce36a..905c513d9d 100644 --- a/modules/gdnative/gdnative/string.cpp +++ b/modules/gdnative/gdnative/string.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "gdnative/string.h" +#include "core/string_db.h" +#include "core/ustring.h" #include "core/variant.h" -#include "string_db.h" -#include "ustring.h" #include <string.h> diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 4d3c024a8f..31b021b751 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -5229,6 +5229,85 @@ "arguments": [ ["godot_object *", "p_instance"] ] + }, + { + "name": "godot_arvr_register_interface", + "return_type": "void", + "arguments": [ + ["const godot_arvr_interface_gdnative *", "p_interface"] + ] + }, + { + "name": "godot_arvr_get_worldscale", + "return_type": "godot_real", + "arguments": [] + }, + { + "name": "godot_arvr_get_reference_frame", + "return_type": "godot_transform", + "arguments": [] + }, + { + "name": "godot_arvr_blit", + "return_type": "void", + "arguments": [ + ["int", "p_eye"], + ["godot_rid *", "p_render_target"], + ["godot_rect2 *", "p_screen_rect"] + ] + }, + { + "name": "godot_arvr_get_texid", + "return_type": "godot_int", + "arguments": [ + ["godot_rid *", "p_render_target"] + ] + }, + { + "name": "godot_arvr_add_controller", + "return_type": "godot_int", + "arguments": [ + ["char *", "p_device_name"], + ["godot_int", "p_hand"], + ["godot_bool", "p_tracks_orientation"], + ["godot_bool", "p_tracks_position"] + ] + }, + { + "name": "godot_arvr_remove_controller", + "return_type": "void", + "arguments": [ + ["godot_int", "p_controller_id"] + ] + }, + { + "name": "godot_arvr_set_controller_transform", + "return_type": "void", + "arguments": [ + ["godot_int", "p_controller_id"], + ["godot_transform *", "p_transform"], + ["godot_bool", "p_tracks_orientation"], + ["godot_bool", "p_tracks_position"] + ] + }, + { + "name": "godot_arvr_set_controller_button", + "return_type": "void", + "arguments": [ + ["godot_int", "p_controller_id"], + ["godot_int", "p_button"], + ["godot_bool", "p_is_pressed"] + ] + }, + { + "name": "godot_arvr_set_controller_axis", + "return_type": "void", + "arguments": [ + ["godot_int", "p_controller_id"], + ["godot_int", "p_exis"], + ["godot_real", "p_value"], + ["godot_bool", "p_can_be_negative"] + ] } ] } diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h index edab028cba..d0639589b7 100644 --- a/modules/gdnative/include/gdnative/array.h +++ b/modules/gdnative/include/gdnative/array.h @@ -46,11 +46,20 @@ typedef struct { } godot_array; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/pool_arrays.h> #include <gdnative/variant.h> #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_array_new(godot_array *r_dest); void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src); void GDAPI godot_array_new_pool_color_array(godot_array *r_dest, const godot_pool_color_array *p_pca); diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h index 8ff6a6f541..b86b1c17d8 100644 --- a/modules/gdnative/include/gdnative/basis.h +++ b/modules/gdnative/include/gdnative/basis.h @@ -45,10 +45,19 @@ typedef struct { } godot_basis; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/quat.h> #include <gdnative/vector3.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis); void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi); void GDAPI godot_basis_new_with_euler(godot_basis *r_dest, const godot_vector3 *p_euler); diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h index 14265466b9..857e86a738 100644 --- a/modules/gdnative/include/gdnative/color.h +++ b/modules/gdnative/include/gdnative/color.h @@ -45,9 +45,18 @@ typedef struct { } godot_color; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/string.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a); void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b); diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h index c85c3f3830..e68d0fdc29 100644 --- a/modules/gdnative/include/gdnative/dictionary.h +++ b/modules/gdnative/include/gdnative/dictionary.h @@ -45,10 +45,19 @@ typedef struct { } godot_dictionary; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/array.h> #include <gdnative/gdnative.h> #include <gdnative/variant.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_dictionary_new(godot_dictionary *r_dest); void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src); void GDAPI godot_dictionary_destroy(godot_dictionary *p_self); diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 2d8726e5db..25d45db306 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -47,7 +47,7 @@ extern "C" { #define GDAPI GDCALLINGCONV #endif #else -#define GDCALLINGCONV __attribute__((sysv_abi, visibility("default"))) +#define GDCALLINGCONV __attribute__((sysv_abi)) #define GDAPI GDCALLINGCONV #endif @@ -255,7 +255,7 @@ godot_dictionary GDAPI godot_get_global_constants(); ////// GDNative procedure types typedef void (*godot_gdnative_init_fn)(godot_gdnative_init_options *); typedef void (*godot_gdnative_terminate_fn)(godot_gdnative_terminate_options *); -typedef godot_variant (*godot_gdnative_procedure_fn)(void *, godot_array *); +typedef godot_variant (*godot_gdnative_procedure_fn)(godot_array *); ////// System Functions diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h index 0cfdbc1127..42446175d8 100644 --- a/modules/gdnative/include/gdnative/node_path.h +++ b/modules/gdnative/include/gdnative/node_path.h @@ -45,9 +45,18 @@ typedef struct { } godot_node_path; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/string.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from); void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src); void GDAPI godot_node_path_destroy(godot_node_path *p_self); diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h index 6a8915e08b..dddd172122 100644 --- a/modules/gdnative/include/gdnative/plane.h +++ b/modules/gdnative/include/gdnative/plane.h @@ -45,9 +45,18 @@ typedef struct { } godot_plane; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/vector3.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d); void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3); void GDAPI godot_plane_new_with_normal(godot_plane *r_dest, const godot_vector3 *p_normal, const godot_real p_d); diff --git a/modules/gdnative/include/gdnative/pool_arrays.h b/modules/gdnative/include/gdnative/pool_arrays.h index cb1095ee8c..93181f2a6b 100644 --- a/modules/gdnative/include/gdnative/pool_arrays.h +++ b/modules/gdnative/include/gdnative/pool_arrays.h @@ -113,6 +113,11 @@ typedef struct { } godot_pool_color_array; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/array.h> #include <gdnative/color.h> #include <gdnative/vector2.h> @@ -120,6 +125,10 @@ typedef struct { #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + // byte void GDAPI godot_pool_byte_array_new(godot_pool_byte_array *r_dest); diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h index 4ffb96eb26..acae6e3e90 100644 --- a/modules/gdnative/include/gdnative/quat.h +++ b/modules/gdnative/include/gdnative/quat.h @@ -45,9 +45,18 @@ typedef struct { } godot_quat; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/vector3.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w); void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle); diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h index 9e6cf60342..1c66443d4f 100644 --- a/modules/gdnative/include/gdnative/rect2.h +++ b/modules/gdnative/include/gdnative/rect2.h @@ -43,9 +43,18 @@ typedef struct godot_rect2 { } godot_rect2; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/vector2.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size); void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height); diff --git a/modules/gdnative/include/gdnative/rect3.h b/modules/gdnative/include/gdnative/rect3.h index f94b6fea25..f603a9268a 100644 --- a/modules/gdnative/include/gdnative/rect3.h +++ b/modules/gdnative/include/gdnative/rect3.h @@ -45,10 +45,19 @@ typedef struct { } godot_rect3; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/plane.h> #include <gdnative/vector3.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size); godot_vector3 GDAPI godot_rect3_get_position(const godot_rect3 *p_self); diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h index d9b5336fc9..caa1bb967e 100644 --- a/modules/gdnative/include/gdnative/rid.h +++ b/modules/gdnative/include/gdnative/rid.h @@ -45,8 +45,17 @@ typedef struct { } godot_rid; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_rid_new(godot_rid *r_dest); godot_int GDAPI godot_rid_get_id(const godot_rid *p_self); diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h index aca23a81d8..f30fdb8dc7 100644 --- a/modules/gdnative/include/gdnative/string.h +++ b/modules/gdnative/include/gdnative/string.h @@ -46,9 +46,18 @@ typedef struct { } godot_string; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/variant.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_string_new(godot_string *r_dest); void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); void GDAPI godot_string_new_data(godot_string *r_dest, const char *p_contents, const int p_size); diff --git a/modules/gdnative/include/gdnative/string_name.h b/modules/gdnative/include/gdnative/string_name.h index e217487250..ee9f603d20 100644 --- a/modules/gdnative/include/gdnative/string_name.h +++ b/modules/gdnative/include/gdnative/string_name.h @@ -46,8 +46,17 @@ typedef struct { } godot_string_name; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name); void GDAPI godot_string_name_new_data(godot_string_name *r_dest, const char *p_name); diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h index 656afae129..8f50b01fb5 100644 --- a/modules/gdnative/include/gdnative/transform.h +++ b/modules/gdnative/include/gdnative/transform.h @@ -45,11 +45,20 @@ typedef struct { } godot_transform; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/basis.h> #include <gdnative/gdnative.h> #include <gdnative/variant.h> #include <gdnative/vector3.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin); void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin); diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h index a945868b17..c68bd2963f 100644 --- a/modules/gdnative/include/gdnative/transform2d.h +++ b/modules/gdnative/include/gdnative/transform2d.h @@ -45,10 +45,19 @@ typedef struct { } godot_transform2d; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> #include <gdnative/variant.h> #include <gdnative/vector2.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos); void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin); diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h index 7b804c1eaf..3d744ef1f2 100644 --- a/modules/gdnative/include/gdnative/variant.h +++ b/modules/gdnative/include/gdnative/variant.h @@ -99,6 +99,11 @@ typedef struct godot_variant_call_error { godot_variant_type expected; } godot_variant_call_error; +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/array.h> #include <gdnative/basis.h> #include <gdnative/color.h> @@ -119,6 +124,10 @@ typedef struct godot_variant_call_error { #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v); void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_src); diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h index 0af4abae27..07105abaf2 100644 --- a/modules/gdnative/include/gdnative/vector2.h +++ b/modules/gdnative/include/gdnative/vector2.h @@ -45,8 +45,17 @@ typedef struct { } godot_vector2; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y); godot_string GDAPI godot_vector2_as_string(const godot_vector2 *p_self); diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h index a27d516ec5..3ed23778ec 100644 --- a/modules/gdnative/include/gdnative/vector3.h +++ b/modules/gdnative/include/gdnative/vector3.h @@ -45,9 +45,18 @@ typedef struct { } godot_vector3; #endif +// reduce extern "C" nesting for VS2013 +#ifdef __cplusplus +} +#endif + #include <gdnative/basis.h> #include <gdnative/gdnative.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { GODOT_VECTOR3_AXIS_X, GODOT_VECTOR3_AXIS_Y, diff --git a/modules/gdnative/include/nativearvr/godot_nativearvr.h b/modules/gdnative/include/nativearvr/godot_nativearvr.h new file mode 100644 index 0000000000..1a8970d396 --- /dev/null +++ b/modules/gdnative/include/nativearvr/godot_nativearvr.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* godot_nativearvr.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef GODOT_NATIVEARVR_H +#define GODOT_NATIVEARVR_H + +#include <gdnative/gdnative.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + void *(*constructor)(godot_object *); + void (*destructor)(void *); + godot_string (*get_name)(const void *); + godot_int (*get_capabilities)(const void *); + godot_bool (*get_anchor_detection_is_enabled)(const void *); + void (*set_anchor_detection_is_enabled)(void *, godot_bool); + godot_bool (*is_stereo)(const void *); + godot_bool (*is_initialized)(const void *); + godot_bool (*initialize)(void *); + void (*uninitialize)(void *); + godot_vector2 (*get_recommended_render_targetsize)(const void *); + godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *); + void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real); + void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *); + void (*process)(void *); +} godot_arvr_interface_gdnative; + +void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface); + +// helper functions to access ARVRServer data +godot_real GDAPI godot_arvr_get_worldscale(); +godot_transform GDAPI godot_arvr_get_reference_frame(); + +// helper functions for rendering +void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect); +godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target); + +// helper functions for updating ARVR controllers +godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position); +void GDAPI godot_arvr_remove_controller(godot_int p_controller_id); +void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position); +void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed); +void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative); + +#ifdef __cplusplus +} +#endif + +#endif /* !GODOT_NATIVEARVR_H */ diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h new file mode 100644 index 0000000000..ec109bac83 --- /dev/null +++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h @@ -0,0 +1,170 @@ +/*************************************************************************/ +/* godot_nativescript.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef GODOT_PLUGINSCRIPT_H +#define GODOT_PLUGINSCRIPT_H + +#include <gdnative/gdnative.h> +#include <nativescript/godot_nativescript.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void godot_pluginscript_instance_data; +typedef void godot_pluginscript_script_data; +typedef void godot_pluginscript_language_data; + +// --- Instance --- + +// TODO: use godot_string_name for faster lookup ? +typedef struct { + godot_pluginscript_instance_data *(*init)(godot_pluginscript_script_data *p_data, godot_object *p_owner); + void (*finish)(godot_pluginscript_instance_data *p_data); + + godot_bool (*set_prop)(godot_pluginscript_instance_data *p_data, const godot_string *p_name, const godot_variant *p_value); + godot_bool (*get_prop)(godot_pluginscript_instance_data *p_data, const godot_string *p_name, godot_variant *r_ret); + + godot_variant (*call_method)(godot_pluginscript_instance_data *p_data, + const godot_string_name *p_method, const godot_variant **p_args, + int p_argcount, godot_variant_call_error *r_error); + + void (*notification)(godot_pluginscript_instance_data *p_data, int p_notification); + // TODO: could this rpc mode stuff be moved to the godot_pluginscript_script_manifest ? + godot_method_rpc_mode (*get_rpc_mode)(godot_pluginscript_instance_data *p_data, const godot_string *p_method); + godot_method_rpc_mode (*get_rset_mode)(godot_pluginscript_instance_data *p_data, const godot_string *p_variable); + + //this is used by script languages that keep a reference counter of their own + //you can make make Ref<> not die when it reaches zero, so deleting the reference + //depends entirely from the script. + // Note: You can set thoses function pointer to NULL if not needed. + void (*refcount_incremented)(godot_pluginscript_instance_data *p_data); + bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die +} godot_pluginscript_instance_desc; + +// --- Script --- + +typedef struct { + godot_pluginscript_script_data *data; + godot_string_name name; + godot_bool is_tool; + godot_string_name base; + + // Member lines format: {<string>: <int>} + godot_dictionary member_lines; + // Method info dictionary format + // { + // name: <string> + // args: [<dict:property>] + // default_args: [<variant>] + // return: <dict:property> + // flags: <int> + // rpc_mode: <int:godot_method_rpc_mode> + // } + godot_array methods; + // Same format than for methods + godot_array signals; + // Property info dictionary format + // { + // name: <string> + // type: <int:godot_variant_type> + // hint: <int:godot_property_hint> + // hint_string: <string> + // usage: <int:godot_property_usage_flags> + // default_value: <variant> + // rset_mode: <int:godot_method_rpc_mode> + // } + godot_array properties; +} godot_pluginscript_script_manifest; + +typedef struct { + godot_pluginscript_script_manifest (*init)(godot_pluginscript_language_data *p_data, const godot_string *p_path, const godot_string *p_source, godot_error *r_error); + void (*finish)(godot_pluginscript_script_data *p_data); + godot_pluginscript_instance_desc instance_desc; +} godot_pluginscript_script_desc; + +// --- Language --- + +typedef struct { + godot_string_name signature; + godot_int call_count; + godot_int total_time; // In microseconds + godot_int self_time; // In microseconds +} godot_pluginscript_profiling_data; + +typedef struct { + const char *name; + const char *type; + const char *extension; + const char **recognized_extensions; // NULL terminated array + godot_pluginscript_language_data *(*init)(); + void (*finish)(godot_pluginscript_language_data *p_data); + const char **reserved_words; // NULL terminated array + const char **comment_delimiters; // NULL terminated array + const char **string_delimiters; // NULL terminated array + godot_bool has_named_classes; + + godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name); + godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_pool_string_array *r_functions); + int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be NULL + godot_string (*make_function)(godot_pluginscript_language_data *p_data, const godot_string *p_class, const godot_string *p_name, const godot_pool_string_array *p_args); + godot_error (*complete_code)(godot_pluginscript_language_data *p_data, const godot_string *p_code, const godot_string *p_base_path, godot_object *p_owner, godot_array *r_options, godot_bool *r_force, godot_string *r_call_hint); + void (*auto_indent_code)(godot_pluginscript_language_data *p_data, godot_string *p_code, int p_from_line, int p_to_line); + + void (*add_global_constant)(godot_pluginscript_language_data *p_data, const godot_string *p_variable, const godot_variant *p_value); + godot_string (*debug_get_error)(godot_pluginscript_language_data *p_data); + int (*debug_get_stack_level_count)(godot_pluginscript_language_data *p_data); + int (*debug_get_stack_level_line)(godot_pluginscript_language_data *p_data, int p_level); + godot_string (*debug_get_stack_level_function)(godot_pluginscript_language_data *p_data, int p_level); + godot_string (*debug_get_stack_level_source)(godot_pluginscript_language_data *p_data, int p_level); + void (*debug_get_stack_level_locals)(godot_pluginscript_language_data *p_data, int p_level, godot_pool_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth); + void (*debug_get_stack_level_members)(godot_pluginscript_language_data *p_data, int p_level, godot_pool_string_array *p_members, godot_array *p_values, int p_max_subitems, int p_max_depth); + void (*debug_get_globals)(godot_pluginscript_language_data *p_data, godot_pool_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth); + godot_string (*debug_parse_stack_level_expression)(godot_pluginscript_language_data *p_data, int p_level, const godot_string *p_expression, int p_max_subitems, int p_max_depth); + + // TODO: could this stuff be moved to the godot_pluginscript_language_desc ? + void (*get_public_functions)(godot_pluginscript_language_data *p_data, godot_array *r_functions); + void (*get_public_constants)(godot_pluginscript_language_data *p_data, godot_dictionary *r_constants); + + void (*profiling_start)(godot_pluginscript_language_data *p_data); + void (*profiling_stop)(godot_pluginscript_language_data *p_data); + int (*profiling_get_accumulated_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max); + int (*profiling_get_frame_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max); + void (*profiling_frame)(godot_pluginscript_language_data *p_data); + + godot_pluginscript_script_desc script_desc; +} godot_pluginscript_language_desc; + +void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc); + +#ifdef __cplusplus +} +#endif + +#endif // GODOT_PLUGINSCRIPT_H diff --git a/modules/gdnative/nativearvr/SCsub b/modules/gdnative/nativearvr/SCsub new file mode 100644 index 0000000000..ecc5996108 --- /dev/null +++ b/modules/gdnative/nativearvr/SCsub @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import os +import methods + +Import('env') +Import('env_modules') + +env_arvr_gdnative = env_modules.Clone() + +env_arvr_gdnative.Append(CPPPATH=['#modules/gdnative/include/']) +env_arvr_gdnative.add_source_files(env.modules_sources, '*.cpp') + diff --git a/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp new file mode 100644 index 0000000000..ff8bda162f --- /dev/null +++ b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp @@ -0,0 +1,386 @@ +/*************************************************************************/ +/* arvr_interface_gdnative.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "arvr_interface_gdnative.h" +#include "main/input_default.h" +#include "servers/arvr/arvr_positional_tracker.h" +#include "servers/visual/visual_server_global.h" + +ARVRInterfaceGDNative::ARVRInterfaceGDNative() { + // testing + printf("Construct gdnative interface\n"); + + // we won't have our data pointer until our library gets set + data = NULL; + + interface = NULL; +} + +ARVRInterfaceGDNative::~ARVRInterfaceGDNative() { + printf("Destruct gdnative interface\n"); + + if (is_initialized()) { + uninitialize(); + }; + + // cleanup after ourselves + cleanup(); +} + +void ARVRInterfaceGDNative::cleanup() { + if (interface != NULL) { + interface->destructor(data); + data = NULL; + interface = NULL; + } +} + +void ARVRInterfaceGDNative::set_interface(const godot_arvr_interface_gdnative *p_interface) { + // this should only be called once, just being paranoid.. + if (interface) { + cleanup(); + } + + // bind to our interface + interface = p_interface; + + // Now we do our constructing... + data = interface->constructor((godot_object *)this); +} + +StringName ARVRInterfaceGDNative::get_name() const { + + ERR_FAIL_COND_V(interface == NULL, StringName()); + + godot_string result = interface->get_name(data); + + StringName name = *(String *)&result; + + godot_string_destroy(&result); + + return name; +} + +int ARVRInterfaceGDNative::get_capabilities() const { + int capabilities; + + ERR_FAIL_COND_V(interface == NULL, 0); // 0 = None + + capabilities = interface->get_capabilities(data); + + return capabilities; +} + +bool ARVRInterfaceGDNative::get_anchor_detection_is_enabled() const { + bool enabled; + + ERR_FAIL_COND_V(interface == NULL, false); + + enabled = interface->get_anchor_detection_is_enabled(data); + + return enabled; +} + +void ARVRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) { + + ERR_FAIL_COND(interface == NULL); + + interface->set_anchor_detection_is_enabled(data, p_enable); +} + +bool ARVRInterfaceGDNative::is_stereo() { + bool stereo; + + ERR_FAIL_COND_V(interface == NULL, false); + + stereo = interface->is_stereo(data); + + return stereo; +} + +bool ARVRInterfaceGDNative::is_initialized() { + bool initialized; + + ERR_FAIL_COND_V(interface == NULL, false); + + initialized = interface->is_initialized(data); + + return initialized; +} + +bool ARVRInterfaceGDNative::initialize() { + bool initialized; + + ERR_FAIL_COND_V(interface == NULL, false); + + initialized = interface->initialize(data); + + if (initialized) { + // if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface + + ARVRServer *arvr_server = ARVRServer::get_singleton(); + if ((arvr_server != NULL) && (arvr_server->get_primary_interface() == NULL)) { + arvr_server->set_primary_interface(this); + }; + }; + + return initialized; +} + +void ARVRInterfaceGDNative::uninitialize() { + ERR_FAIL_COND(interface == NULL); + + ARVRServer *arvr_server = ARVRServer::get_singleton(); + if (arvr_server != NULL) { + // Whatever happens, make sure this is no longer our primary interface + arvr_server->clear_primary_interface_if(this); + } + + interface->uninitialize(data); +} + +Size2 ARVRInterfaceGDNative::get_recommended_render_targetsize() { + + ERR_FAIL_COND_V(interface == NULL, Size2()); + + godot_vector2 result = interface->get_recommended_render_targetsize(data); + Vector2 *vec = (Vector2 *)&result; + + return *vec; +} + +Transform ARVRInterfaceGDNative::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) { + Transform *ret; + + ERR_FAIL_COND_V(interface == NULL, Transform()); + + godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform); + + ret = (Transform *)&t; + + return *ret; +} + +CameraMatrix ARVRInterfaceGDNative::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { + CameraMatrix cm; + + ERR_FAIL_COND_V(interface == NULL, CameraMatrix()); + + interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far); + + return cm; +} + +void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) { + + ERR_FAIL_COND(interface == NULL); + + interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect); +} + +void ARVRInterfaceGDNative::process() { + ERR_FAIL_COND(interface == NULL); + + interface->process(data); +} + +///////////////////////////////////////////////////////////////////////////////////// +// some helper callbacks + +extern "C" { + +void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface) { + Ref<ARVRInterfaceGDNative> new_interface; + new_interface.instance(); + new_interface->set_interface((godot_arvr_interface_gdnative * const)p_interface); + ARVRServer::get_singleton()->add_interface(new_interface); +} + +godot_real GDAPI godot_arvr_get_worldscale() { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, 1.0); + + return arvr_server->get_world_scale(); +} + +godot_transform GDAPI godot_arvr_get_reference_frame() { + godot_transform reference_frame; + Transform *reference_frame_ptr = (Transform *)&reference_frame; + + ARVRServer *arvr_server = ARVRServer::get_singleton(); + if (arvr_server != NULL) { + *reference_frame_ptr = arvr_server->get_reference_frame(); + } else { + godot_transform_new_identity(&reference_frame); + } + + return reference_frame; +} + +void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) { + // blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD + ARVRInterface::Eyes eye = (ARVRInterface::Eyes)p_eye; + RID *render_target = (RID *)p_render_target; + Rect2 screen_rect = *(Rect2 *)p_rect; + + if (eye == ARVRInterface::EYE_LEFT) { + screen_rect.size.x /= 2.0; + } else if (p_eye == ARVRInterface::EYE_RIGHT) { + screen_rect.size.x /= 2.0; + screen_rect.position.x += screen_rect.size.x; + } + + VSG::rasterizer->set_current_render_target(RID()); + VSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0); +} + +godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target) { + // In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID + // This is a handy function to expose that. + RID *render_target = (RID *)p_render_target; + + RID eye_texture = VSG::storage->render_target_get_texture(*render_target); + uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture); + + return texid; +} + +godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, 0); + + InputDefault *input = (InputDefault *)Input::get_singleton(); + ERR_FAIL_NULL_V(input, 0); + + ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker); + new_tracker->set_name(p_device_name); + new_tracker->set_type(ARVRServer::TRACKER_CONTROLLER); + if (p_hand == 1) { + new_tracker->set_hand(ARVRPositionalTracker::TRACKER_LEFT_HAND); + } else if (p_hand == 2) { + new_tracker->set_hand(ARVRPositionalTracker::TRACKER_RIGHT_HAND); + } + + // also register as joystick... + int joyid = input->get_unused_joy_id(); + if (joyid != -1) { + new_tracker->set_joy_id(joyid); + input->joy_connection_changed(joyid, true, p_device_name, ""); + } + + if (p_tracks_orientation) { + Basis orientation; + new_tracker->set_orientation(orientation); + } + if (p_tracks_position) { + Vector3 position; + new_tracker->set_position(position); + } + + // add our tracker to our server and remember its pointer + arvr_server->add_tracker(new_tracker); + + // note, this ID is only unique within controllers! + return new_tracker->get_tracker_id(); +} + +void GDAPI godot_arvr_remove_controller(godot_int p_controller_id) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + InputDefault *input = (InputDefault *)Input::get_singleton(); + ERR_FAIL_NULL(input); + + ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id); + if (remove_tracker != NULL) { + // unset our joystick if applicable + int joyid = remove_tracker->get_joy_id(); + if (joyid != -1) { + input->joy_connection_changed(joyid, false, "", ""); + remove_tracker->set_joy_id(-1); + } + + // remove our tracker from our server + arvr_server->remove_tracker(remove_tracker); + memdelete(remove_tracker); + } +} + +void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker != NULL) { + Transform *transform = (Transform *)p_transform; + if (p_tracks_orientation) { + tracker->set_orientation(transform->basis); + } + if (p_tracks_position) { + tracker->set_position(transform->origin); + } + } +} + +void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + InputDefault *input = (InputDefault *)Input::get_singleton(); + ERR_FAIL_NULL(input); + + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker != NULL) { + int joyid = tracker->get_joy_id(); + if (joyid != -1) { + input->joy_button(joyid, p_button, p_is_pressed); + } + } +} + +void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + InputDefault *input = (InputDefault *)Input::get_singleton(); + ERR_FAIL_NULL(input); + + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker != NULL) { + int joyid = tracker->get_joy_id(); + if (joyid != -1) { + InputDefault::JoyAxis jx; + jx.min = p_can_be_negative ? -1 : 0; + jx.value = p_value; + input->joy_axis(joyid, p_axis, jx); + } + } +} +} diff --git a/modules/gdnative/nativearvr/arvr_interface_gdnative.h b/modules/gdnative/nativearvr/arvr_interface_gdnative.h new file mode 100644 index 0000000000..e45b51e070 --- /dev/null +++ b/modules/gdnative/nativearvr/arvr_interface_gdnative.h @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* arvr_interface_gdnative.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef ARVR_INTERFACE_GDNATIVE_H +#define ARVR_INTERFACE_GDNATIVE_H + +#include "modules/gdnative/gdnative.h" +#include "servers/arvr/arvr_interface.h" + +/** + @authors Hinsbart & Karroffel & Mux213 + + This subclass of our AR/VR interface forms a bridge to GDNative. +*/ + +class ARVRInterfaceGDNative : public ARVRInterface { + GDCLASS(ARVRInterfaceGDNative, ARVRInterface) + + void cleanup(); + +protected: + const godot_arvr_interface_gdnative *interface; + void *data; + +public: + /** general interface information **/ + ARVRInterfaceGDNative(); + ~ARVRInterfaceGDNative(); + + void set_interface(const godot_arvr_interface_gdnative *p_interface); + + virtual StringName get_name() const; + virtual int get_capabilities() const; + + virtual bool is_initialized(); + virtual bool initialize(); + virtual void uninitialize(); + + /** specific to AR **/ + virtual bool get_anchor_detection_is_enabled() const; + virtual void set_anchor_detection_is_enabled(bool p_enable); + + /** rendering and internal **/ + virtual Size2 get_recommended_render_targetsize(); + virtual bool is_stereo(); + virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform); + + // we expose a PoolVector<float> version of this function to GDNative + PoolVector<float> _get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); + + // and a CameraMatrix version to ARVRServer + virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); + + virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect); + + virtual void process(); +}; + +#endif // ARVR_INTERFACE_GDNATIVE_H diff --git a/modules/gdnative/nativearvr/config.py b/modules/gdnative/nativearvr/config.py new file mode 100644 index 0000000000..4d1bdfe4d1 --- /dev/null +++ b/modules/gdnative/nativearvr/config.py @@ -0,0 +1,5 @@ +def can_build(platform): + return True + +def configure(env): + pass diff --git a/modules/gdnative/nativearvr/register_types.cpp b/modules/gdnative/nativearvr/register_types.cpp new file mode 100644 index 0000000000..c7d7847a21 --- /dev/null +++ b/modules/gdnative/nativearvr/register_types.cpp @@ -0,0 +1,39 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* 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 "arvr_interface_gdnative.h" + +void register_nativearvr_types() { + ClassDB::register_class<ARVRInterfaceGDNative>(); +} + +void unregister_nativearvr_types() { +} diff --git a/modules/gdnative/nativearvr/register_types.h b/modules/gdnative/nativearvr/register_types.h new file mode 100644 index 0000000000..5e7557c7e9 --- /dev/null +++ b/modules/gdnative/nativearvr/register_types.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +void register_nativearvr_types(); +void unregister_nativearvr_types(); diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub index 178afec64a..ee3b9c351d 100644 --- a/modules/gdnative/nativescript/SCsub +++ b/modules/gdnative/nativescript/SCsub @@ -4,7 +4,6 @@ Import('env') mod_env = env.Clone() mod_env.add_source_files(env.modules_sources, "*.cpp") -mod_env.Append(CPPPATH='#modules/gdnative') mod_env.Append(CPPFLAGS=['-DGDAPI_BUILT_IN']) if "platform" in env and env["platform"] in ["x11", "iphone"]: diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index 9a956ff594..63fb71feb6 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -31,7 +31,7 @@ #ifdef TOOLS_ENABLED -#include "class_db.h" +#include "core/class_db.h" #include "core/global_constants.h" #include "core/pair.h" #include "core/project_settings.h" diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/gdnative/nativescript/api_generator.h index 56c2d786e6..a8e2eaf0bf 100644 --- a/modules/gdnative/nativescript/api_generator.h +++ b/modules/gdnative/nativescript/api_generator.h @@ -30,8 +30,8 @@ #ifndef API_GENERATOR_H #define API_GENERATOR_H +#include "core/typedefs.h" #include "core/ustring.h" -#include "typedefs.h" Error generate_c_api(const String &p_path); diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index b9bd65af53..aa1fdc32da 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -31,11 +31,11 @@ #include "gdnative/gdnative.h" -#include "global_constants.h" +#include "core/global_constants.h" +#include "core/project_settings.h" #include "io/file_access_encrypted.h" #include "os/file_access.h" #include "os/os.h" -#include "project_settings.h" #include "scene/main/scene_tree.h" #include "scene/resources/scene_format_text.h" @@ -137,7 +137,6 @@ bool NativeScript::can_instance() const { #endif } -// TODO(karroffel): implement this Ref<Script> NativeScript::get_base_script() const { NativeScriptDesc *script_data = get_script_desc(); @@ -1010,17 +1009,15 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { if (!library_script_users.has(lib_path)) library_script_users.insert(lib_path, Set<NativeScript *>()); - void *args[1] = { - (void *)&lib_path - }; + void *proc_ptr; + + Error err = gdn->get_symbol(_init_call_name, proc_ptr); - // here the library registers all the classes and stuff. - gdn->call_native_raw(_init_call_type, - _init_call_name, - NULL, - 1, - args, - NULL); + if (err != OK) { + ERR_PRINT(String("No " + _init_call_name + " in \"" + lib_path + "\" found").utf8().get_data()); + } else { + ((void (*)(godot_string *))proc_ptr)((godot_string *)&lib_path); + } } else { // already initialized. Nice. } @@ -1053,13 +1050,13 @@ 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_initialized()) { - L->get()->call_native_raw( - _noarg_call_type, - name, - NULL, - 0, - NULL, - NULL); + + void *proc_ptr; + Error err = L->get()->get_symbol(name, proc_ptr); + + if (!err) { + ((void (*)())proc_ptr)(); + } } } } @@ -1142,12 +1139,14 @@ void NativeReloadNode::_notification(int p_what) { }; // here the library registers all the classes and stuff. - L->get()->call_native_raw(NSL->_init_call_type, - NSL->_init_call_name, - NULL, - 1, - args, - NULL); + + void *proc_ptr; + Error err = L->get()->get_symbol("godot_nativescript_init", proc_ptr); + if (err != OK) { + ERR_PRINT(String("No godot_nativescript_init in \"" + L->key() + "\" found").utf8().get_data()); + } else { + ((void (*)(void *))proc_ptr)((void *)&L->key()); + } for (Map<String, Set<NativeScript *> >::Element *U = NSL->library_script_users.front(); U; U = U->next()) { for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) { diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index bc7e850d3e..b5db641179 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -30,14 +30,14 @@ #ifndef NATIVE_SCRIPT_H #define NATIVE_SCRIPT_H +#include "core/resource.h" +#include "core/script_language.h" +#include "core/self_list.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "ordered_hash_map.h" #include "os/thread_safe.h" -#include "resource.h" #include "scene/main/node.h" -#include "script_language.h" -#include "self_list.h" #include "modules/gdnative/gdnative.h" #include <nativescript/godot_nativescript.h> diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index b846710ab8..d734bba810 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -38,53 +38,6 @@ NativeScriptLanguage *native_script_language; -typedef void (*native_script_init_fn)(void *); - -void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { - if (p_handle == NULL) { - ERR_PRINT("No valid library handle, can't call nativescript init procedure"); - return; - } - - void *library_proc; - Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( - p_handle, - *(String *)p_proc_name, - library_proc, - true); // we print our own message - if (err != OK) { - ERR_PRINT((String("GDNative procedure \"" + *(String *)p_proc_name) + "\" does not exists and can't be called").utf8().get_data()); - return; - } - - native_script_init_fn fn = (native_script_init_fn)library_proc; - - fn(args[0]); -} - -typedef void (*native_script_empty_callback)(); - -void noarg_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { - if (p_handle == NULL) { - ERR_PRINT("No valid library handle, can't call nativescript callback"); - return; - } - - void *library_proc; - Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( - p_handle, - *(String *)p_proc_name, - library_proc, - true); - if (err != OK) { - // it's fine if thread callbacks are not present in the library. - return; - } - - native_script_empty_callback fn = (native_script_empty_callback)library_proc; - fn(); -} - ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL; ResourceFormatSaverNativeScript *resource_saver_gdns = NULL; @@ -95,9 +48,6 @@ void register_nativescript_types() { ScriptServer::register_language(native_script_language); - GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_init_call_type, init_call_cb); - GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_noarg_call_type, noarg_call_cb); - resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); ResourceSaver::add_resource_format_saver(resource_saver_gdns); diff --git a/modules/gdnative/pluginscript/SCsub b/modules/gdnative/pluginscript/SCsub new file mode 100644 index 0000000000..2031a4236b --- /dev/null +++ b/modules/gdnative/pluginscript/SCsub @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_pluginscript = env_modules.Clone() + +env_pluginscript.Append(CPPPATH=['#modules/gdnative/include/']) +env_pluginscript.add_source_files(env.modules_sources, '*.cpp') diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp new file mode 100644 index 0000000000..8f01350826 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* pluginscript_instance.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// Godot imports +#include "core/os/os.h" +#include "core/variant.h" +// PluginScript imports +#include "pluginscript_instance.h" +#include "pluginscript_language.h" +#include "pluginscript_script.h" + +bool PluginScriptInstance::set(const StringName &p_name, const Variant &p_value) { + String name = String(p_name); + return _desc->set_prop(_data, (const godot_string *)&name, (const godot_variant *)&p_value); +} + +bool PluginScriptInstance::get(const StringName &p_name, Variant &r_ret) const { + String name = String(p_name); + return _desc->get_prop(_data, (const godot_string *)&name, (godot_variant *)&r_ret); +} + +Ref<Script> PluginScriptInstance::get_script() const { + return _script; +} + +ScriptLanguage *PluginScriptInstance::get_language() { + return _script->get_language(); +} + +Variant::Type PluginScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { + if (!_script->has_property(p_name)) { + if (r_is_valid) { + *r_is_valid = false; + } + return Variant::NIL; + } + if (r_is_valid) { + *r_is_valid = true; + } + return _script->get_property_info(p_name).type; +} + +void PluginScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { + _script->get_script_property_list(p_properties); +} + +void PluginScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + _script->get_script_method_list(p_list); +} + +bool PluginScriptInstance::has_method(const StringName &p_method) const { + return _script->has_method(p_method); +} + +Variant PluginScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + // TODO: optimize when calling a Godot method from Godot to avoid param conversion ? + godot_variant ret = _desc->call_method( + _data, (godot_string_name *)&p_method, (const godot_variant **)p_args, + p_argcount, (godot_variant_call_error *)&r_error); + Variant *var_ret = (Variant *)&ret; + return *var_ret; +} + +#if 0 // TODO: Don't rely on default implementations provided by ScriptInstance ? +void PluginScriptInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount) { + +#if 0 + PluginScript *sptr=script.ptr(); + Variant::CallError ce; + + while(sptr) { + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); + if (E) { + E->get()->call(this,p_args,p_argcount,ce); + } + sptr = sptr->_base; + } +#endif + +} + +#if 0 +void PluginScriptInstance::_ml_call_reversed(PluginScript *sptr,const StringName& p_method,const Variant** p_args,int p_argcount) { + + if (sptr->_base) + _ml_call_reversed(sptr->_base,p_method,p_args,p_argcount); + + Variant::CallError ce; + + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); + if (E) { + E->get()->call(this,p_args,p_argcount,ce); + } + +} +#endif + + +void PluginScriptInstance::call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount) { + +#if 0 + if (script.ptr()) { + _ml_call_reversed(script.ptr(),p_method,p_args,p_argcount); + } +#endif +} +#endif // Multilevel stuff + +void PluginScriptInstance::notification(int p_notification) { + _desc->notification(_data, p_notification); +} + +ScriptInstance::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const { + return _script->get_rpc_mode(p_method); +} + +ScriptInstance::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const { + return _script->get_rset_mode(p_variable); +} + +void PluginScriptInstance::refcount_incremented() { + if (_desc->refcount_decremented) { + _desc->refcount_incremented(_data); + } +} + +bool PluginScriptInstance::refcount_decremented() { + // Return true if it can die + if (_desc->refcount_decremented) { + return _desc->refcount_decremented(_data); + } + return true; +} + +PluginScriptInstance::PluginScriptInstance() { +} + +bool PluginScriptInstance::init(PluginScript *p_script, Object *p_owner) { + _owner = p_owner; + _owner_variant = Variant(p_owner); + _script = Ref<PluginScript>(p_script); + _desc = &p_script->_desc->instance_desc; + _data = _desc->init(p_script->_data, (godot_object *)p_owner); + ERR_FAIL_COND_V(_data == NULL, false); + p_owner->set_script_instance(this); + return true; +} + +PluginScriptInstance::~PluginScriptInstance() { + _desc->finish(_data); + _script->_language->lock(); + _script->_instances.erase(_owner); + _script->_language->unlock(); +} diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h new file mode 100644 index 0000000000..68696b4417 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* pluginscript_instance.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PLUGINSCRIPT_INSTANCE_H +#define PLUGINSCRIPT_INSTANCE_H + +// Godot imports +#include "core/script_language.h" +// PluginScript imports +#include <pluginscript/godot_pluginscript.h> + +class PluginScript; + +class PluginScriptInstance : public ScriptInstance { + friend class PluginScript; + +private: + Ref<PluginScript> _script; + Object *_owner; + Variant _owner_variant; + godot_pluginscript_instance_data *_data; + const godot_pluginscript_instance_desc *_desc; + +public: + _FORCE_INLINE_ Object *get_owner() { return _owner; } + + virtual bool set(const StringName &p_name, const Variant &p_value); + virtual bool get(const StringName &p_name, Variant &r_ret) const; + virtual void get_property_list(List<PropertyInfo> *p_properties) const; + virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const; + + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName &p_method) const; + + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); +#if 0 + // Rely on default implementations provided by ScriptInstance for the moment. + // Note that multilevel call could be removed in 3.0 release, so stay tunned + // (see https://godotengine.org/qa/9244/can-override-the-_ready-and-_process-functions-child-classes) + virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); + virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount); +#endif + + virtual void notification(int p_notification); + + virtual Ref<Script> get_script() const; + + virtual ScriptLanguage *get_language(); + + void set_path(const String &p_path); + + virtual RPCMode get_rpc_mode(const StringName &p_method) const; + virtual RPCMode get_rset_mode(const StringName &p_variable) const; + + virtual void refcount_incremented(); + virtual bool refcount_decremented(); + + PluginScriptInstance(); + bool init(PluginScript *p_script, Object *p_owner); + virtual ~PluginScriptInstance(); +}; + +#endif // PLUGINSCRIPT_INSTANCE_H diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp new file mode 100644 index 0000000000..d4b86ae5b4 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -0,0 +1,431 @@ +/*************************************************************************/ +/* pluginscript_language.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// Godot imports +#include "core/os/file_access.h" +#include "core/os/os.h" +#include "core/project_settings.h" +// PluginScript imports +#include "pluginscript_language.h" +#include "pluginscript_script.h" + +String PluginScriptLanguage::get_name() const { + return String(_desc.name); +} + +void PluginScriptLanguage::init() { + _data = _desc.init(); +} + +String PluginScriptLanguage::get_type() const { + return String(_desc.type); +} + +String PluginScriptLanguage::get_extension() const { + return String(_desc.extension); +} + +Error PluginScriptLanguage::execute_file(const String &p_path) { + // TODO: pretty sure this method is totally deprecated and should be removed... + return OK; +} + +void PluginScriptLanguage::finish() { + _desc.finish(_data); +} + +/* EDITOR FUNCTIONS */ + +void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const { + if (_desc.reserved_words) { + const char **w = _desc.reserved_words; + while (*w) { + p_words->push_back(*w); + w++; + } + } +} + +void PluginScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { + if (_desc.comment_delimiters) { + const char **w = _desc.comment_delimiters; + while (*w) { + p_delimiters->push_back(*w); + w++; + } + } +} + +void PluginScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { + if (_desc.string_delimiters) { + const char **w = _desc.string_delimiters; + while (*w) { + p_delimiters->push_back(*w); + w++; + } + } +} + +Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { + Script *ns = create_script(); + Ref<Script> script = Ref<Script>(ns); + if (_desc.get_template_source_code) { + godot_string src = _desc.get_template_source_code(_data, (godot_string *)&p_class_name, (godot_string *)&p_base_class_name); + script->set_source_code(*(String *)&src); + } + return script; +} + +bool PluginScriptLanguage::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 { + PoolStringArray functions; + if (_desc.validate) { + bool ret = _desc.validate( + _data, + (godot_string *)&p_script, + &r_line_error, + &r_col_error, + (godot_string *)&r_test_error, + (godot_string *)&p_path, + (godot_pool_string_array *)&functions); + for (int i = 0; i < functions.size(); i++) { + r_functions->push_back(functions[i]); + } + return ret; + } + return true; +} + +Script *PluginScriptLanguage::create_script() const { + PluginScript *script = memnew(PluginScript()); + // I'm hurting kittens doing this I guess... + script->init(const_cast<PluginScriptLanguage *>(this)); + return script; +} + +bool PluginScriptLanguage::has_named_classes() const { + return _desc.has_named_classes; +} + +int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const { + if (_desc.find_function) { + return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code); + } + return -1; +} + +String PluginScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { + if (_desc.make_function) { + godot_string tmp = _desc.make_function(_data, (godot_string *)&p_class, (godot_string *)&p_name, (godot_pool_string_array *)&p_args); + String ret = *(String *)&tmp; + godot_string_destroy(&tmp); + return ret; + } + return String(); +} + +Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) { + if (_desc.complete_code) { + Array options; + godot_error tmp = _desc.complete_code( + _data, + (godot_string *)&p_code, + (godot_string *)&p_base_path, + (godot_object *)p_owner, + (godot_array *)&options, + &r_force, + (godot_string *)&r_call_hint); + for (int i = 0; i < options.size(); i++) { + r_options->push_back(String(options[i])); + } + Error err = *(Error *)tmp; + return err; + } + return ERR_UNAVAILABLE; +} + +void PluginScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { + if (_desc.auto_indent_code) { + _desc.auto_indent_code(_data, (godot_string *)&p_code, p_from_line, p_to_line); + } + return; +} + +void PluginScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { + const String variable = String(p_variable); + _desc.add_global_constant(_data, (godot_string *)&variable, (godot_variant *)&p_value); +} + +/* LOADER FUNCTIONS */ + +void PluginScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { + for (int i = 0; _desc.recognized_extensions[i]; ++i) { + p_extensions->push_back(String(_desc.recognized_extensions[i])); + } +} + +void PluginScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { + // TODO: provid this statically in `godot_pluginscript_language_desc` ? + if (_desc.get_public_functions) { + Array functions; + _desc.get_public_functions(_data, (godot_array *)&functions); + for (int i = 0; i < functions.size(); i++) { + MethodInfo mi = MethodInfo::from_dict(functions[i]); + p_functions->push_back(mi); + } + } +} + +void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { + // TODO: provid this statically in `godot_pluginscript_language_desc` ? + if (_desc.get_public_constants) { + Dictionary constants; + _desc.get_public_constants(_data, (godot_dictionary *)&constants); + for (const Variant *key = constants.next(); key; key = constants.next(key)) { + Variant value = constants[key]; + p_constants->push_back(Pair<String, Variant>(*key, value)); + } + } +} + +void PluginScriptLanguage::profiling_start() { +#ifdef DEBUG_ENABLED + if (_desc.profiling_start) { + lock(); + _desc.profiling_start(_data); + unlock(); + } +#endif +} + +void PluginScriptLanguage::profiling_stop() { +#ifdef DEBUG_ENABLED + if (_desc.profiling_stop) { + lock(); + _desc.profiling_stop(_data); + unlock(); + } +#endif +} + +int PluginScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { + int info_count = 0; +#ifdef DEBUG_ENABLED + if (_desc.profiling_get_accumulated_data) { + godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc( + sizeof(godot_pluginscript_profiling_data) * p_info_max); + info_count = _desc.profiling_get_accumulated_data(_data, info, p_info_max); + for (int i = 0; i < info_count; ++i) { + p_info_arr[i].signature = *(StringName *)&info[i].signature; + p_info_arr[i].call_count = info[i].call_count; + p_info_arr[i].total_time = info[i].total_time; + p_info_arr[i].self_time = info[i].self_time; + godot_string_name_destroy(&info[i].signature); + } + } +#endif + return info_count; +} + +int PluginScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { + int info_count = 0; +#ifdef DEBUG_ENABLED + if (_desc.profiling_get_frame_data) { + godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc( + sizeof(godot_pluginscript_profiling_data) * p_info_max); + info_count = _desc.profiling_get_frame_data(_data, info, p_info_max); + for (int i = 0; i < info_count; ++i) { + p_info_arr[i].signature = *(StringName *)&info[i].signature; + p_info_arr[i].call_count = info[i].call_count; + p_info_arr[i].total_time = info[i].total_time; + p_info_arr[i].self_time = info[i].self_time; + godot_string_name_destroy(&info[i].signature); + } + } +#endif + return info_count; +} + +void PluginScriptLanguage::frame() { +#ifdef DEBUG_ENABLED + if (_desc.profiling_frame) { + _desc.profiling_frame(_data); + } +#endif +} + +/* DEBUGGER FUNCTIONS */ + +String PluginScriptLanguage::debug_get_error() const { + if (_desc.debug_get_error) { + godot_string tmp = _desc.debug_get_error(_data); + String ret = *(String *)&tmp; + godot_string_destroy(&tmp); + return ret; + } + return String("Nothing"); +} + +int PluginScriptLanguage::debug_get_stack_level_count() const { + if (_desc.debug_get_stack_level_count) { + return _desc.debug_get_stack_level_count(_data); + } + return 1; +} + +int PluginScriptLanguage::debug_get_stack_level_line(int p_level) const { + if (_desc.debug_get_stack_level_line) { + return _desc.debug_get_stack_level_line(_data, p_level); + } + return 1; +} + +String PluginScriptLanguage::debug_get_stack_level_function(int p_level) const { + if (_desc.debug_get_stack_level_function) { + godot_string tmp = _desc.debug_get_stack_level_function(_data, p_level); + String ret = *(String *)&tmp; + godot_string_destroy(&tmp); + return ret; + } + return String("Nothing"); +} + +String PluginScriptLanguage::debug_get_stack_level_source(int p_level) const { + if (_desc.debug_get_stack_level_source) { + godot_string tmp = _desc.debug_get_stack_level_source(_data, p_level); + String ret = *(String *)&tmp; + godot_string_destroy(&tmp); + return ret; + } + return String("Nothing"); +} + +void PluginScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + if (_desc.debug_get_stack_level_locals) { + PoolStringArray locals; + Array values; + _desc.debug_get_stack_level_locals(_data, p_level, (godot_pool_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth); + for (int i = 0; i < locals.size(); i++) { + p_locals->push_back(locals[i]); + } + for (int i = 0; i < values.size(); i++) { + p_values->push_back(values[i]); + } + } +} + +void PluginScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + if (_desc.debug_get_stack_level_members) { + PoolStringArray members; + Array values; + _desc.debug_get_stack_level_members(_data, p_level, (godot_pool_string_array *)&members, (godot_array *)&values, p_max_subitems, p_max_depth); + for (int i = 0; i < members.size(); i++) { + p_members->push_back(members[i]); + } + for (int i = 0; i < values.size(); i++) { + p_values->push_back(values[i]); + } + } +} + +void PluginScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + if (_desc.debug_get_globals) { + PoolStringArray locals; + Array values; + _desc.debug_get_globals(_data, (godot_pool_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth); + for (int i = 0; i < locals.size(); i++) { + p_locals->push_back(locals[i]); + } + for (int i = 0; i < values.size(); i++) { + p_values->push_back(values[i]); + } + } +} + +String PluginScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { + if (_desc.debug_parse_stack_level_expression) { + godot_string tmp = _desc.debug_parse_stack_level_expression(_data, p_level, (godot_string *)&p_expression, p_max_subitems, p_max_depth); + String ret = *(String *)&tmp; + godot_string_destroy(&tmp); + return ret; + } + return String("Nothing"); +} + +void PluginScriptLanguage::reload_all_scripts() { + // TODO +} + +void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { +#ifdef DEBUG_ENABLED + lock(); + // TODO + unlock(); +#endif +} + +void PluginScriptLanguage::lock() { +#ifndef NO_THREADS + if (_lock) { + _lock->lock(); + } +#endif +} + +void PluginScriptLanguage::unlock() { +#ifndef NO_THREADS + if (_lock) { + _lock->unlock(); + } +#endif +} + +PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc) + : _desc(*desc) { + _resource_loader = memnew(ResourceFormatLoaderPluginScript(this)); + _resource_saver = memnew(ResourceFormatSaverPluginScript(this)); + +// TODO: totally remove _lock attribute if NO_THREADS is set +#ifdef NO_THREADS + _lock = NULL; +#else + _lock = Mutex::create(); +#endif +} + +PluginScriptLanguage::~PluginScriptLanguage() { + memdelete(_resource_loader); + memdelete(_resource_saver); +#ifndef NO_THREADS + if (_lock) { + memdelete(_lock); + _lock = NULL; + } +#endif +} diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h new file mode 100644 index 0000000000..a48dde97ce --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -0,0 +1,131 @@ +/*************************************************************************/ +/* pluginscript_language.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PLUGINSCRIPT_LANGUAGE_H +#define PLUGINSCRIPT_LANGUAGE_H + +// Godot imports +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "core/map.h" +#include "core/script_language.h" +#include "core/self_list.h" +// PluginScript imports +#include "pluginscript_loader.h" +#include <pluginscript/godot_pluginscript.h> + +class PluginScript; +class PluginScriptInstance; + +class PluginScriptLanguage : public ScriptLanguage { + friend class PluginScript; + friend class PluginScriptInstance; + + ResourceFormatLoaderPluginScript *_resource_loader; + ResourceFormatSaverPluginScript *_resource_saver; + const godot_pluginscript_language_desc _desc; + godot_pluginscript_language_data *_data; + + Mutex *_lock; + SelfList<PluginScript>::List _script_list; + +public: + virtual String get_name() const; + + _FORCE_INLINE_ ResourceFormatLoaderPluginScript *get_resource_loader() { return _resource_loader; }; + _FORCE_INLINE_ ResourceFormatSaverPluginScript *get_resource_saver() { return _resource_saver; }; + + /* LANGUAGE FUNCTIONS */ + virtual void init(); + virtual String get_type() const; + virtual String get_extension() const; + virtual Error execute_file(const String &p_path); + virtual void finish(); + + /* EDITOR FUNCTIONS */ + virtual void get_reserved_words(List<String> *p_words) const; + 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 = NULL) const; + virtual Script *create_script() const; + virtual bool has_named_classes() const; + virtual bool can_inherit_from_file() { return true; } + virtual int find_function(const String &p_function, const String &p_code) const; + virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; + virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint); + virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; + virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); + + /* MULTITHREAD FUNCTIONS */ + + //some VMs need to be notified of thread creation/exiting to allocate a stack + // void thread_enter() {} + // void thread_exit() {} + + /* DEBUGGER FUNCTIONS */ + + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; + virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); + + // virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); } + + virtual void reload_all_scripts(); + virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + + /* LOADER FUNCTIONS */ + + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual void get_public_functions(List<MethodInfo> *p_functions) const; + virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const; + + virtual void profiling_start(); + 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); + + virtual void frame(); + + void lock(); + void unlock(); + + PluginScriptLanguage(const godot_pluginscript_language_desc *desc); + virtual ~PluginScriptLanguage(); +}; + +#endif // PLUGINSCRIPT_LANGUAGE_H diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp new file mode 100644 index 0000000000..3648e1a5b4 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp @@ -0,0 +1,113 @@ +/*************************************************************************/ +/* pluginscript_loader.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// Godot imports +#include "os/file_access.h" +// Pythonscript imports +#include "pluginscript_language.h" +#include "pluginscript_loader.h" +#include "pluginscript_script.h" + +ResourceFormatLoaderPluginScript::ResourceFormatLoaderPluginScript(PluginScriptLanguage *language) { + _language = language; +} + +RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error) { + if (r_error) + *r_error = ERR_FILE_CANT_OPEN; + + PluginScript *script = memnew(PluginScript); + script->init(_language); + + Ref<PluginScript> scriptres(script); + + Error err = script->load_source_code(p_path); + ERR_FAIL_COND_V(err != OK, RES()); + + script->set_path(p_original_path); + + script->reload(); + + if (r_error) + *r_error = OK; + + return scriptres; +} + +void ResourceFormatLoaderPluginScript::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back(_language->get_extension()); +} + +bool ResourceFormatLoaderPluginScript::handles_type(const String &p_type) const { + return p_type == "Script" || p_type == _language->get_type(); +} + +String ResourceFormatLoaderPluginScript::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == _language->get_extension()) + return _language->get_type(); + return ""; +} + +ResourceFormatSaverPluginScript::ResourceFormatSaverPluginScript(PluginScriptLanguage *language) { + _language = language; +} + +Error ResourceFormatSaverPluginScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + Ref<PluginScript> sqscr = p_resource; + ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); + + String source = sqscr->get_source_code(); + + Error err; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(err, err); + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } + file->close(); + memdelete(file); + return OK; +} + +void ResourceFormatSaverPluginScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + + if (Object::cast_to<PluginScript>(*p_resource)) { + p_extensions->push_back(_language->get_extension()); + } +} + +bool ResourceFormatSaverPluginScript::recognize(const RES &p_resource) const { + + return Object::cast_to<PluginScript>(*p_resource) != NULL; +} diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h new file mode 100644 index 0000000000..b85e7725a1 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_loader.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* pluginscript_loader.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PYTHONSCRIPT_PY_LOADER_H +#define PYTHONSCRIPT_PY_LOADER_H + +// Godot imports +#include "core/script_language.h" +#include "io/resource_loader.h" +#include "io/resource_saver.h" + +class PluginScriptLanguage; + +class ResourceFormatLoaderPluginScript : public ResourceFormatLoader { + PluginScriptLanguage *_language; + +public: + ResourceFormatLoaderPluginScript(PluginScriptLanguage *language); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +class ResourceFormatSaverPluginScript : public ResourceFormatSaver { + PluginScriptLanguage *_language; + +public: + ResourceFormatSaverPluginScript(PluginScriptLanguage *language); + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const RES &p_resource) const; +}; + +#endif // PYTHONSCRIPT_PY_LOADER_H diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp new file mode 100644 index 0000000000..7dd10a8bdf --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -0,0 +1,454 @@ +/*************************************************************************/ +/* pluginscript_script.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// Godot imports +#include "core/os/file_access.h" +// PluginScript imports +#include "pluginscript_instance.h" +#include "pluginscript_script.h" + +#if DEBUG_ENABLED +#define __ASSERT_SCRIPT_REASON "Cannot retrieve pluginscript class for this script, is you code correct ?" +#define ASSERT_SCRIPT_VALID() \ + { \ + ERR_EXPLAIN(__ASSERT_SCRIPT_REASON); \ + ERR_FAIL_COND(!can_instance()) \ + } +#define ASSERT_SCRIPT_VALID_V(ret) \ + { \ + ERR_EXPLAIN(__ASSERT_SCRIPT_REASON); \ + ERR_FAIL_COND_V(!can_instance(), ret) \ + } +#else +#define ASSERT_SCRIPT_VALID() +#define ASSERT_SCRIPT_VALID_V(ret) +#endif + +void PluginScript::_bind_methods() { +} + +#ifdef TOOLS_ENABLED + +void PluginScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + placeholders.erase(p_placeholder); +} + +#endif + +bool PluginScript::can_instance() const { + bool can = _valid || (!_tool && !ScriptServer::is_scripting_enabled()); + return can; +} + +Ref<Script> PluginScript::get_base_script() const { + if (_ref_base_parent.is_valid()) { + return Ref<PluginScript>(_ref_base_parent); + } else { + return Ref<Script>(); + } +} + +StringName PluginScript::get_instance_base_type() const { + if (_native_parent) + return _native_parent; + if (_ref_base_parent.is_valid()) + return _ref_base_parent->get_instance_base_type(); + return StringName(); +} + +void PluginScript::update_exports() { +// TODO +#ifdef TOOLS_ENABLED +#if 0 + ASSERT_SCRIPT_VALID(); + if (/*changed &&*/ placeholders.size()) { //hm :( + + //update placeholders if any + Map<StringName, Variant> propdefvalues; + List<PropertyInfo> propinfos; + const String *props = (const String *)pybind_get_prop_list(_py_exposed_class); + for (int i = 0; props[i] != ""; ++i) { + const String propname = props[i]; + pybind_get_prop_default_value(_py_exposed_class, propname.c_str(), (godot_variant *)&propdefvalues[propname]); + pybind_prop_info raw_info; + pybind_get_prop_info(_py_exposed_class, propname.c_str(), &raw_info); + PropertyInfo info; + info.type = (Variant::Type)raw_info.type; + info.name = propname; + info.hint = (PropertyHint)raw_info.hint; + info.hint_string = *(String *)&raw_info.hint_string; + info.usage = raw_info.usage; + propinfos.push_back(info); + } + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->update(propinfos, propdefvalues); + } + } +#endif +#endif +} + +// TODO: rename p_this "p_owner" ? +ScriptInstance *PluginScript::instance_create(Object *p_this) { + ASSERT_SCRIPT_VALID_V(NULL); + // TODO check script validity ? + if (!_tool && !ScriptServer::is_scripting_enabled()) { +#ifdef TOOLS_ENABLED + // Instance a fake script for editing the values + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(get_language(), Ref<Script>(this), p_this)); + placeholders.insert(si); + update_exports(); + return si; +#else + return NULL; +#endif + } + + PluginScript *top = this; + // TODO: can be optimized by storing a PluginScript::_base_parent direct pointer + while (top->_ref_base_parent.is_valid()) + top = top->_ref_base_parent.ptr(); + if (top->_native_parent) { + if (!ClassDB::is_parent_class(p_this->get_class_name(), top->_native_parent)) { + String msg = "Script inherits from native type '" + String(top->_native_parent) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"; + // TODO: implement PluginscriptLanguage::debug_break_parse + // if (ScriptDebugger::get_singleton()) { + // _language->debug_break_parse(get_path(), 0, msg); + // } + ERR_EXPLAIN(msg); + ERR_FAIL_V(NULL); + } + } + + PluginScriptInstance *instance = memnew(PluginScriptInstance()); + const bool success = instance->init(this, p_this); + if (success) { + _language->lock(); + _instances.insert(instance->get_owner()); + _language->unlock(); + return instance; + } else { + memdelete(instance); + ERR_FAIL_V(NULL); + } +} + +bool PluginScript::instance_has(const Object *p_this) const { + _language->lock(); + bool hasit = _instances.has((Object *)p_this); + _language->unlock(); + return hasit; +} + +bool PluginScript::has_source_code() const { + bool has = _source != ""; + return has; +} + +String PluginScript::get_source_code() const { + return _source; +} + +void PluginScript::set_source_code(const String &p_code) { + if (_source == p_code) + return; + _source = p_code; +} + +Error PluginScript::reload(bool p_keep_state) { + _language->lock(); + ERR_FAIL_COND_V(!p_keep_state && _instances.size(), ERR_ALREADY_IN_USE); + _language->unlock(); + + _valid = false; + String basedir = _path; + + if (basedir == "") + basedir = get_path(); + + if (basedir != "") + basedir = basedir.get_base_dir(); + + if (_data) { + _desc->finish(_data); + } + + Error err; + godot_pluginscript_script_manifest manifest = _desc->init( + _language->_data, + (godot_string *)&_path, + (godot_string *)&_source, + (godot_error *)&err); + if (err) { + // TODO: GDscript uses `ScriptDebugger` here to jump into the parsing error + return err; + } + _valid = true; + // Use the manifest to configure this script object + _data = manifest.data; + _name = *(StringName *)&manifest.name; + _tool = manifest.is_tool; + // Base name is either another PluginScript or a regular class accessible + // through ClassDB + StringName *base_name = (StringName *)&manifest.base; + for (SelfList<PluginScript> *e = _language->_script_list.first(); e != NULL; e = e->next()) { + if (e->self()->_name == *base_name) { + // Found you, base is a PluginScript ! + _ref_base_parent = Ref<PluginScript>(e->self()); + break; + } + } + if (!_ref_base_parent.is_valid()) { + // Base is a native ClassDB + if (!ClassDB::class_exists(*base_name)) { + ERR_EXPLAIN("Unknown script '" + String(_name) + "' parent '" + String(*base_name) + "'."); + ERR_FAIL_V(ERR_PARSE_ERROR); + } + _native_parent = *base_name; + } + + Dictionary *members = (Dictionary *)&manifest.member_lines; + for (const Variant *key = members->next(); key != NULL; key = members->next(key)) { + _member_lines[*key] = (*members)[key]; + } + Array *methods = (Array *)&manifest.methods; + for (int i = 0; i < methods->size(); ++i) { + Dictionary v = (*methods)[i]; + MethodInfo mi = MethodInfo::from_dict(v); + _methods_info[mi.name] = mi; + // rpc_mode is passed as an optional field and is not part of MethodInfo + Variant var = v["rpc_mode"]; + if (var == Variant()) { + _methods_rpc_mode[mi.name] = ScriptInstance::RPC_MODE_DISABLED; + } else { + _methods_rpc_mode[mi.name] = ScriptInstance::RPCMode(int(var)); + } + } + Array *signals = (Array *)&manifest.signals; + for (int i = 0; i < signals->size(); ++i) { + Variant v = (*signals)[i]; + MethodInfo mi = MethodInfo::from_dict(v); + _signals_info[mi.name] = mi; + } + Array *properties = (Array *)&manifest.properties; + for (int i = 0; i < properties->size(); ++i) { + Dictionary v = (*properties)[i]; + PropertyInfo pi = PropertyInfo::from_dict(v); + _properties_info[pi.name] = pi; + _properties_default_values[pi.name] = v["default_value"]; + // rset_mode is passed as an optional field and is not part of PropertyInfo + Variant var = v["rset_mode"]; + if (var == Variant()) { + _methods_rpc_mode[pi.name] = ScriptInstance::RPC_MODE_DISABLED; + } else { + _methods_rpc_mode[pi.name] = ScriptInstance::RPCMode(int(var)); + } + } + // Manifest's attributes must be explicitly freed + godot_string_name_destroy(&manifest.name); + godot_string_name_destroy(&manifest.base); + godot_dictionary_destroy(&manifest.member_lines); + godot_array_destroy(&manifest.methods); + godot_array_destroy(&manifest.signals); + godot_array_destroy(&manifest.properties); + +#ifdef TOOLS_ENABLED +/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + + _update_placeholder(E->get()); + }*/ +#endif + return OK; +} + +void PluginScript::get_script_method_list(List<MethodInfo> *r_methods) const { + ASSERT_SCRIPT_VALID(); + for (Map<StringName, MethodInfo>::Element *e = _methods_info.front(); e != NULL; e = e->next()) { + r_methods->push_back(e->get()); + } +} + +void PluginScript::get_script_property_list(List<PropertyInfo> *r_properties) const { + ASSERT_SCRIPT_VALID(); + for (Map<StringName, PropertyInfo>::Element *e = _properties_info.front(); e != NULL; e = e->next()) { + r_properties->push_back(e->get()); + } +} + +bool PluginScript::has_method(const StringName &p_method) const { + ASSERT_SCRIPT_VALID_V(false); + return _methods_info.has(p_method); +} + +MethodInfo PluginScript::get_method_info(const StringName &p_method) const { + ASSERT_SCRIPT_VALID_V(MethodInfo()); + const Map<StringName, MethodInfo>::Element *e = _methods_info.find(p_method); + if (e != NULL) { + return e->get(); + } else { + return MethodInfo(); + } +} + +bool PluginScript::has_property(const StringName &p_method) const { + ASSERT_SCRIPT_VALID_V(false); + return _properties_info.has(p_method); +} + +PropertyInfo PluginScript::get_property_info(const StringName &p_property) const { + ASSERT_SCRIPT_VALID_V(PropertyInfo()); + const Map<StringName, PropertyInfo>::Element *e = _properties_info.find(p_property); + if (e != NULL) { + return e->get(); + } else { + return PropertyInfo(); + } +} + +bool PluginScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { + ASSERT_SCRIPT_VALID_V(false); +#ifdef TOOLS_ENABLED + const Map<StringName, Variant>::Element *e = _properties_default_values.find(p_property); + if (e != NULL) { + r_value = e->get(); + return true; + } else { + return false; + } +#endif + return false; +} + +String PluginScript::get_node_type() const { + // Even GDscript doesn't know what to put here ! + return ""; // ? +} + +ScriptLanguage *PluginScript::get_language() const { + return _language; +} + +Error PluginScript::load_source_code(const String &p_path) { + + PoolVector<uint8_t> sourcef; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + if (err) { + ERR_FAIL_COND_V(err, err); + } + + int len = f->get_len(); + sourcef.resize(len + 1); + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = f->get_buffer(w.ptr(), len); + f->close(); + memdelete(f); + ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode."); + ERR_FAIL_V(ERR_INVALID_DATA); + } + + _source = s; +#ifdef TOOLS_ENABLED +// source_changed_cache=true; +#endif + _path = p_path; + return OK; +} + +bool PluginScript::has_script_signal(const StringName &p_signal) const { + ASSERT_SCRIPT_VALID_V(false); + return _signals_info.has(p_signal); +} + +void PluginScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + ASSERT_SCRIPT_VALID(); + for (Map<StringName, MethodInfo>::Element *e = _signals_info.front(); e != NULL; e = e->next()) { + r_signals->push_back(e->get()); + } +} + +int PluginScript::get_member_line(const StringName &p_member) const { +#ifdef TOOLS_ENABLED + if (_member_lines.has(p_member)) + return _member_lines[p_member]; + else +#endif + return -1; +} + +ScriptInstance::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const { + ASSERT_SCRIPT_VALID_V(ScriptInstance::RPC_MODE_DISABLED); + const Map<StringName, ScriptInstance::RPCMode>::Element *e = _methods_rpc_mode.find(p_method); + if (e != NULL) { + return e->get(); + } else { + return ScriptInstance::RPC_MODE_DISABLED; + } +} + +ScriptInstance::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const { + ASSERT_SCRIPT_VALID_V(ScriptInstance::RPC_MODE_DISABLED); + const Map<StringName, ScriptInstance::RPCMode>::Element *e = _variables_rset_mode.find(p_variable); + if (e != NULL) { + return e->get(); + } else { + return ScriptInstance::RPC_MODE_DISABLED; + } +} + +PluginScript::PluginScript() + : _data(NULL), _tool(false), _valid(false), _script_list(this) { +} + +void PluginScript::init(PluginScriptLanguage *language) { + _desc = &language->_desc.script_desc; + _language = language; + +#ifdef DEBUG_ENABLED + _language->lock(); + _language->_script_list.add(&_script_list); + _language->unlock(); +#endif +} + +PluginScript::~PluginScript() { + _desc->finish(_data); + +#ifdef DEBUG_ENABLED + _language->lock(); + _language->_script_list.remove(&_script_list); + _language->unlock(); +#endif +} diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h new file mode 100644 index 0000000000..e6b8643cd9 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -0,0 +1,129 @@ +/*************************************************************************/ +/* pluginscript_script.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PLUGINSCRIPT_SCRIPT_H +#define PLUGINSCRIPT_SCRIPT_H + +// Godot imports +#include "core/script_language.h" +// PluginScript imports +#include "pluginscript_language.h" +#include <pluginscript/godot_pluginscript.h> + +class PyInstance; + +class PluginScript : public Script { + + GDCLASS(PluginScript, Script); + + friend class PluginScriptInstance; + friend class PluginScriptLanguage; + +private: + godot_pluginscript_script_data *_data; + const godot_pluginscript_script_desc *_desc; + PluginScriptLanguage *_language; + bool _tool; + bool _valid; + + Ref<PluginScript> _ref_base_parent; + StringName _native_parent; + SelfList<PluginScript> _script_list; + + Map<StringName, int> _member_lines; + Map<StringName, Variant> _properties_default_values; + Map<StringName, PropertyInfo> _properties_info; + Map<StringName, MethodInfo> _signals_info; + Map<StringName, MethodInfo> _methods_info; + Map<StringName, ScriptInstance::RPCMode> _variables_rset_mode; + Map<StringName, ScriptInstance::RPCMode> _methods_rpc_mode; + + Set<Object *> _instances; + //exported members + String _source; + String _path; + StringName _name; + +protected: + static void _bind_methods(); + +#ifdef TOOLS_ENABLED + Set<PlaceHolderScriptInstance *> placeholders; + //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); +#endif +public: + virtual bool can_instance() const; + + virtual Ref<Script> get_base_script() const; //for script inheritance + + virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so + virtual ScriptInstance *instance_create(Object *p_this); + virtual bool instance_has(const Object *p_this) const; + + virtual bool has_source_code() const; + virtual String get_source_code() const; + virtual void set_source_code(const String &p_code); + virtual Error reload(bool p_keep_state = false); + // TODO: load_source_code only allow utf-8 file, should handle bytecode as well ? + virtual Error load_source_code(const String &p_path); + + virtual bool has_method(const StringName &p_method) const; + virtual MethodInfo get_method_info(const StringName &p_method) const; + + bool has_property(const StringName &p_method) const; + PropertyInfo get_property_info(const StringName &p_property) const; + + bool is_tool() const { return _tool; } + + virtual String get_node_type() const; + + virtual ScriptLanguage *get_language() const; + + virtual bool has_script_signal(const StringName &p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + + virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + + virtual void update_exports(); + virtual void get_script_method_list(List<MethodInfo> *r_methods) const; + virtual void get_script_property_list(List<PropertyInfo> *r_propertieslist) const; + + virtual int get_member_line(const StringName &p_member) const; + + ScriptInstance::RPCMode get_rpc_mode(const StringName &p_method) const; + ScriptInstance::RPCMode get_rset_mode(const StringName &p_variable) const; + + PluginScript(); + void init(PluginScriptLanguage *language); + virtual ~PluginScript(); +}; + +#endif // PLUGINSCRIPT_SCRIPT_H diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp new file mode 100644 index 0000000000..5829d08dff --- /dev/null +++ b/modules/gdnative/pluginscript/register_types.cpp @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* 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 "core/project_settings.h" +#include "io/resource_loader.h" +#include "io/resource_saver.h" +#include "os/dir_access.h" +#include "os/os.h" +#include "scene/main/scene_tree.h" + +#include "pluginscript_language.h" +#include "pluginscript_script.h" +#include <pluginscript/godot_pluginscript.h> + +static List<PluginScriptLanguage *> pluginscript_languages; + +static Error _check_language_desc(const godot_pluginscript_language_desc *desc) { + ERR_FAIL_COND_V(!desc->name || desc->name == String(), ERR_BUG); + ERR_FAIL_COND_V(!desc->type || desc->type == String(), ERR_BUG); + ERR_FAIL_COND_V(!desc->extension || desc->extension == String(), ERR_BUG); + ERR_FAIL_COND_V(!desc->recognized_extensions || !desc->recognized_extensions[0], ERR_BUG); + ERR_FAIL_COND_V(!desc->init, ERR_BUG); + ERR_FAIL_COND_V(!desc->finish, ERR_BUG); + + // desc->reserved_words is not mandatory + // desc->comment_delimiters is not mandatory + // desc->string_delimiters is not mandatory + + // desc->get_template_source_code is not mandatory + // desc->validate is not mandatory + + // desc->get_template_source_code is not mandatory + // desc->validate is not mandatory + // desc->find_function is not mandatory + // desc->make_function is not mandatory + // desc->complete_code is not mandatory + // desc->auto_indent_code is not mandatory + // desc->add_global_constant is not mandatory + // desc->debug_get_error is not mandatory + // desc->debug_get_stack_level_count is not mandatory + // desc->debug_get_stack_level_line is not mandatory + // desc->debug_get_stack_level_function is not mandatory + // desc->debug_get_stack_level_source is not mandatory + // desc->debug_get_stack_level_locals is not mandatory + // desc->debug_get_stack_level_members is not mandatory + // desc->debug_get_globals is not mandatory + // desc->debug_parse_stack_level_expression is not mandatory + // desc->profiling_start is not mandatory + // desc->profiling_stop is not mandatory + // desc->profiling_get_accumulated_data is not mandatory + // desc->profiling_get_frame_data is not mandatory + // desc->frame is not mandatory + + ERR_FAIL_COND_V(!desc->script_desc.init, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.finish, ERR_BUG); + + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.init, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.finish, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.set_prop, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.get_prop, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.call_method, ERR_BUG); + ERR_FAIL_COND_V(!desc->script_desc.instance_desc.notification, ERR_BUG); + // desc->script_desc.instance_desc.refcount_incremented is not mandatory + // desc->script_desc.instance_desc.refcount_decremented is not mandatory + return OK; +} + +void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc) { + Error ret = _check_language_desc(language_desc); + if (ret) { + ERR_FAIL(); + } + PluginScriptLanguage *language = memnew(PluginScriptLanguage(language_desc)); + ScriptServer::register_language(language); + ResourceLoader::add_resource_format_loader(language->get_resource_loader()); + ResourceSaver::add_resource_format_saver(language->get_resource_saver()); + pluginscript_languages.push_back(language); +} + +void register_pluginscript_types() { + ClassDB::register_class<PluginScript>(); +} + +void unregister_pluginscript_types() { + for (List<PluginScriptLanguage *>::Element *e = pluginscript_languages.front(); e; e = e->next()) { + PluginScriptLanguage *language = e->get(); + ScriptServer::unregister_language(language); + memdelete(language); + } +} diff --git a/modules/gdnative/pluginscript/register_types.h b/modules/gdnative/pluginscript/register_types.h new file mode 100644 index 0000000000..70bbb16c62 --- /dev/null +++ b/modules/gdnative/pluginscript/register_types.h @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_pluginscript_types(); +void unregister_pluginscript_types(); diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 059cd197d1..d2a3e29849 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -35,7 +35,9 @@ #include "io/resource_loader.h" #include "io/resource_saver.h" +#include "nativearvr/register_types.h" #include "nativescript/register_types.h" +#include "pluginscript/register_types.h" #include "core/engine.h" #include "core/os/os.h" @@ -127,57 +129,12 @@ static void editor_init_callback() { #endif -godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) { - if (handle == NULL) { - ERR_PRINT("No valid library handle, can't call standard varcall procedure"); - godot_variant ret; - godot_variant_new_nil(&ret); - return ret; - } - - void *library_proc; - Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( - handle, - *(String *)p_procedure, - library_proc, - true); // we roll our own message - if (err != OK) { - ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data()); - godot_variant ret; - godot_variant_new_nil(&ret); - return ret; - } +godot_variant cb_standard_varcall(void *p_procedure_handle, godot_array *p_args) { godot_gdnative_procedure_fn proc; - proc = (godot_gdnative_procedure_fn)library_proc; + proc = (godot_gdnative_procedure_fn)p_procedure_handle; - return proc(NULL, p_args); -} - -void cb_singleton_call( - void *p_handle, - godot_string *p_proc_name, - void *p_data, - int p_num_args, - void **p_args, - void *r_return) { - if (p_handle == NULL) { - ERR_PRINT("No valid library handle, can't call singleton procedure"); - return; - } - - void *singleton_proc; - Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( - p_handle, - *(String *)p_proc_name, - singleton_proc); - - if (err != OK) { - return; - } - - void (*singleton_procedure_ptr)() = (void (*)())singleton_proc; - singleton_procedure_ptr(); + return proc(p_args); } GDNativeCallRegistry *GDNativeCallRegistry::singleton; @@ -200,9 +157,9 @@ void register_gdnative_types() { GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); - GDNativeCallRegistry::singleton->register_native_raw_call_type("gdnative_singleton_call", cb_singleton_call); - + register_nativearvr_types(); register_nativescript_types(); + register_pluginscript_types(); // run singletons @@ -223,13 +180,16 @@ void register_gdnative_types() { continue; } - singleton_gdnatives[i]->call_native_raw( - "gdnative_singleton_call", + void *proc_ptr; + Error err = singleton_gdnatives[i]->get_symbol( "godot_gdnative_singleton", - NULL, - 0, - NULL, - NULL); + proc_ptr); + + if (err != OK) { + ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton_gdnatives[i]->get_library()->get_active_library_path()) + "\" found").utf8().get_data()); + } else { + ((void (*)())proc_ptr)(); + } } } @@ -249,7 +209,9 @@ void unregister_gdnative_types() { } singleton_gdnatives.clear(); + unregister_pluginscript_types(); unregister_nativescript_types(); + unregister_nativearvr_types(); memdelete(GDNativeCallRegistry::singleton); diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 3676570ec1..ed8c27e5d0 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -1,8 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GridMap" inherits="Spatial" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Node for 3D tile-based maps. </brief_description> <description> + GridMap lets you place meshes on a grid interactively. It works both from the editor and can help you create in-game level editors. + GridMaps use a [MeshLibrary] which contain a list of tiles: meshes with materials plus optional collisions and extra elements. + A GridMap contains a collection of cells. Each grid cell refers to a [MeshLibrary] item. All cells in the map have the same dimensions. + A GridMap is split into a sparse collection of octants for efficient rendering and physics processing. Every octant has the same dimensions and can contain several cells. </description> <tutorials> </tutorials> @@ -13,6 +18,7 @@ <return type="void"> </return> <description> + Clear all cells. </description> </method> <method name="get_cell_item" qualifiers="const"> @@ -25,6 +31,7 @@ <argument index="2" name="z" type="int"> </argument> <description> + The [MeshLibrary] item index located at the grid-based X, Y and Z coordinates. If the cell is empty, [INVALID_CELL_ITEM] will be returned. </description> </method> <method name="get_cell_item_orientation" qualifiers="const"> @@ -37,48 +44,63 @@ <argument index="2" name="z" type="int"> </argument> <description> + The orientation of the cell at the grid-based X, Y and Z coordinates. -1 is retuned if the cell is empty. </description> </method> <method name="get_cell_size" qualifiers="const"> <return type="Vector3"> </return> <description> + The dimensions of the grid's cells. </description> </method> <method name="get_center_x" qualifiers="const"> <return type="bool"> </return> <description> + Returns whether or not grid items are centered on the X axis. </description> </method> <method name="get_center_y" qualifiers="const"> <return type="bool"> </return> <description> + Returns whether or not grid items are centered on the Y axis. </description> </method> <method name="get_center_z" qualifiers="const"> <return type="bool"> </return> <description> + Returns whether or not grid items are centered on the Z axis. </description> </method> <method name="get_meshes"> <return type="Array"> </return> <description> + Array of [Transform] and [Mesh] references corresponding to the non empty cells in the grid. The transforms are specified in world space. </description> </method> <method name="get_octant_size" qualifiers="const"> <return type="int"> </return> <description> + The size of each octant measured in number of cells. This applies to all three axis. </description> </method> <method name="get_theme" qualifiers="const"> <return type="MeshLibrary"> </return> <description> + The assigned [MeshLibrary]. + </description> + </method> + <method name="get_used_cells" qualifiers="const"> + <return type="Array"> + </return> + <description> + Array of [Vector3] with the non empty cell coordinates in the grid map. </description> </method> <method name="resource_changed"> @@ -103,6 +125,9 @@ <argument index="4" name="orientation" type="int" default="0"> </argument> <description> + Set the mesh index for the cell referenced by its grid-based X, Y and Z coordinates. + A negative item index will clear the cell. + Optionally, the item's orientation can be passed. </description> </method> <method name="set_cell_size"> @@ -111,6 +136,7 @@ <argument index="0" name="size" type="Vector3"> </argument> <description> + Sets the height, width and depth of the grid's cells. </description> </method> <method name="set_center_x"> @@ -119,6 +145,7 @@ <argument index="0" name="enable" type="bool"> </argument> <description> + Set grid items to be centered on the X axis. By default it is enabled. </description> </method> <method name="set_center_y"> @@ -127,6 +154,7 @@ <argument index="0" name="enable" type="bool"> </argument> <description> + Set grid items to be centered on the Y axis. By default it is enabled. </description> </method> <method name="set_center_z"> @@ -135,6 +163,7 @@ <argument index="0" name="enable" type="bool"> </argument> <description> + Set grid items to be centered on the Z axis. By default it is enabled. </description> </method> <method name="set_clip"> @@ -157,6 +186,7 @@ <argument index="0" name="size" type="int"> </argument> <description> + Sets the size for each octant measured in number of cells. This applies to all three axis. </description> </method> <method name="set_theme"> @@ -165,11 +195,13 @@ <argument index="0" name="theme" type="MeshLibrary"> </argument> <description> + Sets the collection of meshes for the map. </description> </method> </methods> <constants> <constant name="INVALID_CELL_ITEM" value="-1" enum=""> + Invalid cell item that can be used in [method set_cell_item] to clear cells (or represent an empty cell in [method get_cell_item]). </constant> </constants> </class> diff --git a/modules/mobile_vr/mobile_interface.h b/modules/mobile_vr/mobile_interface.h index 6a5e01c163..747377ae46 100644 --- a/modules/mobile_vr/mobile_interface.h +++ b/modules/mobile_vr/mobile_interface.h @@ -90,7 +90,7 @@ private: ///@TODO a few support functions for trackers, most are math related and should likely be moved elsewhere float floor_decimals(float p_value, float p_decimals) { - float power_of_10 = pow(10.0, p_decimals); + float power_of_10 = pow(10.0f, p_decimals); return floor(p_value * power_of_10) / power_of_10; }; diff --git a/modules/mono/config.py b/modules/mono/config.py index 9de199bb5a..0833d30ce1 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -125,12 +125,16 @@ def configure(env): else: env.Append(LIBS=[mono_lib]) - env.Append(LIBS=['m', 'rt', 'dl', 'pthread']) + if sys.platform == "darwin": + env.Append(LIBS=['iconv', 'pthread']) + elif sys.platform == "linux" or sys.platform == "linux2": + env.Append(LIBS=['m', 'rt', 'dl', 'pthread']) + else: if mono_static: raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually') - env.ParseConfig('pkg-config mono-2 --cflags --libs') + env.ParseConfig('pkg-config monosgen-2 --cflags --libs') env.Append(LINKFLAGS='-rdynamic') diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b475782729..ba8c7df9cc 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -41,6 +41,7 @@ #include "editor/csharp_project.h" #include "editor/editor_node.h" #include "editor/godotsharp_editor.h" +#include "utils/string_utils.h" #endif #include "godotsharp_dirs.h" @@ -48,8 +49,9 @@ #include "mono_gd/gd_mono_marshal.h" #include "signal_awaiter_utils.h" -#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->string_names.m_var) +#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var) +#ifdef TOOLS_ENABLED static bool _create_project_solution_if_needed() { String sln_path = GodotSharpDirs::get_project_sln_path(); @@ -64,6 +66,7 @@ static bool _create_project_solution_if_needed() { return true; } +#endif CSharpLanguage *CSharpLanguage::singleton = NULL; @@ -295,20 +298,88 @@ bool CSharpLanguage::has_named_classes() const { return true; } -String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { +static String variant_type_to_managed_name(const String &p_var_type_name) { + + if (p_var_type_name.empty()) + return "object"; + + if (!ClassDB::class_exists(p_var_type_name)) { + Variant::Type var_types[] = { + Variant::BOOL, + Variant::INT, + Variant::REAL, + Variant::STRING, + Variant::VECTOR2, + Variant::RECT2, + Variant::VECTOR3, + Variant::TRANSFORM2D, + Variant::PLANE, + Variant::QUAT, + Variant::RECT3, + Variant::BASIS, + Variant::TRANSFORM, + Variant::COLOR, + Variant::NODE_PATH, + Variant::_RID + }; + + for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) { + if (p_var_type_name == Variant::get_type_name(var_types[i])) + return p_var_type_name; + } + + if (p_var_type_name == "String") + return "string"; // I prefer this one >:[ + + // TODO these will be rewritten later into custom containers + + if (p_var_type_name == "Array") + return "object[]"; + + if (p_var_type_name == "Dictionary") + return "Dictionary<object, object>"; + if (p_var_type_name == "PoolByteArray") + return "byte[]"; + if (p_var_type_name == "PoolIntArray") + return "int[]"; + if (p_var_type_name == "PoolRealArray") + return "float[]"; + if (p_var_type_name == "PoolStringArray") + return "string[]"; + if (p_var_type_name == "PoolVector2Array") + return "Vector2[]"; + if (p_var_type_name == "PoolVector3Array") + return "Vector3[]"; + if (p_var_type_name == "PoolColorArray") + return "Color[]"; + + return "object"; + } + + return p_var_type_name; +} + +String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { +#ifdef TOOLS_ENABLED // FIXME - // Due to Godot's API limitation this just appends the function to the end of the file - // Another limitation is that the parameter types are not specified, so we must use System.Object + // - Due to Godot's API limitation this just appends the function to the end of the file + // - Use fully qualified name if there is ambiguity String s = "private void " + p_name + "("; for (int i = 0; i < p_args.size(); i++) { + const String &arg = p_args[i]; + if (i > 0) s += ", "; - s += "object " + p_args[i]; + + s += variant_type_to_managed_name(arg.get_slice(":", 1)) + " " + escape_csharp_keyword(arg.get_slice(":", 0)); } s += ")\n{\n // Replace with function body\n}\n"; return s; +#else + return String(); +#endif } void CSharpLanguage::frame() { @@ -903,46 +974,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, } else { return Variant(); } - } else if (p_method == CACHED_STRING_NAME(_awaited_signal_callback)) { - // shitty hack.. - // TODO move to its own function, thx - - if (p_argcount < 1) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - return Variant(); - } - - Ref<SignalAwaiterHandle> awaiter = *p_args[p_argcount - 1]; - - if (awaiter.is_null()) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = p_argcount - 1; - r_error.expected = Variant::OBJECT; - return Variant(); - } - - awaiter->set_completed(true); - - int extra_argc = p_argcount - 1; - MonoArray *extra_args = mono_array_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(MonoObject), extra_argc); - - for (int i = 0; i < extra_argc; i++) { - MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]); - mono_array_set(extra_args, MonoObject *, i, boxed); - } - - GDMonoUtils::GodotObject__AwaitedSignalCallback thunk = CACHED_METHOD_THUNK(GodotObject, _AwaitedSignalCallback); - - MonoObject *ex = NULL; - thunk(mono_object, &extra_args, awaiter->get_target(), &ex); - - if (ex) { - mono_print_unhandled_exception(ex); - ERR_FAIL_V(Variant()); - } - - return Variant(); } top = top->get_parent_class(); @@ -1239,8 +1270,11 @@ bool CSharpScript::_update_exports() { for (int i = 0; i < fields.size(); i++) { GDMonoField *field = fields[i]; - if (field->is_static() || field->get_visibility() != GDMono::PUBLIC) + if (field->is_static()) { + if (field->has_attribute(CACHED_CLASS(ExportAttribute))) + ERR_PRINTS("Cannot export field because it is static: " + top->get_full_name() + "." + field->get_name()); continue; + } String name = field->get_name(); StringName cname = name; @@ -1248,17 +1282,39 @@ bool CSharpScript::_update_exports() { if (member_info.has(cname)) continue; - Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type()); + ManagedType field_type = field->get_type(); + Variant::Type type = GDMonoMarshal::managed_to_variant_type(field_type); if (field->has_attribute(CACHED_CLASS(ExportAttribute))) { + // Field has Export attribute MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute)); - // Field has Export attribute - int hint = CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr); - String hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); - int usage = CACHED_FIELD(ExportAttribute, usage)->get_int_value(attr); + PropertyHint hint; + String hint_string; + + if (type == Variant::NIL) { + ERR_PRINTS("Unknown type of exported field: " + top->get_full_name() + "." + field->get_name()); + continue; + } else if (type == Variant::INT && field_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(field_type.type_class->get_raw())) { + type = Variant::INT; + hint = PROPERTY_HINT_ENUM; + + Vector<MonoClassField *> fields = field_type.type_class->get_enum_fields(); + + for (int i = 0; i < fields.size(); i++) { + if (i > 0) + hint_string += ","; + hint_string += mono_field_get_name(fields[i]); + } + } else if (type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(field_type.type_class)) { + hint = PROPERTY_HINT_RESOURCE_TYPE; + hint_string = NATIVE_GDMONOCLASS_NAME(field_type.type_class); + } else { + hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); + hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); + } - PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage)); + PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); member_info[cname] = prop_info; exported_members_cache.push_back(prop_info); @@ -1392,12 +1448,15 @@ bool CSharpScript::can_instance() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - if (_create_project_solution_if_needed()) { - CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), - "Compile", - ProjectSettings::get_singleton()->globalize_path(get_path())); - } else { - ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created."); + + if (get_path().find("::") == -1) { // Ignore if built-in script. Can happen if the file is deleted... + if (_create_project_solution_if_needed()) { + CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), + "Compile", + ProjectSettings::get_singleton()->globalize_path(get_path())); + } else { + ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created."); + } } } #endif @@ -1679,16 +1738,6 @@ void CSharpScript::update_exports() { #ifdef TOOLS_ENABLED _update_exports(); - - if (placeholders.size()) { - Map<StringName, Variant> values; - List<PropertyInfo> propnames; - _update_exports_values(values, propnames); - - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); - } - } #endif } @@ -1915,7 +1964,7 @@ bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const { CSharpLanguage::StringNameCache::StringNameCache() { - _awaited_signal_callback = StaticCString::create("_AwaitedSignalCallback"); + _signal_callback = StaticCString::create("_signal_callback"); _set = StaticCString::create("_set"); _get = StaticCString::create("_get"); _notification = StaticCString::create("_notification"); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 3fcc3bdf04..6b8475fb61 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -225,7 +225,7 @@ class CSharpLanguage : public ScriptLanguage { struct StringNameCache { - StringName _awaited_signal_callback; + StringName _signal_callback; StringName _set; StringName _get; StringName _notification; @@ -242,6 +242,8 @@ public: _FORCE_INLINE_ int get_language_index() { return lang_idx; } void set_language_index(int p_idx); + _FORCE_INLINE_ const StringNameCache &get_string_names() { return string_names; } + _FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; } bool debug_break(const String &p_error, bool p_allow_continue = true); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 704910c5b9..95e75f9103 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -108,36 +108,6 @@ const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in bool BindingsGenerator::verbose_output = false; -static bool is_csharp_keyword(const String &p_name) { - - // Reserved keywords - - return p_name == "abstract" || p_name == "as" || p_name == "base" || p_name == "bool" || - p_name == "break" || p_name == "byte" || p_name == "case" || p_name == "catch" || - p_name == "char" || p_name == "checked" || p_name == "class" || p_name == "const" || - p_name == "continue" || p_name == "decimal" || p_name == "default" || p_name == "delegate" || - p_name == "do" || p_name == "double" || p_name == "else" || p_name == "enum" || - p_name == "event" || p_name == "explicit" || p_name == "extern" || p_name == "false" || - p_name == "finally" || p_name == "fixed" || p_name == "float" || p_name == "for" || - p_name == "forech" || p_name == "goto" || p_name == "if" || p_name == "implicit" || - p_name == "in" || p_name == "int" || p_name == "interface" || p_name == "internal" || - p_name == "is" || p_name == "lock" || p_name == "long" || p_name == "namespace" || - p_name == "new" || p_name == "null" || p_name == "object" || p_name == "operator" || - p_name == "out" || p_name == "override" || p_name == "params" || p_name == "private" || - p_name == "protected" || p_name == "public" || p_name == "readonly" || p_name == "ref" || - p_name == "return" || p_name == "sbyte" || p_name == "sealed" || p_name == "short" || - p_name == "sizeof" || p_name == "stackalloc" || p_name == "static" || p_name == "string" || - p_name == "struct" || p_name == "switch" || p_name == "this" || p_name == "throw" || - p_name == "true" || p_name == "try" || p_name == "typeof" || p_name == "uint" || p_name == "ulong" || - p_name == "unchecked" || p_name == "unsafe" || p_name == "ushort" || p_name == "using" || - p_name == "virtual" || p_name == "volatile" || p_name == "void" || p_name == "while"; -} - -inline static String escape_csharp_keyword(const String &p_name) { - - return is_csharp_keyword(p_name) ? "@" + p_name : p_name; -} - static String snake_to_pascal_case(const String &p_identifier) { String ret; @@ -904,10 +874,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str return ERR_BUG; } - cs_file.push_back(MEMBER_BEGIN "private void _AwaitedSignalCallback("); - cs_file.push_back(array_itype->get().cs_type); - cs_file.push_back(" args, SignalAwaiter awaiter)\n" OPEN_BLOCK_L2 "awaiter.SignalCallback(args);\n" CLOSE_BLOCK_L2); - Map<String, TypeInterface>::Element *object_itype = obj_types.find("Object"); if (!object_itype) { diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs index af3f603d6d..a4e7d447dd 100644 --- a/modules/mono/glue/cs_files/ExportAttribute.cs +++ b/modules/mono/glue/cs_files/ExportAttribute.cs @@ -7,13 +7,11 @@ namespace Godot { private int hint; private string hint_string; - private int usage; - public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "", int usage = GD.PROPERTY_USAGE_DEFAULT) + public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "") { this.hint = hint; this.hint_string = hint_string; - this.usage = usage; } } } diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 0a2010e99d..6bcf0e2355 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -33,6 +33,7 @@ #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" +#include "os/dir_access.h" #include "project_settings.h" #include "version.h" #endif @@ -60,12 +61,20 @@ String _get_mono_user_dir() { } else { String settings_path; - if (OS::get_singleton()->has_environment("APPDATA")) { - String app_data = OS::get_singleton()->get_environment("APPDATA").replace("\\", "/"); - settings_path = app_data.plus_file(String(_MKSTR(VERSION_SHORT_NAME)).capitalize()); - } else if (OS::get_singleton()->has_environment("HOME")) { - String home = OS::get_singleton()->get_environment("HOME"); - settings_path = home.plus_file("." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower()); + String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir(); + DirAccessRef d = DirAccess::create_for_path(exe_dir); + + if (d->file_exists("._sc_") || d->file_exists("_sc_")) { + // contain yourself + settings_path = exe_dir.plus_file("editor_data"); + } else { + if (OS::get_singleton()->has_environment("APPDATA")) { + String app_data = OS::get_singleton()->get_environment("APPDATA").replace("\\", "/"); + settings_path = app_data.plus_file(String(_MKSTR(VERSION_SHORT_NAME)).capitalize()); + } else if (OS::get_singleton()->has_environment("HOME")) { + String home = OS::get_singleton()->get_environment("HOME"); + settings_path = home.plus_file("." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower()); + } } return settings_path.plus_file("mono"); diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 0134ace5d7..77ba0ee90e 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -43,6 +43,14 @@ bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { return mono_class_is_assignable_from(mono_class, p_from->mono_class); } +String GDMonoClass::get_full_name() const { + + String res = namespace_name; + if (res.length()) + res += "."; + return res + class_name; +} + GDMonoClass *GDMonoClass::get_parent_class() { if (assembly) { @@ -56,6 +64,30 @@ GDMonoClass *GDMonoClass::get_parent_class() { return NULL; } +#ifdef TOOLS_ENABLED +Vector<MonoClassField *> GDMonoClass::get_enum_fields() { + + bool class_is_enum = mono_class_is_enum(mono_class); + ERR_FAIL_COND_V(!class_is_enum, Vector<MonoClassField *>()); + + Vector<MonoClassField *> enum_fields; + + void *iter = NULL; + MonoClassField *raw_field = NULL; + while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) { + uint32_t field_flags = mono_field_get_flags(raw_field); + + // Enums have an instance field named value__ which holds the value of the enum. + // Enum constants are static, so we will use this to ignore the value__ field. + if (field_flags & MONO_FIELD_ATTR_PUBLIC && field_flags & MONO_FIELD_ATTR_STATIC) { + enum_fields.push_back(raw_field); + } + } + + return enum_fields; +} +#endif + bool GDMonoClass::has_method(const StringName &p_name) { return get_method(p_name) != NULL; diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 1e72553879..ef1ca425a7 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -98,8 +98,14 @@ public: _FORCE_INLINE_ MonoClass *get_raw() const { return mono_class; } _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; } + String get_full_name() const; + GDMonoClass *get_parent_class(); +#ifdef TOOLS_ENABLED + Vector<MonoClassField *> get_enum_fields(); +#endif + bool has_method(const StringName &p_name); bool has_attribute(GDMonoClass *p_attr_class); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index c2d8eeaa32..81315ee87a 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -51,6 +51,7 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) { { \ m_type val = p_value.operator m_type(); \ mono_field_set_value(p_object, mono_field, &val); \ + break; \ } #define SET_FROM_ARRAY_AND_BREAK(m_type) \ @@ -137,6 +138,9 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) { if (tclass == CACHED_CLASS(Plane)) SET_FROM_STRUCT_AND_BREAK(Plane); + if (mono_class_is_enum(tclass->get_raw())) + SET_FROM_PRIMITIVE(signed int); + ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name()); ERR_FAIL(); } break; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 9a6c8f0cd6..77a1ef3cb0 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -112,6 +112,9 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { if (tclass == CACHED_CLASS(Plane)) return Variant::PLANE; + + if (mono_class_is_enum(tclass->get_raw())) + return Variant::INT; } break; case MONO_TYPE_ARRAY: @@ -165,9 +168,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { return Variant::DICTIONARY; } } break; + + default: { + } break; } - // No error, the caller will decide what to do in this case + // Unknown return Variant::NIL; } @@ -299,6 +305,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty if (tclass == CACHED_CLASS(Plane)) RETURN_BOXED_STRUCT(Plane, p_var); + + if (mono_class_is_enum(tclass->get_raw())) { + int val = p_var->operator signed int(); + return BOX_ENUM(tclass->get_raw(), val); + } } break; case MONO_TYPE_ARRAY: @@ -515,6 +526,9 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) { if (tclass == CACHED_CLASS(Plane)) RETURN_UNBOXED_STRUCT(Plane, p_obj); + + if (mono_class_is_enum(tclass->get_raw())) + return unbox<int32_t>(p_obj); } break; case MONO_TYPE_ARRAY: diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 38dd22357d..9f403b787f 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -53,6 +53,7 @@ T unbox(MonoObject *p_obj) { #define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x) #define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x) #define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x) +#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x) Variant::Type managed_to_variant_type(const ManagedType &p_type); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 5deca8e64d..53e45002c4 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -86,6 +86,7 @@ void MonoCache::clear_members() { class_NodePath = NULL; class_RID = NULL; class_GodotObject = NULL; + class_GodotReference = NULL; class_Node = NULL; class_Control = NULL; class_Spatial = NULL; @@ -95,7 +96,6 @@ void MonoCache::clear_members() { class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; field_ExportAttribute_hint_string = NULL; - field_ExportAttribute_usage = NULL; class_ToolAttribute = NULL; class_RemoteAttribute = NULL; class_SyncAttribute = NULL; @@ -111,7 +111,7 @@ void MonoCache::clear_members() { methodthunk_MarshalUtils_DictionaryToArrays = NULL; methodthunk_MarshalUtils_ArraysToDictionary = NULL; - methodthunk_GodotObject__AwaitedSignalCallback = NULL; + methodthunk_SignalAwaiter_SignalCallback = NULL; methodthunk_SignalAwaiter_FailureCallback = NULL; methodthunk_GodotTaskScheduler_Activate = NULL; @@ -153,6 +153,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath)); CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); + CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference)); CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); @@ -163,7 +164,6 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string")); - CACHE_FIELD_AND_CHECK(ExportAttribute, usage, CACHED_CLASS(ExportAttribute)->get_field("usage")); CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); @@ -178,7 +178,7 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk()); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk()); - CACHE_METHOD_THUNK_AND_CHECK(GodotObject, _AwaitedSignalCallback, (GodotObject__AwaitedSignalCallback)CACHED_CLASS(GodotObject)->get_method("_AwaitedSignalCallback", 2)->get_thunk()); + CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk()); CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk()); CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk()); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index f97f048aa9..e3af57e78a 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -42,7 +42,7 @@ namespace GDMonoUtils { typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **); typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **); -typedef MonoObject *(*GodotObject__AwaitedSignalCallback)(MonoObject *, MonoArray **, MonoObject *, MonoObject **); +typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray **, MonoObject **); typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **); typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **); @@ -88,6 +88,7 @@ struct MonoCache { GDMonoClass *class_NodePath; GDMonoClass *class_RID; GDMonoClass *class_GodotObject; + GDMonoClass *class_GodotReference; GDMonoClass *class_Node; GDMonoClass *class_Control; GDMonoClass *class_Spatial; @@ -97,7 +98,6 @@ struct MonoCache { GDMonoClass *class_ExportAttribute; GDMonoField *field_ExportAttribute_hint; GDMonoField *field_ExportAttribute_hint_string; - GDMonoField *field_ExportAttribute_usage; GDMonoClass *class_ToolAttribute; GDMonoClass *class_RemoteAttribute; GDMonoClass *class_SyncAttribute; @@ -113,7 +113,7 @@ struct MonoCache { MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays; MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary; - GodotObject__AwaitedSignalCallback methodthunk_GodotObject__AwaitedSignalCallback; + SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback; SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback; GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate; @@ -164,7 +164,7 @@ String get_exception_name_and_message(MonoObject *p_ex); } // GDMonoUtils -#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field("nativeName")->get_value(NULL))) +#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL))) #define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class) #define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_raw()) diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 012dd119b1..7e99df29a1 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -29,6 +29,9 @@ /*************************************************************************/ #include "signal_awaiter_utils.h" +#include "csharp_script.h" +#include "mono_gd/gd_mono_class.h" +#include "mono_gd/gd_mono_marshal.h" #include "mono_gd/gd_mono_utils.h" namespace SignalAwaiterUtils { @@ -40,13 +43,20 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p uint32_t awaiter_handle = MonoGCHandle::make_strong_handle(p_awaiter); Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(awaiter_handle)); +#ifdef DEBUG_ENABLED + sa_con->set_connection_target(p_target); +#endif + Vector<Variant> binds; binds.push_back(sa_con); - Error err = p_source->connect(p_signal, p_target, "_AwaitedSignalCallback", binds, Object::CONNECT_ONESHOT); + + Error err = p_source->connect(p_signal, sa_con.ptr(), + CSharpLanguage::get_singleton()->get_string_names()._signal_callback, + binds, Object::CONNECT_ONESHOT); if (err != OK) { - // set it as completed to prevent it from calling the failure callback when deleted - // the awaiter will be aware of the failure by checking the returned error + // Set it as completed to prevent it from calling the failure callback when released. + // The awaiter will be aware of the failure by checking the returned error. sa_con->set_completed(true); } @@ -54,11 +64,68 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p } } -SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_handle) - : MonoGCHandle(p_handle) { +Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + +#ifdef DEBUG_ENABLED + if (conn_target_id && !ObjectDB::get_instance(conn_target_id)) { + ERR_EXPLAIN("Resumed after await, but class instance is gone"); + ERR_FAIL_V(Variant()); + } +#endif + + if (p_argcount < 1) { + r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 1; + return Variant(); + } + + Ref<SignalAwaiterHandle> self = *p_args[p_argcount - 1]; + + if (self.is_null()) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = p_argcount - 1; + r_error.expected = Variant::OBJECT; + return Variant(); + } + + set_completed(true); + + int signal_argc = p_argcount - 1; + MonoArray *signal_args = mono_array_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(MonoObject), signal_argc); + + for (int i = 0; i < signal_argc; i++) { + MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]); + mono_array_set(signal_args, MonoObject *, i, boxed); + } + + GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback); + + MonoObject *ex = NULL; + thunk(get_target(), &signal_args, &ex); + + if (ex) { + mono_print_unhandled_exception(ex); + ERR_FAIL_V(Variant()); + } + + return Variant(); +} + +void SignalAwaiterHandle::_bind_methods() { + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &SignalAwaiterHandle::_signal_callback, MethodInfo("_signal_callback")); +} + +SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_managed_handle) + : MonoGCHandle(p_managed_handle) { + +#ifdef DEBUG_ENABLED + conn_target_id = 0; +#endif } SignalAwaiterHandle::~SignalAwaiterHandle() { + if (!completed) { GDMonoUtils::SignalAwaiter_FailureCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback); diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index 422ed4754f..0d615b5826 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -40,13 +40,30 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p class SignalAwaiterHandle : public MonoGCHandle { + GDCLASS(SignalAwaiterHandle, MonoGCHandle) + bool completed; +#ifdef DEBUG_ENABLED + ObjectID conn_target_id; +#endif + + Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + +protected: + static void _bind_methods(); + public: _FORCE_INLINE_ bool is_completed() { return completed; } _FORCE_INLINE_ void set_completed(bool p_completed) { completed = p_completed; } - SignalAwaiterHandle(uint32_t p_handle); +#ifdef DEBUG_ENABLED + _FORCE_INLINE_ void set_connection_target(Object *p_target) { + conn_target_id = p_target->get_instance_id(); + } +#endif + + SignalAwaiterHandle(uint32_t p_managed_handle); ~SignalAwaiterHandle(); }; diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index de1a60dbd1..f26663ea11 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -126,3 +126,32 @@ String sformat(const String &p_text, const Variant &p1, const Variant &p2, const return new_string; } + +bool is_csharp_keyword(const String &p_name) { + + // Reserved keywords + + return p_name == "abstract" || p_name == "as" || p_name == "base" || p_name == "bool" || + p_name == "break" || p_name == "byte" || p_name == "case" || p_name == "catch" || + p_name == "char" || p_name == "checked" || p_name == "class" || p_name == "const" || + p_name == "continue" || p_name == "decimal" || p_name == "default" || p_name == "delegate" || + p_name == "do" || p_name == "double" || p_name == "else" || p_name == "enum" || + p_name == "event" || p_name == "explicit" || p_name == "extern" || p_name == "false" || + p_name == "finally" || p_name == "fixed" || p_name == "float" || p_name == "for" || + p_name == "forech" || p_name == "goto" || p_name == "if" || p_name == "implicit" || + p_name == "in" || p_name == "int" || p_name == "interface" || p_name == "internal" || + p_name == "is" || p_name == "lock" || p_name == "long" || p_name == "namespace" || + p_name == "new" || p_name == "null" || p_name == "object" || p_name == "operator" || + p_name == "out" || p_name == "override" || p_name == "params" || p_name == "private" || + p_name == "protected" || p_name == "public" || p_name == "readonly" || p_name == "ref" || + p_name == "return" || p_name == "sbyte" || p_name == "sealed" || p_name == "short" || + p_name == "sizeof" || p_name == "stackalloc" || p_name == "static" || p_name == "string" || + p_name == "struct" || p_name == "switch" || p_name == "this" || p_name == "throw" || + p_name == "true" || p_name == "try" || p_name == "typeof" || p_name == "uint" || p_name == "ulong" || + p_name == "unchecked" || p_name == "unsafe" || p_name == "ushort" || p_name == "using" || + p_name == "virtual" || p_name == "volatile" || p_name == "void" || p_name == "while"; +} + +String escape_csharp_keyword(const String &p_name) { + return is_csharp_keyword(p_name) ? "@" + p_name : p_name; +} diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h index 2f2c3c2d89..a0d66ebdc3 100644 --- a/modules/mono/utils/string_utils.h +++ b/modules/mono/utils/string_utils.h @@ -35,4 +35,10 @@ String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant()); +#ifdef TOOLS_ENABLED +bool is_csharp_keyword(const String &p_name); + +String escape_csharp_keyword(const String &p_name); +#endif + #endif // STRING_FORMAT_H diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp index c19bdc4214..6d1d5485f3 100644 --- a/modules/openssl/stream_peer_openssl.cpp +++ b/modules/openssl/stream_peer_openssl.cpp @@ -30,7 +30,7 @@ #include "stream_peer_openssl.h" // Compatibility with OpenSSL 1.1.0. -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) #define BIO_set_num(b, n) #else #define BIO_set_num(b, n) ((b)->num = (n)) @@ -269,7 +269,7 @@ int StreamPeerOpenSSL::_bio_puts(BIO *b, const char *str) { return _bio_write(b, str, strlen(str)); } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) BIO_METHOD *StreamPeerOpenSSL::_bio_method = NULL; BIO_METHOD *StreamPeerOpenSSL::_get_bio_method() { @@ -568,7 +568,7 @@ void StreamPeerOpenSSL::initialize_ssl() { load_certs_func = _load_certs; _create = _create_func; -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use #endif SSL_library_init(); // Initialize OpenSSL's SSL libraries diff --git a/modules/openssl/stream_peer_openssl.h b/modules/openssl/stream_peer_openssl.h index 535114058d..ad09564447 100644 --- a/modules/openssl/stream_peer_openssl.h +++ b/modules/openssl/stream_peer_openssl.h @@ -53,7 +53,7 @@ private: static int _bio_gets(BIO *b, char *buf, int len); static int _bio_puts(BIO *b, const char *str); -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) static BIO_METHOD *_bio_method; #else static BIO_METHOD _bio_method; diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index 27ea310780..5c252bda86 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -129,7 +129,6 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { Ref<AudioStreamPlaybackOGGVorbis> ovs; - printf("instance at %p, data %p\n", this, data); ERR_FAIL_COND_V(data == NULL, ovs); @@ -208,8 +207,6 @@ void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t> &p_data) { break; } } - - printf("create at %p, data %p\n", this, data); } PoolVector<uint8_t> AudioStreamOGGVorbis::get_data() const { diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 972be5f5a4..4b294325dc 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -65,6 +65,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "decimals", "stepify", "lerp", + "inverse_lerp", + "range_lerp", "dectime", "randomize", "randi", @@ -194,9 +196,12 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case COLORN: return 2; case MATH_LERP: + case MATH_INVERSE_LERP: case MATH_DECTIME: case LOGIC_CLAMP: return 3; + case MATH_RANGE_LERP: + return 5; case FUNC_MAX: { } } @@ -297,7 +302,26 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::REAL, "to"); else return PropertyInfo(Variant::REAL, "weight"); - + } break; + case MATH_INVERSE_LERP: { + if (p_idx == 0) + return PropertyInfo(Variant::REAL, "from"); + else if (p_idx == 1) + return PropertyInfo(Variant::REAL, "to"); + else + return PropertyInfo(Variant::REAL, "value"); + } break; + case MATH_RANGE_LERP: { + if (p_idx == 0) + return PropertyInfo(Variant::REAL, "value"); + else if (p_idx == 1) + return PropertyInfo(Variant::REAL, "istart"); + else if (p_idx == 2) + return PropertyInfo(Variant::REAL, "istop"); + else if (p_idx == 3) + return PropertyInfo(Variant::REAL, "ostart"); + else + return PropertyInfo(Variant::REAL, "ostop"); } break; case MATH_DECTIME: { if (p_idx == 0) @@ -495,6 +519,8 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case MATH_STEPIFY: case MATH_LERP: + case MATH_INVERSE_LERP: + case MATH_RANGE_LERP: case MATH_DECTIME: { t = Variant::REAL; @@ -795,6 +821,22 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(2); *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; + case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_RANGE_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + VALIDATE_ARG_NUM(3); + VALIDATE_ARG_NUM(4); + *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); + } break; case VisualScriptBuiltinFunc::MATH_DECTIME: { VALIDATE_ARG_NUM(0); @@ -1203,6 +1245,8 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_DECIMALS); BIND_ENUM_CONSTANT(MATH_STEPIFY); BIND_ENUM_CONSTANT(MATH_LERP); + BIND_ENUM_CONSTANT(MATH_INVERSE_LERP); + BIND_ENUM_CONSTANT(MATH_RANGE_LERP); BIND_ENUM_CONSTANT(MATH_DECTIME); BIND_ENUM_CONSTANT(MATH_RANDOMIZE); BIND_ENUM_CONSTANT(MATH_RAND); @@ -1236,6 +1280,11 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_MAX); } +VisualScriptBuiltinFunc::VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func) { + + this->func = func; +} + VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() { func = MATH_SIN; @@ -1244,9 +1293,7 @@ VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() { template <VisualScriptBuiltinFunc::BuiltinFunc func> static Ref<VisualScriptNode> create_builtin_func_node(const String &p_name) { - Ref<VisualScriptBuiltinFunc> node; - node.instance(); - node->set_func(func); + Ref<VisualScriptBuiltinFunc> node = memnew(VisualScriptBuiltinFunc(func)); return node; } @@ -1282,6 +1329,8 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 97ab307039..5758d23e8f 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -64,6 +64,8 @@ public: MATH_DECIMALS, MATH_STEPIFY, MATH_LERP, + MATH_INVERSE_LERP, + MATH_RANGE_LERP, MATH_DECTIME, MATH_RANDOMIZE, MATH_RAND, @@ -130,6 +132,7 @@ public: virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); + VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func); VisualScriptBuiltinFunc(); }; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 47ef0182dc..03015df844 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -809,7 +809,7 @@ void VisualScriptEditor::_update_members() { ti->set_text(0, E->get()); Variant var = script->get_variable_default_value(E->get()); - ti->set_suffix(0, "=" + String(var)); + ti->set_suffix(0, "= " + String(var)); ti->set_icon(0, type_icons[script->get_variable_info(E->get()).type]); ti->set_selectable(0, true); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 5a34fc3cd9..d3cd839cf3 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -532,6 +532,7 @@ String VisualScriptOperator::get_text() const { L"A or B", //OP_OR, L"A xor B", //OP_XOR, L"not A", //OP_NOT, + L"A in B", //OP_IN, }; return op_names[op]; |