diff options
45 files changed, 2242 insertions, 143 deletions
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 4653ade294..2feb068ecb 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -855,15 +855,19 @@ void ScriptDebuggerRemote::_print_handler(void *p_this, const String &p_string) } sdr->char_count += allowed_chars; - - if (sdr->char_count >= sdr->max_cps) { - s += "\n[output overflow, print less text!]\n"; - } + bool overflowed = sdr->char_count >= sdr->max_cps; sdr->mutex->lock(); if (!sdr->locking && sdr->tcp_client->is_connected_to_host()) { + if (overflowed) + s += "[...]"; + sdr->output_strings.push_back(s); + + if (overflowed) { + sdr->output_strings.push_back("[output overflow, print less text!]"); + } } sdr->mutex->unlock(); } diff --git a/doc/classes/Particles2D.xml b/doc/classes/Particles2D.xml index b2c63ea0c3..cfc907b727 100644 --- a/doc/classes/Particles2D.xml +++ b/doc/classes/Particles2D.xml @@ -286,7 +286,7 @@ </methods> <members> <member name="amount" type="int" setter="set_amount" getter="get_amount"> - Number of particles to emit. + Number of particles emitted in one emission cycle. </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="Particles2D.DrawOrder"> Particle draw order. Uses [code]DRAW_ORDER_*[/code] values. Default value: [code]DRAW_ORDER_INDEX[/code]. @@ -295,7 +295,7 @@ If [code]true[/code] particles are being emitted. Default value: [code]true[/code]. </member> <member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio"> - Time ratio between each emission. If [code]0[/code] particles are emitted continuously. If [code]1[/code] all particles are emitted simultaneously. Default value: [code]0[/code]. + How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins. Default value: [code]0[/code]. </member> <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps"> </member> @@ -313,18 +313,19 @@ <member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map"> </member> <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot"> - If [code]true[/code] only [code]amount[/code] particles will be emitted. Default value: [code]false[/code]. + If [code]true[/code] only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end. Default value: [code]false[/code]. </member> <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time"> + Particle system starts as if it had already run for this many seconds. </member> <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material"> [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial]. </member> <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio"> - Emission randomness ratio. Default value: [code]0[/code]. + Emission lifetime randomness ratio. Default value: [code]0[/code]. </member> <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale"> - Speed scaling ratio. Default value: [code]1[/code]. + Particle system's running speed scaling ratio. Default value: [code]1[/code]. </member> <member name="texture" type="Texture" setter="set_texture" getter="get_texture"> Particle texture. If [code]null[/code] particles will be squares. @@ -333,6 +334,7 @@ Number of vertical frames in [code]texture[/code]. </member> <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect"> + Editor visibility helper. </member> </members> <constants> diff --git a/doc/classes/VisualScriptLocalVar.xml b/doc/classes/VisualScriptLocalVar.xml index bca19d06d5..3101b3e34b 100644 --- a/doc/classes/VisualScriptLocalVar.xml +++ b/doc/classes/VisualScriptLocalVar.xml @@ -4,7 +4,7 @@ Gets a local variable's value. </brief_description> <description> - This node returns a local variable's value. "Var Name" must be supplied, with an optional type. + Returns a local variable's value. "Var Name" must be supplied, with an optional type. [b]Input Ports:[/b] none [b]Output Ports:[/b] diff --git a/doc/classes/VisualScriptLocalVarSet.xml b/doc/classes/VisualScriptLocalVarSet.xml index 67a5efa33e..e039a7204e 100644 --- a/doc/classes/VisualScriptLocalVarSet.xml +++ b/doc/classes/VisualScriptLocalVarSet.xml @@ -4,7 +4,7 @@ Changes a local variable's value. </brief_description> <description> - The node changes a local variable's value to the given input. The new value is also provided on an output Data port. + Changes a local variable's value to the given input. The new value is also provided on an output Data port. [b]Input Ports:[/b] - Sequence - Data (variant): [code]set[/code] diff --git a/doc/classes/VisualScriptPreload.xml b/doc/classes/VisualScriptPreload.xml index b68bf5546b..b683439751 100644 --- a/doc/classes/VisualScriptPreload.xml +++ b/doc/classes/VisualScriptPreload.xml @@ -1,8 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Creates a new [Resource] or loads one from the filesystem. </brief_description> <description> + Creates a new [Resource] or loads one from the filesystem. + [b]Input Ports:[/b] + none + [b]Output Ports:[/b] + - Data (object): [code]res[/code] </description> <tutorials> </tutorials> @@ -26,6 +32,7 @@ </methods> <members> <member name="resource" type="Resource" setter="set_preload" getter="get_preload"> + The [Resource] to load. </member> </members> <constants> diff --git a/doc/classes/VisualScriptSelect.xml b/doc/classes/VisualScriptSelect.xml index 855da76e6c..f265c57645 100644 --- a/doc/classes/VisualScriptSelect.xml +++ b/doc/classes/VisualScriptSelect.xml @@ -1,8 +1,16 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Chooses between two input values. </brief_description> <description> + Chooses between two input values based on a Boolean condition. + [b]Input Ports:[/b] + - Data (boolean): [code]cond[/code] + - Data (variant): [code]a[/code] + - Data (variant): [code]b[/code] + [b]Output Ports:[/b] + - Data (variant): [code]out[/code] </description> <tutorials> </tutorials> @@ -26,6 +34,7 @@ </methods> <members> <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type"> + The input variables' type. </member> </members> <constants> diff --git a/doc/classes/VisualScriptVariableGet.xml b/doc/classes/VisualScriptVariableGet.xml index 8411933756..5b45dd0cc4 100644 --- a/doc/classes/VisualScriptVariableGet.xml +++ b/doc/classes/VisualScriptVariableGet.xml @@ -1,8 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Gets a variable's value. </brief_description> <description> + Returns a variable's value. "Var Name" must be supplied, with an optional type. + [b]Input Ports:[/b] + none + [b]Output Ports:[/b] + - Data (variant): [code]value[/code] </description> <tutorials> </tutorials> @@ -26,6 +32,7 @@ </methods> <members> <member name="var_name" type="String" setter="set_variable" getter="get_variable"> + The variable's name. </member> </members> <constants> diff --git a/doc/classes/VisualScriptVariableSet.xml b/doc/classes/VisualScriptVariableSet.xml index fbe0f8e275..51f85f6881 100644 --- a/doc/classes/VisualScriptVariableSet.xml +++ b/doc/classes/VisualScriptVariableSet.xml @@ -1,8 +1,15 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Changes a variable's value. </brief_description> <description> + Changes a variable's value to the given input. + [b]Input Ports:[/b] + - Sequence + - Data (variant): [code]set[/code] + [b]Output Ports:[/b] + - Sequence </description> <tutorials> </tutorials> @@ -26,6 +33,7 @@ </methods> <members> <member name="var_name" type="String" setter="set_variable" getter="get_variable"> + The variable's name. </member> </members> <constants> diff --git a/doc/classes/VisualScriptWhile.xml b/doc/classes/VisualScriptWhile.xml index b49678582e..60bf161339 100644 --- a/doc/classes/VisualScriptWhile.xml +++ b/doc/classes/VisualScriptWhile.xml @@ -1,8 +1,16 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Conditional loop. </brief_description> <description> + Loops while a condition is [code]true[/code]. Execution continues out the [code]exit[/code] Sequence port when the loop terminates. + [b]Input Ports:[/b] + - Sequence: [code]while(cond)[/code] + - Data (bool): [code]cond[/code] + [b]Output Ports:[/b] + - Sequence: [code]repeat[/code] + - Sequence: [code]exit[/code] </description> <tutorials> </tutorials> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 6117c91a6a..39f027a5aa 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2569,8 +2569,8 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform ubo_data.light_direction_attenuation[3] = 1.0; ubo_data.light_params[0] = 0; - ubo_data.light_params[1] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - ubo_data.light_params[2] = 0; + ubo_data.light_params[1] = 0; + ubo_data.light_params[2] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; ubo_data.light_params[3] = 0; Color shadow_color = li->light_ptr->shadow_color.to_linear(); diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme index 3f0df5c437..b6beeb012f 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme @@ -23,7 +23,7 @@ </BuildActionEntries> </BuildAction> <TestAction - buildConfiguration = "Development" + buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -42,7 +42,7 @@ </AdditionalOptions> </TestAction> <LaunchAction - buildConfiguration = "Development" + buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" @@ -67,7 +67,7 @@ </AdditionalOptions> </LaunchAction> <ProfileAction - buildConfiguration = "Development" + buildConfiguration = "Debug" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" @@ -84,10 +84,10 @@ </BuildableProductRunnable> </ProfileAction> <AnalyzeAction - buildConfiguration = "Development"> + buildConfiguration = "Debug"> </AnalyzeAction> <ArchiveAction - buildConfiguration = "Development" + buildConfiguration = "Debug" revealArchiveInOrganizer = "YES"> </ArchiveAction> </Scheme> diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index ba4163aab7..a6ae143947 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -13,6 +13,7 @@ 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 + ' ' @@ -26,6 +27,7 @@ def _build_gdnative_api_struct_header(api): '#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)', '', @@ -98,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/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/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/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 52379560b3..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" @@ -1011,10 +1011,13 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { void *proc_ptr; - gdn->get_symbol(_init_call_name, proc_ptr); - - ((void (*)(godot_string *))proc_ptr)((godot_string *)&lib_path); + Error err = gdn->get_symbol(_init_call_name, proc_ptr); + 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. } @@ -1138,9 +1141,12 @@ void NativeReloadNode::_notification(int p_what) { // here the library registers all the classes and stuff. void *proc_ptr; - L->get()->get_symbol("godot_nativescript_init", proc_ptr); - - ((void (*)(void *))proc_ptr)((void *)&L->key()); + 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/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..2198e66ae4 --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -0,0 +1,432 @@ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include <stdlib.h> +// 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..051ef46bae --- /dev/null +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* 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 + +#include <iostream> +// 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 8e5f58524b..d2a3e29849 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -37,6 +37,7 @@ #include "nativearvr/register_types.h" #include "nativescript/register_types.h" +#include "pluginscript/register_types.h" #include "core/engine.h" #include "core/os/os.h" @@ -158,6 +159,7 @@ void register_gdnative_types() { register_nativearvr_types(); register_nativescript_types(); + register_pluginscript_types(); // run singletons @@ -207,8 +209,9 @@ void unregister_gdnative_types() { } singleton_gdnatives.clear(); - unregister_nativearvr_types(); + unregister_pluginscript_types(); unregister_nativescript_types(); + unregister_nativearvr_types(); memdelete(GDNativeCallRegistry::singleton); diff --git a/modules/mono/config.py b/modules/mono/config.py index 9de199bb5a..13b9a4b1e6 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -130,7 +130,7 @@ def configure(env): 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..69895e58e2 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,7 +49,7 @@ #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) static bool _create_project_solution_if_needed() { @@ -295,20 +296,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 +972,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(); @@ -1392,12 +1421,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 @@ -1915,7 +1947,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/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 5deca8e64d..d23fcf8a67 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -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; @@ -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..bbda3a01d4 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 **); @@ -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; diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 012dd119b1..99bcc72b41 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,66 @@ 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) { + + conn_target_id = 0; } 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/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/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 5216dc5d6a..0507ef19d6 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -592,7 +592,15 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return err; #ifdef OSX_ENABLED - ep.step("Making .xcarchive", 2); + ep.step("Code-signing dylibs", 2); + DirAccess *dylibs_dir = DirAccess::open(dest_dir + "dylibs"); + ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); + CodesignData codesign_data(p_preset, p_debug); + err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); + memdelete(dylibs_dir); + ERR_FAIL_COND_V(err, err); + + ep.step("Making .xcarchive", 3); String archive_path = p_path.get_basename() + ".xcarchive"; List<String> archive_args; archive_args.push_back("-project"); @@ -611,14 +619,6 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p err = OS::get_singleton()->execute("xcodebuild", archive_args, true); ERR_FAIL_COND_V(err, err); - ep.step("Code-signing dylibs", 3); - DirAccess *dylibs_dir = DirAccess::open(archive_path + "/Products/Applications/" + binary_name + ".app/dylibs"); - ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); - CodesignData codesign_data(p_preset, p_debug); - err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); - memdelete(dylibs_dir); - ERR_FAIL_COND_V(err, err); - ep.step("Making .ipa", 4); List<String> export_args; export_args.push_back("-exportArchive"); diff --git a/platform/server/detect.py b/platform/server/detect.py index 04b38f280d..ffec2af933 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -12,6 +12,9 @@ def get_name(): def can_build(): + # Doesn't build against Godot 3.0 for now, disable to avoid confusing users + return False + if (os.name != "posix" or sys.platform == "darwin"): return False diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index b2a11deea1..8fee6050a0 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2586,6 +2586,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else if (tk.type == TK_BRACKET_OPEN) { Node *index = _parse_and_reduce_expression(p_block, p_builtin_types); + if (!index) + return NULL; if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) { _set_error("Only integer datatypes are allowed for indexing"); |