diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/etc/config.py | 6 | ||||
| -rw-r--r-- | modules/etc/image_etc.cpp | 4 | ||||
| -rw-r--r-- | modules/gdnative/gdnative.cpp | 1311 | ||||
| -rw-r--r-- | modules/gdnative/gdnative.h | 396 | ||||
| -rw-r--r-- | modules/gdnative/godot/array.cpp (renamed from modules/gdnative/godot/godot_array.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/array.h (renamed from modules/gdnative/godot/godot_array.h) | 15 | ||||
| -rw-r--r-- | modules/gdnative/godot/basis.cpp (renamed from modules/gdnative/godot/godot_basis.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/basis.h (renamed from modules/gdnative/godot/godot_basis.h) | 13 | ||||
| -rw-r--r-- | modules/gdnative/godot/color.cpp (renamed from modules/gdnative/godot/godot_color.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/color.h (renamed from modules/gdnative/godot/godot_color.h) | 12 | ||||
| -rw-r--r-- | modules/gdnative/godot/dictionary.cpp (renamed from modules/gdnative/godot/godot_dictionary.cpp) | 12 | ||||
| -rw-r--r-- | modules/gdnative/godot/dictionary.h (renamed from modules/gdnative/godot/godot_dictionary.h) | 16 | ||||
| -rw-r--r-- | modules/gdnative/godot/gdnative.cpp (renamed from modules/gdnative/godot.cpp) | 79 | ||||
| -rw-r--r-- | modules/gdnative/godot/gdnative.h | 303 | ||||
| -rw-r--r-- | modules/gdnative/godot/icon.png.import | 23 | ||||
| -rw-r--r-- | modules/gdnative/godot/node_path.cpp (renamed from modules/gdnative/godot/godot_node_path.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/node_path.h (renamed from modules/gdnative/godot/godot_node_path.h) | 12 | ||||
| -rw-r--r-- | modules/gdnative/godot/plane.cpp (renamed from modules/gdnative/godot/godot_plane.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/plane.h (renamed from modules/gdnative/godot/godot_plane.h) | 12 | ||||
| -rw-r--r-- | modules/gdnative/godot/pool_arrays.cpp (renamed from modules/gdnative/godot/godot_pool_arrays.cpp) | 10 | ||||
| -rw-r--r-- | modules/gdnative/godot/pool_arrays.h (renamed from modules/gdnative/godot/godot_pool_arrays.h) | 61 | ||||
| -rw-r--r-- | modules/gdnative/godot/quat.cpp (renamed from modules/gdnative/godot/godot_quat.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/quat.h (renamed from modules/gdnative/godot/godot_quat.h) | 12 | ||||
| -rw-r--r-- | modules/gdnative/godot/rect2.cpp (renamed from modules/gdnative/godot/godot_rect2.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/rect2.h (renamed from modules/gdnative/godot/godot_rect2.h) | 6 | ||||
| -rw-r--r-- | modules/gdnative/godot/rect3.cpp (renamed from modules/gdnative/godot/godot_rect3.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/rect3.h (renamed from modules/gdnative/godot/godot_rect3.h) | 14 | ||||
| -rw-r--r-- | modules/gdnative/godot/rid.cpp (renamed from modules/gdnative/godot/godot_rid.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/rid.h (renamed from modules/gdnative/godot/godot_rid.h) | 10 | ||||
| -rw-r--r-- | modules/gdnative/godot/string.cpp (renamed from modules/gdnative/godot/godot_string.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/string.h (renamed from modules/gdnative/godot/godot_string.h) | 11 | ||||
| -rw-r--r-- | modules/gdnative/godot/transform.cpp (renamed from modules/gdnative/godot/godot_transform.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/transform.h (renamed from modules/gdnative/godot/godot_transform.h) | 16 | ||||
| -rw-r--r-- | modules/gdnative/godot/transform2d.cpp (renamed from modules/gdnative/godot/godot_transform2d.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/transform2d.h (renamed from modules/gdnative/godot/godot_transform2d.h) | 14 | ||||
| -rw-r--r-- | modules/gdnative/godot/variant.cpp (renamed from modules/gdnative/godot/godot_variant.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/variant.h (renamed from modules/gdnative/godot/godot_variant.h) | 47 | ||||
| -rw-r--r-- | modules/gdnative/godot/vector2.cpp (renamed from modules/gdnative/godot/godot_vector2.cpp) | 4 | ||||
| -rw-r--r-- | modules/gdnative/godot/vector2.h (renamed from modules/gdnative/godot/godot_vector2.h) | 10 | ||||
| -rw-r--r-- | modules/gdnative/godot/vector3.cpp (renamed from modules/gdnative/godot/godot_vector3.cpp) | 9 | ||||
| -rw-r--r-- | modules/gdnative/godot/vector3.h (renamed from modules/gdnative/godot/godot_vector3.h) | 14 | ||||
| -rw-r--r-- | modules/gdnative/register_types.cpp | 55 | ||||
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 24 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.cpp | 34 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.cpp | 4 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 86 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 10 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 318 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.h | 3 | ||||
| -rw-r--r-- | modules/gridmap/grid_map.cpp | 1 | ||||
| -rw-r--r-- | modules/nativescript/SCsub | 10 | ||||
| -rw-r--r-- | modules/nativescript/api_generator.cpp (renamed from modules/gdnative/api_generator.cpp) | 6 | ||||
| -rw-r--r-- | modules/nativescript/api_generator.h (renamed from modules/gdnative/api_generator.h) | 0 | ||||
| -rw-r--r-- | modules/nativescript/config.py | 8 | ||||
| -rw-r--r-- | modules/nativescript/godot_nativescript.cpp | 205 | ||||
| -rw-r--r-- | modules/nativescript/godot_nativescript.h (renamed from modules/gdnative/godot.h) | 267 | ||||
| -rw-r--r-- | modules/nativescript/nativescript.cpp | 1232 | ||||
| -rw-r--r-- | modules/nativescript/nativescript.h | 317 | ||||
| -rw-r--r-- | modules/nativescript/register_types.cpp | 124 | ||||
| -rw-r--r-- | modules/nativescript/register_types.h | 31 | ||||
| -rw-r--r-- | modules/openssl/stream_peer_openssl.cpp | 4 | ||||
| -rw-r--r-- | modules/openssl/stream_peer_openssl.h | 2 | ||||
| -rw-r--r-- | modules/stb_vorbis/audio_stream_ogg_vorbis.cpp | 2 | ||||
| -rw-r--r-- | modules/theora/video_stream_theora.cpp | 4 | ||||
| -rw-r--r-- | modules/tinyexr/config.py | 6 | ||||
| -rw-r--r-- | modules/visual_script/register_types.cpp | 1 | ||||
| -rw-r--r-- | modules/visual_script/visual_script.cpp | 28 | ||||
| -rw-r--r-- | modules/visual_script/visual_script.h | 2 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 324 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_editor.h | 24 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_expression.cpp | 16 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_flow_control.cpp | 45 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_flow_control.h | 3 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_func_nodes.cpp | 345 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_func_nodes.h | 30 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_nodes.cpp | 227 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_nodes.h | 35 | ||||
| -rw-r--r-- | modules/visual_script/visual_script_yield_nodes.cpp | 14 | ||||
| -rw-r--r-- | modules/webm/video_stream_webm.cpp | 4 |
79 files changed, 3944 insertions, 2411 deletions
diff --git a/modules/etc/config.py b/modules/etc/config.py index fb920482f5..4b0b01b78e 100644 --- a/modules/etc/config.py +++ b/modules/etc/config.py @@ -4,4 +4,8 @@ def can_build(platform): def configure(env): - pass + # Tools only, disabled for non-tools + # TODO: Find a cleaner way to achieve that + if (env["tools"] == "no"): + env["module_etc_enabled"] = "no" + env.disabled_modules.append("etc") diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp index d9daffc59e..353bd1274a 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_etc.cpp @@ -153,6 +153,9 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format); int wofs = 0; + + print_line("begin encoding, format: " + Image::get_format_name(etc_format)); + uint64_t t = OS::get_singleton()->get_ticks_msec(); for (int i = 0; i < mmc + 1; i++) { // convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF) // NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion. @@ -177,6 +180,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f delete[] etc_data; delete[] src_rgba_f; } + print_line("time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t)); p_img->create(imgw, imgh, mmc > 1 ? true : false, etc_format, dst_data); } diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index dad9a54df6..158f7fd94d 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -29,732 +29,70 @@ /*************************************************************************/ #include "gdnative.h" -#include "global_config.h" #include "global_constants.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" -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) -#include "api_generator.h" -#endif - -#ifdef TOOLS_ENABLED -#include "editor/editor_node.h" -#endif - -Error NativeLibrary::initialize(NativeLibrary *&p_native_lib, const StringName p_path) { - - if (GDNativeScriptLanguage::get_singleton()->initialized_libraries.has(p_path)) { - p_native_lib = GDNativeScriptLanguage::get_singleton()->initialized_libraries[p_path]; - return OK; - } - - NativeLibrary *lib = memnew(NativeLibrary); - lib->path = p_path; - - p_native_lib = lib; - - // Open the file - - Error error; - error = OS::get_singleton()->open_dynamic_library(p_path, lib->handle); - if (error) return error; - ERR_FAIL_COND_V(!lib->handle, ERR_BUG); - - // Get the method - - void *library_init; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(lib->handle, GDNativeScriptLanguage::get_init_symbol_name(), library_init); - if (error) return error; - ERR_FAIL_COND_V(!library_init, ERR_BUG); - - void (*library_init_fpointer)(godot_native_init_options *) = (void (*)(godot_native_init_options *))library_init; - - godot_native_init_options options; - - options.in_editor = SceneTree::get_singleton()->is_editor_hint(); - options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); - options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); - options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); - - library_init_fpointer(&options); // Catch errors? - - GDNativeScriptLanguage::get_singleton()->initialized_libraries[p_path] = lib; - - return OK; -} - -Error NativeLibrary::terminate(NativeLibrary *&p_native_lib) { - - if (!GDNativeScriptLanguage::get_singleton()->initialized_libraries.has(p_native_lib->path)) { - OS::get_singleton()->close_dynamic_library(p_native_lib->handle); - p_native_lib->handle = 0; - return OK; - } - - Error error = OK; - void *library_terminate; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(p_native_lib->handle, GDNativeScriptLanguage::get_terminate_symbol_name(), library_terminate); - if (!error) { - - void (*library_terminate_pointer)(godot_native_terminate_options *) = (void (*)(godot_native_terminate_options *))library_terminate; - - godot_native_terminate_options options; - options.in_editor = SceneTree::get_singleton()->is_editor_hint(); - - library_terminate_pointer(&options); - } - - GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); - - OS::get_singleton()->close_dynamic_library(p_native_lib->handle); - p_native_lib->handle = 0; - - return OK; -} - -// Script -#ifdef TOOLS_ENABLED - -void GDNativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { - ERR_FAIL_COND(!script_data); - - List<PropertyInfo> pinfo; - Map<StringName, Variant> values; - - for (Map<StringName, GDNativeScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { - PropertyInfo p = E->get().info; - p.name = String(E->key()); - pinfo.push_back(p); - values[p.name] = E->get().default_value; - } - - p_placeholder->update(pinfo, values); -} - -void GDNativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - - placeholders.erase(p_placeholder); -} - -#endif - -bool GDNativeScript::can_instance() const { -#ifdef TOOLS_ENABLED - return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); -#else - // allow defaultlibrary without editor features - if (!library.is_valid()) { - String path = GLOBAL_GET("gdnative/default_gdnativelibrary"); - - RES lib = ResourceLoader::load(path); - - if (lib.is_valid() && lib->cast_to<GDNativeLibrary>()) { - return true; - } - } +const String init_symbol = "godot_gdnative_init"; +const String terminate_symbol = "godot_gdnative_terminate"; - return script_data; -#endif - //return script_data || (!tool && !ScriptServer::is_scripting_enabled()); - // change to true enable in editor stuff. -} - -Ref<Script> GDNativeScript::get_base_script() const { - Ref<GDNativeScript> base_script; - base_script->library = library; - base_script->script_data = script_data; - base_script->script_name = script_data->base; - return base_script; -} - -StringName GDNativeScript::get_instance_base_type() const { - return script_data->base_native_type; -} - -ScriptInstance *GDNativeScript::instance_create(Object *p_this) { - -#ifdef TOOLS_ENABLED - - // find a good way to initialize stuff in the editor - if (!ScriptServer::is_scripting_enabled() && !is_tool()) { - // placeholder, for nodes. But for tools we want the real thing - - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(GDNativeScriptLanguage::singleton, Ref<Script>((Script *)this), p_this)); - placeholders.insert(sins); - - if (!library.is_valid()) - return sins; - - if (!library->native_library) { - Error err = library->_initialize(); - if (err != OK) { - return sins; - } - } - - if (!script_data) { - script_data = library->get_script_data(script_name); - } - if (script_data && script_data->create_func.create_func) { - script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - } - - _update_placeholder(sins); - - return sins; - } - -#endif +String GDNativeLibrary::platform_names[NUM_PLATFORMS] = { + "X11_32bit", + "X11_64bit", + "Windows_32bit", + "Windows_64bit", + "OSX", - if (!library.is_valid()) { - String path = GLOBAL_GET("gdnative/default_gdnativelibrary"); + "Android", + "iOS", - RES lib = ResourceLoader::load(path); - - if (lib.is_valid() && lib->cast_to<GDNativeLibrary>()) { - set_library(lib); - } - } + "WebAssembly" +}; +String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = { + "so", + "so", + "dll", + "dll", + "dylib", - GDNativeInstance *new_instance = memnew(GDNativeInstance); + "so", + "dylib", - new_instance->owner = p_this; - new_instance->script = Ref<GDNativeScript>(this); + "wasm" +}; -#ifndef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled()) { - new_instance->userdata = 0; - } else { - new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - } +// TODO(karroffel): make this actually do the right thing. +GDNativeLibrary::Platform GDNativeLibrary::current_platform = +#if defined(X11_ENABLED) + X11_64BIT; +#elif defined(WINDOWS_ENABLED) + WINDOWS_64BIT; +#elif defined(OSX_ENABLED) + OSX; #else - new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); + X11_64BIT; // need a sensible default.. #endif - instances.insert(p_this); - return new_instance; -} - -bool GDNativeScript::instance_has(const Object *p_this) const { - return instances.has((Object *)p_this); // TODO -} - -bool GDNativeScript::has_source_code() const { - return false; -} - -String GDNativeScript::get_source_code() const { - return ""; -} - -Error GDNativeScript::reload(bool p_keep_state) { - return FAILED; -} - -bool GDNativeScript::has_method(const StringName &p_method) const { - if (!script_data) - return false; - GDNativeScriptData *data = script_data; - - while (data) { - if (data->methods.has(p_method)) - return true; - - data = data->base_data; - } - - return false; -} - -MethodInfo GDNativeScript::get_method_info(const StringName &p_method) const { - if (!script_data) - return MethodInfo(); - GDNativeScriptData *data = script_data; - - while (data) { - if (data->methods.has(p_method)) - return data->methods[p_method].info; - - data = data->base_data; - } - - ERR_FAIL_COND_V(!script_data->methods.has(p_method), MethodInfo()); - return MethodInfo(); -} - -void GDNativeScript::get_script_method_list(List<MethodInfo> *p_list) const { - if (!script_data) return; - - Set<MethodInfo> methods; - GDNativeScriptData *data = script_data; - - while (data) { - for (Map<StringName, GDNativeScriptData::Method>::Element *E = data->methods.front(); E; E = E->next()) { - methods.insert(E->get().info); - } - data = data->base_data; - } - - for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -void GDNativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { - if (!script_data) return; - - Set<PropertyInfo> properties; - GDNativeScriptData *data = script_data; - - while (data) { - for (Map<StringName, GDNativeScriptData::Property>::Element *E = data->properties.front(); E; E = E->next()) { - properties.insert(E->get().info); - } - data = data->base_data; - } - - for (Set<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -bool GDNativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - if (!script_data) return false; - - GDNativeScriptData *data = script_data; - - while (data) { - if (data->properties.has(p_property)) { - r_value = data->properties[p_property].default_value; - return true; - } - - data = data->base_data; - } - - return false; -} - -bool GDNativeScript::is_tool() const { - ERR_FAIL_COND_V(!script_data, false); - return script_data->is_tool; -} - -String GDNativeScript::get_node_type() const { - return ""; // ? -} - -ScriptLanguage *GDNativeScript::get_language() const { - return GDNativeScriptLanguage::singleton; -} - -bool GDNativeScript::has_script_signal(const StringName &p_signal) const { - if (!script_data) - return false; - - GDNativeScriptData *data = script_data; - - while (data) { - if (data->signals_.has(p_signal)) { - return true; - } - - data = data->base_data; - } - - return false; -} - -void GDNativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - if (!script_data) - return; - - Set<MethodInfo> signals_; - GDNativeScriptData *data = script_data; - - while (data) { - - for (Map<StringName, GDNativeScriptData::Signal>::Element *S = data->signals_.front(); S; S = S->next()) { - signals_.insert(S->get().signal); - } - - data = data->base_data; - } - - for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) { - r_signals->push_back(E->get()); - } -} - -Variant GDNativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - /* STEP 1, CREATE */ - - if (!library.is_valid() || ((String)script_name).empty() || !script_data) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - r_error.error = Variant::CallError::CALL_OK; - REF ref; - Object *owner = NULL; - - GDNativeScriptData *_baseptr = script_data; - while (_baseptr->base_data) { - _baseptr = _baseptr->base_data; - } - - if (!(_baseptr->base_native_type == "")) { - owner = ClassDB::instance(_baseptr->base_native_type); - } else { - owner = memnew(Reference); //by default, no base means use reference - } - - Reference *r = owner->cast_to<Reference>(); - if (r) { - ref = REF(r); - } - - // GDScript does it like this: _create_instance(p_args, p_argcount, owner, r != NULL, r_error); - // @Todo support varargs for constructors. - GDNativeInstance *instance = (GDNativeInstance *)instance_create(owner); - - owner->set_script_instance(instance); - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -Ref<GDNativeLibrary> GDNativeScript::get_library() const { - return library; -} - -void GDNativeScript::set_library(Ref<GDNativeLibrary> p_library) { - library = p_library; - -#ifdef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled()) - return; -#endif - if (library.is_valid()) { - Error initalize_status = library->_initialize(); - ERR_FAIL_COND(initalize_status != OK); - if (script_name) { - script_data = library->native_library->scripts[script_name]; - ERR_FAIL_COND(!script_data); - } - } -} - -StringName GDNativeScript::get_script_name() const { - return script_name; -} - -void GDNativeScript::set_script_name(StringName p_script_name) { - script_name = p_script_name; - - if (library.is_valid()) { -#ifdef TOOLS_ENABLED - if (!library->native_library) { - library->_initialize(); - } -#endif - if (library->native_library) { - script_data = library->get_script_data(script_name); - ERR_FAIL_COND(!script_data); - } - } -} - -void GDNativeScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_library"), &GDNativeScript::get_library); - ClassDB::bind_method(D_METHOD("set_library", "library"), &GDNativeScript::set_library); - ClassDB::bind_method(D_METHOD("get_script_name"), &GDNativeScript::get_script_name); - ClassDB::bind_method(D_METHOD("set_script_name", "script_name"), &GDNativeScript::set_script_name); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDNativeScript::_new, MethodInfo(Variant::OBJECT, "new")); - - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); - ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_name"), "set_script_name", "get_script_name"); -} - -GDNativeScript::GDNativeScript() { - script_data = NULL; - GDNativeScriptLanguage::get_singleton()->script_list.insert(this); -} - -GDNativeScript::~GDNativeScript() { - //hmm - GDNativeScriptLanguage::get_singleton()->script_list.erase(this); -} - -// Library - -GDNativeLibrary *GDNativeLibrary::currently_initialized_library = NULL; - -GDNativeLibrary *GDNativeLibrary::get_currently_initialized_library() { - return currently_initialized_library; -} - -static const char *_dl_platforms_info[] = { - "|unix|so|Unix", - "unix|x11|so|X11", - "unix|server|so|Server", - "unix|android|so|Android", - "unix|haiku|so|Haiku", // Right? - "|mac|dylib|Mac", - "mac|ios|dylib|iOS", - "mac|osx|dylib|OSX", - "|html5|js|HTML5", - "|windows|dll|Windows", - "windows|uwp|dll|UWP", - NULL // Finishing condition -}; - -void GDNativeLibrary::set_platform_file(StringName p_platform, String p_file) { - if (p_file.empty()) { - platform_files.erase(p_platform); - } else { - platform_files[p_platform] = p_file; - } -} - -String GDNativeLibrary::get_platform_file(StringName p_platform) const { - if (platform_files.has(p_platform)) { - return platform_files[p_platform]; - } else { - return ""; - } -} - -Error GDNativeLibrary::_initialize() { - _THREAD_SAFE_METHOD_ - - // Get the file - - const String platform_name = OS::get_singleton()->get_name(); - String platform_file(""); - char **platform_info = (char **)_dl_platforms_info; - - if (platform_files.has(platform_name.to_lower())) { - platform_file = platform_files[platform_name.to_lower()]; - } - - while (*platform_info) { - String platform_info_string(*platform_info); - - if (platform_name == platform_info_string.get_slicec('|', 3)) { - String platform_key = platform_info_string.get_slicec('|', 1); - String fallback_platform_key = platform_info_string.get_slicec('|', 0); - - if (platform_files.has(platform_key)) { - platform_file = platform_files[platform_key]; - } else if (!fallback_platform_key.empty() && platform_files.has(fallback_platform_key)) { - platform_file = platform_files[fallback_platform_key]; - } else { - return ERR_UNAVAILABLE; - } - } - platform_info++; - } - ERR_FAIL_COND_V(platform_file == "", ERR_DOES_NOT_EXIST); - - StringName path = GlobalConfig::get_singleton()->globalize_path(platform_file); - - GDNativeLibrary::currently_initialized_library = this; - - Error ret = NativeLibrary::initialize(native_library, path); - native_library->dllib = this; - - GDNativeLibrary::currently_initialized_library = NULL; - - return ret; -} - -Error GDNativeLibrary::_terminate() { - ERR_FAIL_COND_V(!native_library, ERR_BUG); - ERR_FAIL_COND_V(!native_library->handle, ERR_BUG); - - // de-init stuff - - for (Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.front(); E; E = E->next()) { - for (Map<StringName, GDNativeScriptData::Method>::Element *M = E->get()->methods.front(); M; M = M->next()) { - if (M->get().method.free_func) { - M->get().method.free_func(M->get().method.method_data); - } - } - if (E->get()->create_func.free_func) { - E->get()->create_func.free_func(E->get()->create_func.method_data); - } - if (E->get()->destroy_func.free_func) { - E->get()->destroy_func.free_func(E->get()->destroy_func.method_data); - } - - for (Set<GDNativeScript *>::Element *S = GDNativeScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { - if (S->get()->script_data == E->get()) { - S->get()->script_data = NULL; - } - } - - memdelete(E->get()); - } - - Error ret = NativeLibrary::terminate(native_library); - native_library->scripts.clear(); - - return ret; -} - -void GDNativeLibrary::_register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(native_library->scripts.has(p_name)); - - GDNativeScriptData *s = memnew(GDNativeScriptData); - s->base = p_base; - s->create_func = p_instance_func; - s->destroy_func = p_destroy_func; - Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.find(p_base); - if (E) { - s->base_data = E->get(); - s->base_native_type = s->base_data->base_native_type; - } else { - if (!ClassDB::class_exists(p_base)) { - memdelete(s); - ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'"); - ERR_FAIL(); - } - s->base_native_type = p_base; - } - - native_library->scripts.insert(p_name, s); -} - -void GDNativeLibrary::_register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(native_library->scripts.has(p_name)); - - GDNativeScriptData *s = memnew(GDNativeScriptData); - s->base = p_base; - s->create_func = p_instance_func; - s->destroy_func = p_destroy_func; - s->is_tool = true; - Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.find(p_base); - if (E) { - s->base_data = E->get(); - s->base_native_type = s->base_data->base_native_type; - } else { - if (!ClassDB::class_exists(p_base)) { - memdelete(s); - ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'"); - ERR_FAIL(); - } - s->base_native_type = p_base; - } - - native_library->scripts.insert(p_name, s); -} - -void GDNativeLibrary::_register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - - p_info.name = p_method; - GDNativeScriptData::Method method; - - method = GDNativeScriptData::Method(p_func, p_info, p_attr.rpc_type); - - native_library->scripts[p_name]->methods.insert(p_method, method); -} - -void GDNativeLibrary::_register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - - GDNativeScriptData::Property p; - - PropertyInfo pi; - pi.name = p_path; - - if (p_attr != NULL) { - pi = PropertyInfo((Variant::Type)p_attr->type, p_path, (PropertyHint)p_attr->hint, *(String *)&p_attr->hint_string, p_attr->usage); - - p = GDNativeScriptData::Property(p_setter, p_getter, pi, *(Variant *)&p_attr->default_value, p_attr->rset_type); - } - - native_library->scripts[p_name]->properties.insert(p_path, p); +GDNativeLibrary::GDNativeLibrary() + : library_paths() { } -void GDNativeLibrary::_register_script_signal(const StringName p_name, const godot_signal *p_signal) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - ERR_FAIL_COND(!p_signal); - - GDNativeScriptData::Signal signal; - - signal.signal.name = *(String *)&p_signal->name; - - { - List<PropertyInfo> arguments; - for (int i = 0; i < p_signal->num_args; i++) { - PropertyInfo info; - godot_signal_argument attrib = p_signal->args[i]; - - String *name = (String *)&attrib.name; - info.name = *name; - info.type = (Variant::Type)attrib.type; - info.hint = (PropertyHint)attrib.hint; - info.hint_string = *(String *)&attrib.hint_string; - info.usage = attrib.usage; - - arguments.push_back(info); - } - - signal.signal.arguments = arguments; - } - - { - Vector<Variant> default_arguments; - for (int i = 0; i < p_signal->num_default_args; i++) { - Variant *v; - godot_signal_argument attrib = p_signal->args[i]; - - v = (Variant *)&attrib.default_value; - - default_arguments.push_back(*v); - } - - signal.signal.default_arguments = default_arguments; - } - - native_library->scripts[p_name]->signals_.insert(*(String *)&p_signal->name, signal); +GDNativeLibrary::~GDNativeLibrary() { } -GDNativeScriptData *GDNativeLibrary::get_script_data(const StringName p_name) { - ERR_FAIL_COND_V(!native_library, NULL); - - ERR_FAIL_COND_V(!native_library->scripts.has(p_name), NULL); - - return native_library->scripts[p_name]; +void GDNativeLibrary::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path); + ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path); } bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name.begins_with("platform/")) { - set_platform_file(name.get_slice("/", 1), p_value); + set_library_path(name.get_slice("/", 1), p_value); return true; } return false; @@ -763,517 +101,234 @@ bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) { bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name; if (name.begins_with("platform/")) { - r_ret = get_platform_file(name.get_slice("/", 1)); + r_ret = get_library_path(name.get_slice("/", 1)); return true; } return false; } void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { - char **platform_info = (char **)_dl_platforms_info; - - Set<String> registered_platform_names; - { - List<StringName> ep; - // ep.push_back("X11"); - // EditorImportExport::get_singleton()->get_export_platforms(&ep); - - // @Todo - // get export platforms with the new export system somehow. - for (List<StringName>::Element *E = ep.front(); E; E = E->next()) { - registered_platform_names.insert(String(E->get()).to_lower()); - } + for (int i = 0; i < NUM_PLATFORMS; i++) { + p_list->push_back(PropertyInfo(Variant::STRING, + "platform/" + platform_names[i], + PROPERTY_HINT_FILE, + "*." + platform_lib_ext[i])); } +} - while (*platform_info) { - String platform_info_string(*platform_info); - String fallback_platform_key = platform_info_string.get_slicec('|', 0); - String platform_key = platform_info_string.get_slicec('|', 1); - String platform_extension = platform_info_string.get_slicec('|', 2); - String platform_name = platform_info_string.get_slicec('|', 3); - - registered_platform_names.erase(platform_name); - - if (fallback_platform_key.empty()) { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension)); - - } else { - if (platform_files.has(platform_key)) { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED)); - } else { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE)); - } +void GDNativeLibrary::set_library_path(StringName p_platform, String p_path) { + int i; + for (i = 0; i <= NUM_PLATFORMS; i++) { + if (i == NUM_PLATFORMS) break; + if (platform_names[i] == p_platform) { + break; } - platform_info++; - } - - while (registered_platform_names.size()) { - const String platform_name = registered_platform_names.front()->get(); - registered_platform_names.erase(platform_name); - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_name.to_lower(), PROPERTY_HINT_FILE, "*")); } -} - -void GDNativeLibrary::_notification(int what) { - // TODO -} - -void GDNativeLibrary::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_platform_file", "platform", "file"), &GDNativeLibrary::set_platform_file); - ClassDB::bind_method(D_METHOD("get_platform_file", "platform"), &GDNativeLibrary::get_platform_file); -} - -GDNativeLibrary::GDNativeLibrary() { - native_library = NULL; -} - -GDNativeLibrary::~GDNativeLibrary() { - if (!native_library) { - return; + if (i == NUM_PLATFORMS) { + ERR_EXPLAIN(String("No such platform: ") + p_platform); + ERR_FAIL(); } - if (native_library->handle) { - _terminate(); - } + library_paths[i] = p_path; } -// Instance - -bool GDNativeInstance::set(const StringName &p_name, const Variant &p_value) { - if (!script->script_data) - return false; - if (script->script_data->properties.has(p_name)) { - script->script_data->properties[p_name].setter.set_func((godot_object *)owner, script->script_data->properties[p_name].setter.method_data, userdata, *(godot_variant *)&p_value); - return true; +String GDNativeLibrary::get_library_path(StringName p_platform) const { + int i; + for (i = 0; i <= NUM_PLATFORMS; i++) { + if (i == NUM_PLATFORMS) break; + if (platform_names[i] == p_platform) { + break; + } } - return false; -} -bool GDNativeInstance::get(const StringName &p_name, Variant &r_ret) const { - if (!script->script_data) - return false; - if (script->script_data->properties.has(p_name)) { - godot_variant value = script->script_data->properties[p_name].getter.get_func((godot_object *)owner, script->script_data->properties[p_name].getter.method_data, userdata); - r_ret = *(Variant *)&value; - return true; + if (i == NUM_PLATFORMS) { + ERR_EXPLAIN(String("No such platform: ") + p_platform); + ERR_FAIL_V(""); } - return false; -} - -void GDNativeInstance::get_property_list(List<PropertyInfo> *p_properties) const { - script->get_script_property_list(p_properties); - // TODO: dynamic properties -} -Variant::Type GDNativeInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - if (script->script_data->properties.has(p_name)) { - *r_is_valid = true; - return script->script_data->properties[p_name].info.type; - } - *r_is_valid = false; - return Variant::NIL; + return library_paths[i]; } -void GDNativeInstance::get_method_list(List<MethodInfo> *p_list) const { - script->get_script_method_list(p_list); +String GDNativeLibrary::get_active_library_path() const { + return library_paths[GDNativeLibrary::current_platform]; } -bool GDNativeInstance::has_method(const StringName &p_method) const { - return script->has_method(p_method); +GDNative::GDNative() { + initialized = false; + native_handle = NULL; } -Variant GDNativeInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - // TODO: validated methods & errors - - GDNativeScriptData *data_ptr = script->script_data; - while (data_ptr) { - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - godot_variant result = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - return *(Variant *)&result; - } - data_ptr = data_ptr->base_data; - } - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); +GDNative::~GDNative() { + // TODO(karroffel): implement ALL the things! } -void GDNativeInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - // TODO: validated methods & errors +extern "C" void _api_anchor(); - GDNativeScriptData *data_ptr = script->script_data; - while (data_ptr) { - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - } - data_ptr = data_ptr->base_data; - } +void GDNative::_compile_dummy_for_api() { + _api_anchor(); } -void GDNativeInstance::_ml_call_reversed(GDNativeScriptData *data_ptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - // TODO: validated methods & errors +void GDNative::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &GDNative::set_library); + ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &GDNative::get_library); - if (data_ptr->base_data) - _ml_call_reversed(data_ptr->base_data, p_method, p_args, p_argcount); + ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize); + ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate); - // Variant::CallError ce; + // TODO(karroffel): get_native_(raw_)call_types binding? - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - } -} + // TODO(karroffel): make this a varargs function? + ClassDB::bind_method(D_METHOD("call_native:Variant", "procedure_name", "arguments:Array"), &GDNative::call_native); -void GDNativeInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.ptr() && script->script_data) { - _ml_call_reversed(script->script_data, p_method, p_args, p_argcount); - } -} - -void GDNativeInstance::notification(int p_notification) { - Variant value = p_notification; - const Variant *args[1] = { &value }; - call_multilevel(GDNativeScriptLanguage::singleton->strings._notification, args, 1); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); } -Ref<Script> GDNativeInstance::get_script() const { - return script; +void GDNative::set_library(Ref<GDNativeLibrary> p_library) { + ERR_EXPLAIN("Tried to change library of GDNative when it is already set"); + ERR_FAIL_COND(library.is_valid()); + library = p_library; } -ScriptLanguage *GDNativeInstance::get_language() { - return GDNativeScriptLanguage::singleton; +Ref<GDNativeLibrary> GDNative::get_library() { + return library; } -ScriptInstance::RPCMode GDNativeInstance::get_rpc_mode(const StringName &p_method) const { - GDNativeScriptData::Method m = script->script_data->methods[p_method]; - switch (m.rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_SYNC: - return RPC_MODE_SYNC; - case GODOT_METHOD_RPC_MODE_MASTER: - return RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_SLAVE: - return RPC_MODE_SLAVE; - default: - return RPC_MODE_DISABLED; +bool GDNative::initialize() { + if (library.is_null()) { + ERR_PRINT("No library set, can't initialize GDNative object"); + return false; } -} -ScriptInstance::RPCMode GDNativeInstance::get_rset_mode(const StringName &p_variable) const { - GDNativeScriptData::Property p = script->script_data->properties[p_variable]; - switch (p.rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_SYNC: - return RPC_MODE_SYNC; - case GODOT_METHOD_RPC_MODE_MASTER: - return RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_SLAVE: - return RPC_MODE_SLAVE; - default: - return RPC_MODE_DISABLED; + String lib_path = library->get_active_library_path(); + if (lib_path.empty()) { + ERR_PRINT("No library set for this platform"); + return false; } -} - -GDNativeInstance::GDNativeInstance() { - owner = NULL; - userdata = NULL; -} -GDNativeInstance::~GDNativeInstance() { - if (script.is_valid()) { - if (owner) { - script->instances.erase(owner); - } - if (!script->script_data) - return; - script->script_data->destroy_func.destroy_func((godot_object *)owner, script->script_data->destroy_func.method_data, userdata); - if (script->script_data->destroy_func.free_func) - script->script_data->destroy_func.free_func(script->script_data->destroy_func.method_data); - if (script->script_data->create_func.free_func) - script->script_data->create_func.free_func(script->script_data->create_func.method_data); + String path = ProjectSettings::get_singleton()->globalize_path(lib_path); + Error err = OS::get_singleton()->open_dynamic_library(path, native_handle); + if (err != OK) { + return false; } -} - -// Language - -GDNativeScriptLanguage *GDNativeScriptLanguage::singleton = NULL; - -String GDNativeScriptLanguage::get_name() const { - return "Native"; -} - -void _add_reload_node() { -#ifdef TOOLS_ENABLED - GDNativeReloadNode *rn = memnew(GDNativeReloadNode); - EditorNode::get_singleton()->add_child(rn); -#endif -} - -void GDNativeScriptLanguage::init() { - // TODO: Expose globals - GLOBAL_DEF("gdnative/default_gdnativelibrary", ""); - PropertyInfo prop_info(Variant::STRING, "gdnative/default_gdnativelibrary", PROPERTY_HINT_FILE, "tres,res,dllib"); - GlobalConfig::get_singleton()->set_custom_property_info("gdnative/default_gdnativelibrary", prop_info); - -// generate bindings -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) - - List<String> args = OS::get_singleton()->get_cmdline_args(); - List<String>::Element *E = args.find("--gdnative-generate-json-api"); + void *library_init; + err = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + init_symbol, + library_init); - if (E && E->next()) { - if (generate_c_api(E->next()->get()) != OK) { - ERR_PRINT("Failed to generate C API\n"); - } + if (err || !library_init) { + return false; } -#endif - -#ifdef TOOLS_ENABLED - // if (SceneTree::get_singleton()->is_editor_hint()) { - EditorNode::add_init_callback(&_add_reload_node); -// } -#endif -} -String GDNativeScriptLanguage::get_type() const { - return "Native"; -} - -String GDNativeScriptLanguage::get_extension() const { - return "gdn"; -} - -Error GDNativeScriptLanguage::execute_file(const String &p_path) { - return OK; // ?? -} - -void GDNativeScriptLanguage::finish() { - // cleanup is for noobs -} + godot_gdnative_init_fn library_init_fpointer; + library_init_fpointer = (godot_gdnative_init_fn)library_init; -// scons doesn't want to link in the api source so we need to call a dummy function to cause it to link -extern "C" void _api_anchor(); - -void GDNativeScriptLanguage::_compile_dummy_for_the_api() { - _api_anchor(); -} + godot_gdnative_init_options options; -Ref<Script> GDNativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - GDNativeScript *src = memnew(GDNativeScript); - src->set_script_name(p_class_name); - return Ref<GDNativeScript>(src); -} - -bool GDNativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { - return false; // TODO -} + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); + options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); + options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); + options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); + options.gd_native_library = (godot_object *)(get_library().ptr()); -Script *GDNativeScriptLanguage::create_script() const { - GDNativeScript *scr = memnew(GDNativeScript); - return scr; -} + library_init_fpointer(&options); -bool GDNativeScriptLanguage::has_named_classes() const { return true; } -int GDNativeScriptLanguage::find_function(const String &p_function, const String &p_code) const { - return -1; // No source code! -} - -String GDNativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { - return ""; // No source code! -} - -void GDNativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { - // TODO TODO TODO -} - -// TODO: Any debugging? (research) -String GDNativeScriptLanguage::debug_get_error() const { - return ""; -} - -int GDNativeScriptLanguage::debug_get_stack_level_count() const { - return 1; // ? -} +bool GDNative::terminate() { -int GDNativeScriptLanguage::debug_get_stack_level_line(int p_level) const { - return -1; -} - -String GDNativeScriptLanguage::debug_get_stack_level_function(int p_level) const { - return "[native code]"; // ? -} - -String GDNativeScriptLanguage::debug_get_stack_level_source(int p_level) const { - return ""; -} - -void GDNativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} - -void GDNativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} - -String GDNativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - return ""; // ?? -} + if (native_handle == NULL) { + ERR_PRINT("No valid library handle, can't terminate GDNative object"); + return false; + } -void GDNativeScriptLanguage::reload_all_scripts() { - // @Todo -} + Error error = OK; + void *library_terminate; + error = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + terminate_symbol, + library_terminate); + if (error) { + OS::get_singleton()->close_dynamic_library(native_handle); + native_handle = NULL; + return true; + } -void GDNativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { - // @Todo - OS::get_singleton()->print("reload tool scripts\n"); -} + godot_gdnative_terminate_fn library_terminate_pointer; + library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate; -void GDNativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdn"); // Container file format -} + // TODO(karroffel): remove this? Should be part of NativeScript, not + // GDNative IMO + godot_gdnative_terminate_options options; + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); -void GDNativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { -} + library_terminate_pointer(&options); -void GDNativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { -} + // GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); -// TODO: all profilling -void GDNativeScriptLanguage::profiling_start() { -} + OS::get_singleton()->close_dynamic_library(native_handle); + native_handle = NULL; -void GDNativeScriptLanguage::profiling_stop() { + return false; } -int GDNativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; +void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) { + native_calls.insert(p_call_type, p_callback); } -int GDNativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; +void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) { + native_raw_calls.insert(p_raw_call_type, p_callback); } -void GDNativeScriptLanguage::frame() { -} +Vector<StringName> GDNativeCallRegistry::get_native_call_types() { + Vector<StringName> call_types; + call_types.resize(native_calls.size()); -String GDNativeScriptLanguage::get_init_symbol_name() { - return "godot_native_init"; // TODO: Maybe make some internal function which would do the actual stuff -} + size_t idx = 0; + for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) { + call_types[idx] = E->key(); + } -String GDNativeScriptLanguage::get_terminate_symbol_name() { - return "godot_native_terminate"; + return call_types; } -GDNativeScriptLanguage::GDNativeScriptLanguage() { - ERR_FAIL_COND(singleton); - strings._notification = StringName("_notification"); - singleton = this; - initialized_libraries = Map<StringName, NativeLibrary *>(); -} +Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() { + Vector<StringName> call_types; + call_types.resize(native_raw_calls.size()); -GDNativeScriptLanguage::~GDNativeScriptLanguage() { - singleton = NULL; -} - -// DLReloadNode + size_t idx = 0; + for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) { + call_types[idx] = E->key(); + } -void GDNativeReloadNode::_bind_methods() { - ClassDB::bind_method("_notification", &GDNativeReloadNode::_notification); + return call_types; } -void GDNativeReloadNode::_notification(int p_what) { -#ifdef TOOLS_ENABLED - - switch (p_what) { - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { - - Set<NativeLibrary *> libs_to_reload; - - for (Map<StringName, NativeLibrary *>::Element *L = GDNativeScriptLanguage::get_singleton()->initialized_libraries.front(); L; L = L->next()) { - // check if file got modified at all - // @Todo - - libs_to_reload.insert(L->get()); - } - - for (Set<NativeLibrary *>::Element *L = libs_to_reload.front(); L; L = L->next()) { - - GDNativeLibrary *lib = L->get()->dllib; - - lib->_terminate(); - lib->_initialize(); - - // update placeholders (if any) - - Set<GDNativeScript *> scripts; - - for (Set<GDNativeScript *>::Element *S = GDNativeScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { - - if (lib->native_library->scripts.has(S->get()->get_script_name())) { - GDNativeScript *script = S->get(); - script->script_data = lib->get_script_data(script->get_script_name()); - scripts.insert(script); - } - } - - for (Set<GDNativeScript *>::Element *S = scripts.front(); S; S = S->next()) { - GDNativeScript *script = S->get(); - if (script->placeholders.size() == 0) - continue; +Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) { - for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { - PlaceHolderScriptInstance *p = P->get(); - script->_update_placeholder(p); - } - } - } - - } break; - default: { - }; + Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type); + if (!E) { + ERR_PRINT((String("No handler for native call type \"" + p_native_call_type) + "\" found").utf8().get_data()); + return Variant(); } -#endif -} -// Resource loader/saver + String procedure_name = p_procedure_name; + godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments); -RES ResourceFormatLoaderGDNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) { - ResourceFormatLoaderText rsflt; - return rsflt.load(p_path, p_original_path, r_error); + return *(Variant *)&result; } -void ResourceFormatLoaderGDNativeScript::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdn"); -} -bool ResourceFormatLoaderGDNativeScript::handles_type(const String &p_type) const { - return (p_type == "Script" || p_type == "Native"); -} -String ResourceFormatLoaderGDNativeScript::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gdn") - return "Native"; - return ""; -} +void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) { -Error ResourceFormatSaverGDNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - ResourceFormatSaverText rfst; - return rfst.save(p_path, p_resource, p_flags); -} - -bool ResourceFormatSaverGDNativeScript::recognize(const RES &p_resource) const { - return p_resource->cast_to<GDNativeScript>() != NULL; -} - -void ResourceFormatSaverGDNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (p_resource->cast_to<GDNativeScript>()) { - p_extensions->push_back("gdn"); + Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type); + if (!E) { + ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data()); + return; } + + String procedure_name = p_procedure_name; + E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return); } diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index 650f999192..dd845cab7a 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -34,382 +34,112 @@ #include "io/resource_saver.h" #include "os/thread_safe.h" #include "resource.h" -#include "scene/main/node.h" -#include "script_language.h" -#include "self_list.h" -#include "godot.h" +#include "godot/gdnative.h" -struct GDNativeScriptData; -class GDNativeLibrary; - -struct NativeLibrary { - StringName path; - void *handle; - - GDNativeLibrary *dllib; - - Map<StringName, GDNativeScriptData *> scripts; - - static Error initialize(NativeLibrary *&p_native_lib, const StringName p_path); - static Error terminate(NativeLibrary *&p_native_lib); -}; - -struct GDNativeScriptData { - /* typedef void* (InstanceFunc)(godot_object* instance); - typedef void (DestroyFunc)(godot_object* instance,void* userdata); - typedef godot_variant (MethodFunc)(godot_object *instance, void *userdata, void *method_data, int arg_count,godot_variant **args); - typedef void (MethodDataFreeFunc)(void *method_data); - typedef void (SetterFunc)(godot_object* instance,void* userdata,godot_variant value); - typedef godot_variant (GetterFunc)(godot_object* instance,void* userdata);*/ - - struct Method { - godot_instance_method method; - MethodInfo info; - int rpc_mode; - - Method() { - } - Method(godot_instance_method p_method, MethodInfo p_info, int p_rpc_mode) { - method = p_method; - info = p_info; - rpc_mode = p_rpc_mode; - } - }; - struct Property { - godot_property_set_func setter; - godot_property_get_func getter; - PropertyInfo info; - Variant default_value; - int rset_mode; - - Property() { - } - Property(godot_property_set_func p_setter, godot_property_get_func p_getter) { - setter = p_setter; - getter = p_getter; - } - Property(godot_property_set_func p_setter, godot_property_get_func p_getter, PropertyInfo p_info, Variant p_default_value, int p_rset_mode) { - setter = p_setter; - getter = p_getter; - info = p_info; - default_value = p_default_value; - rset_mode = p_rset_mode; - } - }; - - struct Signal { - MethodInfo signal; - }; - - Map<StringName, Method> methods; - Map<StringName, Property> properties; - Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals - StringName base; - StringName base_native_type; - GDNativeScriptData *base_data; - godot_instance_create_func create_func; - godot_instance_destroy_func destroy_func; - - bool is_tool; - - GDNativeScriptData() { - base = StringName(); - base_data = NULL; - is_tool = false; - } - GDNativeScriptData(StringName p_base, godot_instance_create_func p_instance, godot_instance_destroy_func p_free) { - base = p_base; - base_data = NULL; - create_func = p_instance; - destroy_func = p_free; - is_tool = false; - } -}; - -class GDNativeScript : public Script { - GDCLASS(GDNativeScript, Script); - - Ref<GDNativeLibrary> library; - StringName script_name; - StringName base_native_type; - Set<Object *> instances; - GDNativeScriptData *script_data; - -#ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; - void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); - virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); -#endif - - friend class GDNativeInstance; - friend class GDNativeScriptLanguage; - friend class GDNativeReloadNode; - friend class GDNativeLibrary; - -protected: - static void _bind_methods(); - -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); - - virtual bool has_method(const StringName &p_method) const; - virtual MethodInfo get_method_info(const StringName &p_method) const; - - virtual bool is_tool() const; - - virtual String get_node_type() const; +class GDNativeLibrary : public Resource { + GDCLASS(GDNativeLibrary, Resource) - virtual ScriptLanguage *get_language() const; + enum Platform { + X11_32BIT, + X11_64BIT, + WINDOWS_32BIT, + WINDOWS_64BIT, + // NOTE(karroffel): I heard OSX 32 bit is dead, so 64 only + OSX, - virtual bool has_script_signal(const StringName &p_signal) const; - virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + // TODO(karroffel): all different android versions and archs + ANDROID, - virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + // TODO(karroffe): all different iOS versions and archs + IOS, - virtual void update_exports() {} //editor tool - virtual void get_script_method_list(List<MethodInfo> *p_list) const; - virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + // TODO(karroffel): figure out how to deal with web stuff at all... + WASM, - Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + // TODO(karroffel): does UWP have different libs?? + // UWP, - Ref<GDNativeLibrary> get_library() const; - void set_library(Ref<GDNativeLibrary> p_library); + NUM_PLATFORMS - StringName get_script_name() const; - void set_script_name(StringName p_script_name); + }; - GDNativeScript(); - ~GDNativeScript(); -}; + static String platform_names[NUM_PLATFORMS]; + static String platform_lib_ext[NUM_PLATFORMS]; -class GDNativeLibrary : public Resource { - _THREAD_SAFE_CLASS_ + // TODO(karroffel): make this actually do something lol. + static Platform current_platform; - GDCLASS(GDNativeLibrary, Resource); - OBJ_SAVE_TYPE(GDNativeLibrary); - - Map<StringName, String> platform_files; - NativeLibrary *native_library; - static GDNativeLibrary *currently_initialized_library; + String library_paths[NUM_PLATFORMS]; protected: - friend class GDNativeScript; - friend struct NativeLibrary; - friend class GDNativeReloadNode; - - GDNativeScriptData *get_script_data(const StringName p_name); - bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - void _notification(int p_what); - static void _bind_methods(); public: - Error _initialize(); - Error _terminate(); - - static GDNativeLibrary *get_currently_initialized_library(); - - void _register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func); - void _register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func); - void _register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info); - void _register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter); - void _register_script_signal(const StringName p_name, const godot_signal *p_signal); - - void set_platform_file(StringName p_platform, String p_file); - String get_platform_file(StringName p_platform) const; - GDNativeLibrary(); ~GDNativeLibrary(); -}; - -class GDNativeInstance : public ScriptInstance { - friend class GDNativeScript; - Object *owner; - Ref<GDNativeScript> script; - void *userdata; - - void _ml_call_reversed(GDNativeScriptData *data_ptr, const StringName &p_method, const Variant **p_args, int p_argcount); - -public: - _FORCE_INLINE_ Object *get_owner() { return owner; } - - _FORCE_INLINE_ void *get_userdata() { return userdata; } - - 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); - 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); - - Variant debug_get_member_by_index(int p_idx) const { return Variant(); } - - virtual void notification(int p_notification); - - virtual Ref<Script> get_script() const; - - virtual ScriptLanguage *get_language(); - - void set_path(const String &p_path); - - void reload_members(); + static void _bind_methods(); - virtual RPCMode get_rpc_mode(const StringName &p_method) const; - virtual RPCMode get_rset_mode(const StringName &p_variable) const; + void set_library_path(StringName p_platform, String p_path); + String get_library_path(StringName p_platform) const; - GDNativeInstance(); - ~GDNativeInstance(); + String get_active_library_path() const; }; -class GDNativeReloadNode; +typedef godot_variant (*native_call_cb)(void *, godot_string *, godot_array *); +typedef void (*native_raw_call_cb)(void *, godot_string *, void *, int, void **, void *); -class GDNativeScriptLanguage : public ScriptLanguage { - friend class GDNativeScript; - friend class GDNativeInstance; - friend class GDNativeReloadNode; - friend class GDNativeLibrary; +struct GDNativeCallRegistry { + static GDNativeCallRegistry *singleton; - static GDNativeScriptLanguage *singleton; + inline GDNativeCallRegistry *get_singleton() { + return singleton; + } - Variant *_global_array; // @Unused necessary? - Vector<Variant> global_array; // @Unused necessary? - Map<StringName, int> globals; // @Unused necessary? + inline GDNativeCallRegistry() + : native_calls(), + native_raw_calls() {} - // @Unused necessary? - void _add_global(const StringName &p_name, const Variant &p_value); + Map<StringName, native_call_cb> native_calls; + Map<StringName, native_raw_call_cb> native_raw_calls; - Mutex *lock; + void register_native_call_type(StringName p_call_type, native_call_cb p_callback); + void register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback); - Set<GDNativeScript *> script_list; + Vector<StringName> get_native_call_types(); + Vector<StringName> get_native_raw_call_types(); +}; - bool profiling; - uint64_t script_frame_time; +class GDNative : public Reference { + GDCLASS(GDNative, Reference) - struct { + Ref<GDNativeLibrary> library; + bool initialized; - StringName _notification; + // TODO(karroffel): different platforms? WASM???? + void *native_handle; - } strings; + void _compile_dummy_for_api(); public: - Map<StringName, NativeLibrary *> initialized_libraries; - - _FORCE_INLINE_ static GDNativeScriptLanguage *get_singleton() { return singleton; } - - virtual String get_name() const; - - /* 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 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 open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } - virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; } - - virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result) { return ERR_UNAVAILABLE; } + GDNative(); + ~GDNative(); - 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 - virtual void thread_enter() {} - virtual 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; - - /* PROFILLER FUNCTIONS */ - - 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(); - - static String get_init_symbol_name(); - static String get_terminate_symbol_name(); - - /* HACKER FUNCTIONS */ - void _compile_dummy_for_the_api(); + static void _bind_methods(); - GDNativeScriptLanguage(); - ~GDNativeScriptLanguage(); -}; + void set_library(Ref<GDNativeLibrary> p_library); + Ref<GDNativeLibrary> get_library(); -class GDNativeReloadNode : public Node { - GDCLASS(GDNativeReloadNode, Node) -public: - static void _bind_methods(); - void _notification(int p_what); -}; + bool is_initialized(); -class ResourceFormatLoaderGDNativeScript : public ResourceFormatLoader { -public: - 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; -}; + bool initialize(); + bool terminate(); -class ResourceFormatSaverGDNativeScript : public ResourceFormatSaver { - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual bool recognize(const RES &p_resource) const; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; + Variant call_native(StringName p_call_type, StringName p_procedure_name, Array p_arguments = Array()); + void call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return); }; #endif // GDNATIVE_H diff --git a/modules/gdnative/godot/godot_array.cpp b/modules/gdnative/godot/array.cpp index 5497dde520..c068eecf8f 100644 --- a/modules/gdnative/godot/godot_array.cpp +++ b/modules/gdnative/godot/array.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_array.cpp */ +/* array.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_array.h" +#include "array.h" #include "core/array.h" #include "core/os/memory.h" diff --git a/modules/gdnative/godot/godot_array.h b/modules/gdnative/godot/array.h index bf8bc61977..cbdbfbdde3 100644 --- a/modules/gdnative/godot/godot_array.h +++ b/modules/gdnative/godot/array.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_array.h */ +/* array.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -37,16 +37,19 @@ extern "C" { #include <stdint.h> +#define GODOT_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED -typedef struct godot_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_ARRAY_SIZE]; } godot_array; #endif -#include "godot_pool_arrays.h" -#include "godot_variant.h" +#include "pool_arrays.h" +#include "variant.h" -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_array_new(godot_array *r_dest); void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src); diff --git a/modules/gdnative/godot/godot_basis.cpp b/modules/gdnative/godot/basis.cpp index 46464932c5..7188215d04 100644 --- a/modules/gdnative/godot/godot_basis.cpp +++ b/modules/gdnative/godot/basis.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_basis.cpp */ +/* basis.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_basis.h" +#include "basis.h" #include "core/variant.h" #include "core/math/matrix3.h" diff --git a/modules/gdnative/godot/godot_basis.h b/modules/gdnative/godot/basis.h index a096a8cc08..79b2b45fdd 100644 --- a/modules/gdnative/godot/godot_basis.h +++ b/modules/gdnative/godot/basis.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_basis.h */ +/* basis.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_BASIS_SIZE 36 + #ifndef GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED #define GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED -typedef struct godot_basis { - uint8_t _dont_touch_that[36]; +typedef struct { + uint8_t _dont_touch_that[GODOT_BASIS_SIZE]; } godot_basis; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "quat.h" +#include "vector3.h" void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis); void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi); diff --git a/modules/gdnative/godot/godot_color.cpp b/modules/gdnative/godot/color.cpp index 6dedf2ab10..eac966ca1f 100644 --- a/modules/gdnative/godot/godot_color.cpp +++ b/modules/gdnative/godot/color.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_color.cpp */ +/* color.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_color.h" +#include "color.h" #include "core/variant.h" #include "core/color.h" diff --git a/modules/gdnative/godot/godot_color.h b/modules/gdnative/godot/color.h index 10dc228b1c..77e709fbe3 100644 --- a/modules/gdnative/godot/godot_color.h +++ b/modules/gdnative/godot/color.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_color.h */ +/* color.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_COLOR_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED #define GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED -typedef struct godot_color { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_COLOR_SIZE]; } godot_color; #endif -#include "../godot.h" -#include "godot_string.h" +#include "gdnative.h" +#include "string.h" void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a); void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b); diff --git a/modules/gdnative/godot/godot_dictionary.cpp b/modules/gdnative/godot/dictionary.cpp index 12c40f0564..1c0761edfd 100644 --- a/modules/gdnative/godot/godot_dictionary.cpp +++ b/modules/gdnative/godot/dictionary.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_dictionary.cpp */ +/* dictionary.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_dictionary.h" +#include "dictionary.h" #include "core/variant.h" #include "core/dictionary.h" @@ -124,11 +124,17 @@ void GDAPI godot_dictionary_set(godot_dictionary *p_self, const godot_variant *p } godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key) { - Array *self = (Array *)p_self; + Dictionary *self = (Dictionary *)p_self; const Variant *key = (const Variant *)p_key; return (godot_variant *)&self->operator[](*key); } +godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key) { + Dictionary *self = (Dictionary *)p_self; + const Variant *key = (const Variant *)p_key; + return (godot_variant *)self->next(key); +} + godot_bool GDAPI godot_dictionary_operator_equal(const godot_dictionary *p_self, const godot_dictionary *p_b) { const Dictionary *self = (const Dictionary *)p_self; const Dictionary *b = (const Dictionary *)p_b; diff --git a/modules/gdnative/godot/godot_dictionary.h b/modules/gdnative/godot/dictionary.h index 0325670b15..a08deb27df 100644 --- a/modules/gdnative/godot/godot_dictionary.h +++ b/modules/gdnative/godot/dictionary.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_dictionary.h */ +/* dictionary.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_DICTIONARY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED #define GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED -typedef struct godot_dictionary { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_DICTIONARY_SIZE]; } godot_dictionary; #endif -#include "../godot.h" -#include "godot_array.h" -#include "godot_variant.h" +#include "array.h" +#include "gdnative.h" +#include "variant.h" void GDAPI godot_dictionary_new(godot_dictionary *r_dest); void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src); @@ -74,6 +76,8 @@ void GDAPI godot_dictionary_set(godot_dictionary *p_self, const godot_variant *p godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key); +godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key); + godot_bool GDAPI godot_dictionary_operator_equal(const godot_dictionary *p_self, const godot_dictionary *p_b); godot_string GDAPI godot_dictionary_to_json(const godot_dictionary *p_self); diff --git a/modules/gdnative/godot.cpp b/modules/gdnative/godot/gdnative.cpp index 4dbb72bba1..29b499ebab 100644 --- a/modules/gdnative/godot.cpp +++ b/modules/gdnative/godot/gdnative.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot.cpp */ +/* gdnative.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,13 +27,14 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot.h" +#include "gdnative.h" #include "class_db.h" #include "error_macros.h" #include "gdnative.h" -#include "global_config.h" #include "global_constants.h" +#include "os/os.h" +#include "project_settings.h" #include "variant.h" #ifdef __cplusplus @@ -79,13 +80,6 @@ void _api_anchor() { _variant_api_anchor(); } -extern "C++" { -template <class a, class b> -_FORCE_INLINE_ a memcast(b v) { - return *((a *)&v); -} -} - void GDAPI godot_object_destroy(godot_object *p_o) { memdelete((Object *)p_o); } @@ -93,9 +87,13 @@ void GDAPI godot_object_destroy(godot_object *p_o) { // Singleton API godot_object GDAPI *godot_global_get_singleton(char *p_name) { - return (godot_object *)GlobalConfig::get_singleton()->get_singleton_object(String(p_name)); + return (godot_object *)ProjectSettings::get_singleton()->get_singleton_object(String(p_name)); } // result shouldn't be freed +void GDAPI *godot_get_stack_bottom() { + return OS::get_singleton()->get_stack_bottom(); +} + // MethodBind API godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname) { @@ -142,65 +140,6 @@ void GDAPI godot_method_bind_varcall(godot_method_bind *p_method_bind) } */ -// Script API - -void GDAPI godot_script_register_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_script(p_name, p_base, p_create_func, p_destroy_func); -} - -void GDAPI godot_script_register_tool_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_tool_script(p_name, p_base, p_create_func, p_destroy_func); -} - -void GDAPI godot_script_register_method(const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_script_method(p_name, p_function_name, p_attr, p_method, MethodInfo()); -} - -void GDAPI godot_script_register_property(const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - - library->_register_script_property(p_name, p_path, p_attr, p_set_func, p_get_func); -} - -void GDAPI godot_script_register_signal(const char *p_name, const godot_signal *p_signal) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - - library->_register_script_signal(p_name, p_signal); -} - -void GDAPI *godot_native_get_userdata(godot_object *p_instance) { - Object *instance = (Object *)p_instance; - if (!instance) - return NULL; - if (instance->get_script_instance() && instance->get_script_instance()->get_language() == GDNativeScriptLanguage::get_singleton()) { - return ((GDNativeInstance *)instance->get_script_instance())->get_userdata(); - } - return NULL; -} - godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname) { ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); if (class_info) diff --git a/modules/gdnative/godot/gdnative.h b/modules/gdnative/godot/gdnative.h new file mode 100644 index 0000000000..b0343272ef --- /dev/null +++ b/modules/gdnative/godot/gdnative.h @@ -0,0 +1,303 @@ +/*************************************************************************/ +/* gdnative.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 GODOT_GDNATIVE_H +#define GODOT_GDNATIVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef GDAPI_BUILT_IN +#define GDAPI_EXPORT +#endif + +#ifdef _WIN32 +#if defined(GDAPI_EXPORT) +#define GDCALLINGCONV +#define GDAPI __declspec(dllexport) GDCALLINGCONV +#else +#define GDCALLINGCONV +#define GDAPI __declspec(dllimport) GDCALLINGCONV +#endif +#elif defined(__APPLE__) +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE +#define GDCALLINGCONV +#define GDAPI +#elif TARGET_OS_MAC +#define GDCALLINGCONV __attribute__((sysv_abi)) +#define GDAPI GDCALLINGCONV +#endif +#else +#define GDCALLINGCONV __attribute__((sysv_abi)) +#define GDAPI GDCALLINGCONV +#endif + +// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!! +#ifdef _WIN32 +#define GDN_EXPORT __declspec(dllexport) +#else +#define GDN_EXPORT +#endif + +#include <stdbool.h> +#include <stdint.h> + +#define GODOT_API_VERSION 1 + +////// Error + +typedef enum { + GODOT_OK, + GODOT_FAILED, ///< Generic fail error + GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable + GODOT_ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet + GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource + GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5) + GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory + GODOT_ERR_FILE_NOT_FOUND, + GODOT_ERR_FILE_BAD_DRIVE, + GODOT_ERR_FILE_BAD_PATH, + GODOT_ERR_FILE_NO_PERMISSION, // (10) + GODOT_ERR_FILE_ALREADY_IN_USE, + GODOT_ERR_FILE_CANT_OPEN, + GODOT_ERR_FILE_CANT_WRITE, + GODOT_ERR_FILE_CANT_READ, + GODOT_ERR_FILE_UNRECOGNIZED, // (15) + GODOT_ERR_FILE_CORRUPT, + GODOT_ERR_FILE_MISSING_DEPENDENCIES, + GODOT_ERR_FILE_EOF, + GODOT_ERR_CANT_OPEN, ///< Can't open a resource/socket/file + GODOT_ERR_CANT_CREATE, // (20) + GODOT_ERR_QUERY_FAILED, + GODOT_ERR_ALREADY_IN_USE, + GODOT_ERR_LOCKED, ///< resource is locked + GODOT_ERR_TIMEOUT, + GODOT_ERR_CANT_CONNECT, // (25) + GODOT_ERR_CANT_RESOLVE, + GODOT_ERR_CONNECTION_ERROR, + GODOT_ERR_CANT_AQUIRE_RESOURCE, + GODOT_ERR_CANT_FORK, + GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30) + GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid + GODOT_ERR_ALREADY_EXISTS, ///< When adding, item already exists + GODOT_ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist + GODOT_ERR_DATABASE_CANT_READ, ///< database is full + GODOT_ERR_DATABASE_CANT_WRITE, ///< database is full (35) + GODOT_ERR_COMPILATION_FAILED, + GODOT_ERR_METHOD_NOT_FOUND, + GODOT_ERR_LINK_FAILED, + GODOT_ERR_SCRIPT_FAILED, + GODOT_ERR_CYCLIC_LINK, // (40) + GODOT_ERR_INVALID_DECLARATION, + GODOT_ERR_DUPLICATE_SYMBOL, + GODOT_ERR_PARSE_ERROR, + GODOT_ERR_BUSY, + GODOT_ERR_SKIP, // (45) + GODOT_ERR_HELP, ///< user requested help!! + GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. + GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames + GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though + GODOT_ERR_WTF = GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above +} godot_error; + +////// bool + +typedef bool godot_bool; + +#define GODOT_TRUE 1 +#define GODOT_FALSE 0 + +/////// int + +typedef int godot_int; + +/////// real + +typedef float godot_real; + +/////// Object (forward declared) +typedef void godot_object; + +/////// Brute force forward declarations for the rest +/* +typedef struct godot_variant godot_variant; +typedef struct godot_string godot_string; +typedef struct godot_vector2 godot_vector2; +typedef struct godot_rect2 godot_rect2; +typedef struct godot_vector3 godot_vector3; +typedef struct godot_transform2d godot_transform2d; +typedef struct godot_plane godot_plane; +typedef struct godot_quat godot_quat; +typedef struct godot_rect3 godot_rect3; +typedef struct godot_basis godot_basis; +typedef struct godot_transform godot_transform; +typedef struct godot_color godot_color; +typedef struct godot_node_path godot_node_path; +typedef struct godot_rid godot_rid; +typedef struct godot_dictionary godot_dictionary; +typedef struct godot_array godot_array; +typedef struct godot_pool_byte_array godot_pool_byte_array; +typedef struct godot_pool_int_array godot_pool_int_array; +typedef struct godot_pool_real_array godot_pool_real_array; +typedef struct godot_pool_string_array godot_pool_string_array; +typedef struct godot_pool_vector2_array godot_pool_vector2_array; +typedef struct godot_pool_vector3_array godot_pool_vector3_array; +typedef struct godot_pool_color_array godot_pool_color_array; +*/ +/////// String + +#include "string.h" + +////// Vector2 + +#include "vector2.h" + +////// Rect2 + +#include "rect2.h" + +////// Vector3 + +#include "vector3.h" + +////// Transform2D + +#include "transform2d.h" + +/////// Plane + +#include "plane.h" + +/////// Quat + +#include "quat.h" + +/////// Rect3 + +#include "rect3.h" + +/////// Basis + +#include "basis.h" + +/////// Transform + +#include "transform.h" + +/////// Color + +#include "color.h" + +/////// NodePath + +#include "node_path.h" + +/////// RID + +#include "rid.h" + +/////// Dictionary + +#include "dictionary.h" + +/////// Array + +#include "array.h" + +// single API file for Pool*Array +#include "pool_arrays.h" + +void GDAPI godot_object_destroy(godot_object *p_o); + +////// Variant + +#include "variant.h" + +////// Singleton API + +godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed + +////// OS API + +void GDAPI *godot_get_stack_bottom(); // returns stack bottom of the main thread + +////// MethodBind API + +typedef struct { + uint8_t _dont_touch_that[1]; // TODO +} godot_method_bind; + +godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname); +void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret); +godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error); +////// Script API + +typedef struct { + godot_bool in_editor; + uint64_t core_api_hash; + uint64_t editor_api_hash; + uint64_t no_api_hash; + godot_object *gd_native_library; // pointer to GDNativeLibrary that is being initialized +} godot_gdnative_init_options; + +typedef struct { + godot_bool in_editor; +} godot_gdnative_terminate_options; + +// Calling convention? +typedef godot_object *(*godot_class_constructor)(); + +godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname); + +godot_dictionary GDAPI godot_get_global_constants(); + +////// GDNative procedure types +typedef void (*godot_gdnative_init_fn)(godot_gdnative_init_options *); +typedef void (*godot_gdnative_terminate_fn)(godot_gdnative_terminate_options *); +typedef godot_variant (*godot_gdnative_procedure_fn)(void *, godot_array *); + +////// System Functions + +//using these will help Godot track how much memory is in use in debug mode +void GDAPI *godot_alloc(int p_bytes); +void GDAPI *godot_realloc(void *p_ptr, int p_bytes); +void GDAPI godot_free(void *p_ptr); + +//print using Godot's error handler list +void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line); +void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line); +void GDAPI godot_print(const godot_string *p_message); + +#ifdef __cplusplus +} +#endif + +#endif // GODOT_C_H diff --git a/modules/gdnative/godot/icon.png.import b/modules/gdnative/godot/icon.png.import new file mode 100644 index 0000000000..27920124f9 --- /dev/null +++ b/modules/gdnative/godot/icon.png.import @@ -0,0 +1,23 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-aa47d037a37fb38b3b7e7828e4eec407.stex" + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +stream=false +size_limit=0 +detect_3d=true diff --git a/modules/gdnative/godot/godot_node_path.cpp b/modules/gdnative/godot/node_path.cpp index c8eacd05af..a9edbc8352 100644 --- a/modules/gdnative/godot/godot_node_path.cpp +++ b/modules/gdnative/godot/node_path.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_node_path.cpp */ +/* node_path.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_node_path.h" +#include "node_path.h" #include "core/variant.h" #include "core/path_db.h" diff --git a/modules/gdnative/godot/godot_node_path.h b/modules/gdnative/godot/node_path.h index b0c9d44859..06955a052e 100644 --- a/modules/gdnative/godot/godot_node_path.h +++ b/modules/gdnative/godot/node_path.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_node_path.h */ +/* node_path.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_NODE_PATH_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED #define GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED -typedef struct godot_node_path { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_NODE_PATH_SIZE]; } godot_node_path; #endif -#include "../godot.h" -#include "godot_string.h" +#include "gdnative.h" +#include "string.h" void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from); void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src); diff --git a/modules/gdnative/godot/godot_plane.cpp b/modules/gdnative/godot/plane.cpp index 68adbd4a98..e9e659e5da 100644 --- a/modules/gdnative/godot/godot_plane.cpp +++ b/modules/gdnative/godot/plane.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_plane.cpp */ +/* plane.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_plane.h" +#include "plane.h" #include "core/variant.h" #include "core/math/plane.h" diff --git a/modules/gdnative/godot/godot_plane.h b/modules/gdnative/godot/plane.h index cfc955f277..e9e3b71e03 100644 --- a/modules/gdnative/godot/godot_plane.h +++ b/modules/gdnative/godot/plane.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_plane.h */ +/* plane.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_PLANE_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED #define GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED -typedef struct godot_plane { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_PLANE_SIZE]; } godot_plane; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "vector3.h" void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d); void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3); diff --git a/modules/gdnative/godot/godot_pool_arrays.cpp b/modules/gdnative/godot/pool_arrays.cpp index ea9aceea81..6a6ee0f126 100644 --- a/modules/gdnative/godot/godot_pool_arrays.cpp +++ b/modules/gdnative/godot/pool_arrays.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_pool_arrays.cpp */ +/* pool_arrays.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,11 +27,15 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_pool_arrays.h" +#include "pool_arrays.h" #include "array.h" +#include "core/variant.h" #include "dvector.h" -#include "variant.h" + +#include "core/color.h" +#include "core/math/math_2d.h" +#include "core/math/vector3.h" #ifdef __cplusplus extern "C" { diff --git a/modules/gdnative/godot/godot_pool_arrays.h b/modules/gdnative/godot/pool_arrays.h index a794d03f01..1e2916cea9 100644 --- a/modules/gdnative/godot/godot_pool_arrays.h +++ b/modules/gdnative/godot/pool_arrays.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_pool_arrays.h */ +/* pool_arrays.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -38,66 +38,87 @@ extern "C" { /////// PoolByteArray +#define GODOT_POOL_BYTE_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED -typedef struct godot_pool_byte_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_BYTE_ARRAY_SIZE]; } godot_pool_byte_array; #endif /////// PoolIntArray +#define GODOT_POOL_INT_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED -typedef struct godot_pool_int_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_INT_ARRAY_SIZE]; } godot_pool_int_array; #endif /////// PoolRealArray +#define GODOT_POOL_REAL_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED -typedef struct godot_pool_real_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_REAL_ARRAY_SIZE]; } godot_pool_real_array; #endif /////// PoolStringArray +#define GODOT_POOL_STRING_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED -typedef struct godot_pool_string_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_STRING_ARRAY_SIZE]; } godot_pool_string_array; #endif /////// PoolVector2Array +#define GODOT_POOL_VECTOR2_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED -typedef struct godot_pool_vector2_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_VECTOR2_ARRAY_SIZE]; } godot_pool_vector2_array; #endif /////// PoolVector3Array +#define GODOT_POOL_VECTOR3_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED -typedef struct godot_pool_vector3_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_VECTOR3_ARRAY_SIZE]; } godot_pool_vector3_array; #endif /////// PoolColorArray +#define GODOT_POOL_COLOR_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED -typedef struct godot_pool_color_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_COLOR_ARRAY_SIZE]; } godot_pool_color_array; #endif -#include "godot_array.h" -#include "godot_color.h" -#include "godot_vector2.h" -#include "godot_vector3.h" +#include "array.h" +#include "color.h" +#include "vector2.h" +#include "vector3.h" -#include "../godot.h" +#include "gdnative.h" // byte diff --git a/modules/gdnative/godot/godot_quat.cpp b/modules/gdnative/godot/quat.cpp index 7235e4fcec..6800f7fc7e 100644 --- a/modules/gdnative/godot/godot_quat.cpp +++ b/modules/gdnative/godot/quat.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_quat.cpp */ +/* quat.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_quat.h" +#include "quat.h" #include "core/variant.h" #include "core/math/quat.h" diff --git a/modules/gdnative/godot/godot_quat.h b/modules/gdnative/godot/quat.h index 2289b6cbab..b86cbacc62 100644 --- a/modules/gdnative/godot/godot_quat.h +++ b/modules/gdnative/godot/quat.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_quat.h */ +/* quat.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_QUAT_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED #define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED -typedef struct godot_quat { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_QUAT_SIZE]; } godot_quat; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "vector3.h" void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w); void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle); diff --git a/modules/gdnative/godot/godot_rect2.cpp b/modules/gdnative/godot/rect2.cpp index 0e456ea3ba..830d7bb496 100644 --- a/modules/gdnative/godot/godot_rect2.cpp +++ b/modules/gdnative/godot/rect2.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect2.cpp */ +/* rect2.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rect2.h" +#include "rect2.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_rect2.h b/modules/gdnative/godot/rect2.h index 488a1204f7..7b6613d9dd 100644 --- a/modules/gdnative/godot/godot_rect2.h +++ b/modules/gdnative/godot/rect2.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect2.h */ +/* rect2.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -43,8 +43,8 @@ typedef struct godot_rect2 { } godot_rect2; #endif -#include "../godot.h" -#include "godot_vector2.h" +#include "gdnative.h" +#include "vector2.h" void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size); void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height); diff --git a/modules/gdnative/godot/godot_rect3.cpp b/modules/gdnative/godot/rect3.cpp index e524fa8463..0fabba5b7b 100644 --- a/modules/gdnative/godot/godot_rect3.cpp +++ b/modules/gdnative/godot/rect3.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect3.cpp */ +/* rect3.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rect3.h" +#include "rect3.h" #include "core/variant.h" #include "core/math/rect3.h" diff --git a/modules/gdnative/godot/godot_rect3.h b/modules/gdnative/godot/rect3.h index 9e9a49ac27..638d89f76f 100644 --- a/modules/gdnative/godot/godot_rect3.h +++ b/modules/gdnative/godot/rect3.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect3.h */ +/* rect3.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_RECT3_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_RECT3_TYPE_DEFINED #define GODOT_CORE_API_GODOT_RECT3_TYPE_DEFINED -typedef struct godot_rect3 { - uint8_t _dont_touch_that[24]; +typedef struct { + uint8_t _dont_touch_that[GODOT_RECT3_SIZE]; } godot_rect3; #endif -#include "../godot.h" -#include "godot_plane.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "plane.h" +#include "vector3.h" void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size); diff --git a/modules/gdnative/godot/godot_rid.cpp b/modules/gdnative/godot/rid.cpp index 343c004bff..2b724e554d 100644 --- a/modules/gdnative/godot/godot_rid.cpp +++ b/modules/gdnative/godot/rid.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rid.cpp */ +/* rid.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rid.h" +#include "rid.h" #include "core/variant.h" #include "core/resource.h" diff --git a/modules/gdnative/godot/godot_rid.h b/modules/gdnative/godot/rid.h index 25dc8d965e..92e101fd2e 100644 --- a/modules/gdnative/godot/godot_rid.h +++ b/modules/gdnative/godot/rid.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rid.h */ +/* rid.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,14 +36,16 @@ extern "C" { #include <stdint.h> +#define GODOT_RID_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_RID_TYPE_DEFINED #define GODOT_CORE_API_GODOT_RID_TYPE_DEFINED -typedef struct godot_rid { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_RID_SIZE]; } godot_rid; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_rid_new(godot_rid *r_dest); diff --git a/modules/gdnative/godot/godot_string.cpp b/modules/gdnative/godot/string.cpp index 679011e715..e54ef3655f 100644 --- a/modules/gdnative/godot/godot_string.cpp +++ b/modules/gdnative/godot/string.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_string.cpp */ +/* string.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_string.h" +#include "string.h" #include "string_db.h" #include "ustring.h" diff --git a/modules/gdnative/godot/godot_string.h b/modules/gdnative/godot/string.h index df848abb76..d4d6d6c1d0 100644 --- a/modules/gdnative/godot/godot_string.h +++ b/modules/gdnative/godot/string.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_string.h */ +/* string.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -37,13 +37,16 @@ extern "C" { #include <stdint.h> #include <wchar.h> +#define GODOT_STRING_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED -typedef struct godot_string { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_STRING_SIZE]; } godot_string; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_string_new(godot_string *r_dest); void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); diff --git a/modules/gdnative/godot/godot_transform.cpp b/modules/gdnative/godot/transform.cpp index eb9e1e207b..e566ed0b6e 100644 --- a/modules/gdnative/godot/godot_transform.cpp +++ b/modules/gdnative/godot/transform.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform.cpp */ +/* transform.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_transform.h" +#include "transform.h" #include "core/variant.h" #include "core/math/transform.h" diff --git a/modules/gdnative/godot/godot_transform.h b/modules/gdnative/godot/transform.h index ee87e1d33f..d14190ec49 100644 --- a/modules/gdnative/godot/godot_transform.h +++ b/modules/gdnative/godot/transform.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform.h */ +/* transform.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,17 +36,19 @@ extern "C" { #include <stdint.h> +#define GODOT_TRANSFORM_SIZE 48 + #ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED #define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED -typedef struct godot_transform { - uint8_t _dont_touch_that[48]; +typedef struct { + uint8_t _dont_touch_that[GODOT_TRANSFORM_SIZE]; } godot_transform; #endif -#include "../godot.h" -#include "godot_basis.h" -#include "godot_variant.h" -#include "godot_vector3.h" +#include "basis.h" +#include "gdnative.h" +#include "variant.h" +#include "vector3.h" void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin); void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin); diff --git a/modules/gdnative/godot/godot_transform2d.cpp b/modules/gdnative/godot/transform2d.cpp index bdb5476f7d..01db3f7ae0 100644 --- a/modules/gdnative/godot/godot_transform2d.cpp +++ b/modules/gdnative/godot/transform2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform2d.cpp */ +/* transform2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_transform2d.h" +#include "transform2d.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_transform2d.h b/modules/gdnative/godot/transform2d.h index c375e90af7..7171e528f2 100644 --- a/modules/gdnative/godot/godot_transform2d.h +++ b/modules/gdnative/godot/transform2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform2d.h */ +/* transform2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_TRANSFORM2D_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED #define GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED -typedef struct godot_transform2d { - uint8_t _dont_touch_that[24]; +typedef struct { + uint8_t _dont_touch_that[GODOT_TRANSFORM2D_SIZE]; } godot_transform2d; #endif -#include "../godot.h" -#include "godot_variant.h" -#include "godot_vector2.h" +#include "gdnative.h" +#include "variant.h" +#include "vector2.h" void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos); void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin); diff --git a/modules/gdnative/godot/godot_variant.cpp b/modules/gdnative/godot/variant.cpp index c9607fb21a..3469058cfd 100644 --- a/modules/gdnative/godot/godot_variant.cpp +++ b/modules/gdnative/godot/variant.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_variant.cpp */ +/* variant.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_variant.h" +#include "variant.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/godot/godot_variant.h b/modules/gdnative/godot/variant.h index 9b6d287249..b56d5824fa 100644 --- a/modules/gdnative/godot/godot_variant.h +++ b/modules/gdnative/godot/variant.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_variant.h */ +/* variant.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,9 +36,12 @@ extern "C" { #include <stdint.h> +#define GODOT_VARIANT_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED -typedef struct godot_variant { - uint8_t _dont_touch_that[24]; +#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_VARIANT_SIZE]; } godot_variant; #endif @@ -96,25 +99,25 @@ typedef struct godot_variant_call_error { godot_variant_type expected; } godot_variant_call_error; -#include "godot_array.h" -#include "godot_basis.h" -#include "godot_color.h" -#include "godot_dictionary.h" -#include "godot_node_path.h" -#include "godot_plane.h" -#include "godot_pool_arrays.h" -#include "godot_quat.h" -#include "godot_rect2.h" -#include "godot_rect3.h" -#include "godot_rid.h" -#include "godot_string.h" -#include "godot_transform.h" -#include "godot_transform2d.h" -#include "godot_variant.h" -#include "godot_vector2.h" -#include "godot_vector3.h" - -#include "../godot.h" +#include "array.h" +#include "basis.h" +#include "color.h" +#include "dictionary.h" +#include "node_path.h" +#include "plane.h" +#include "pool_arrays.h" +#include "quat.h" +#include "rect2.h" +#include "rect3.h" +#include "rid.h" +#include "string.h" +#include "transform.h" +#include "transform2d.h" +#include "variant.h" +#include "vector2.h" +#include "vector3.h" + +#include "gdnative.h" godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v); diff --git a/modules/gdnative/godot/godot_vector2.cpp b/modules/gdnative/godot/vector2.cpp index 0ced800872..6b40e31a89 100644 --- a/modules/gdnative/godot/godot_vector2.cpp +++ b/modules/gdnative/godot/vector2.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector2.cpp */ +/* vector2.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_vector2.h" +#include "vector2.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_vector2.h b/modules/gdnative/godot/vector2.h index 9c7590fedf..9934ddadbb 100644 --- a/modules/gdnative/godot/godot_vector2.h +++ b/modules/gdnative/godot/vector2.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector2.h */ +/* vector2.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,14 +36,16 @@ extern "C" { #include <stdint.h> +#define GODOT_VECTOR2_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED #define GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED -typedef struct godot_vector2 { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_VECTOR2_SIZE]; } godot_vector2; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y); diff --git a/modules/gdnative/godot/godot_vector3.cpp b/modules/gdnative/godot/vector3.cpp index f9942af6e5..904cdad9d0 100644 --- a/modules/gdnative/godot/godot_vector3.cpp +++ b/modules/gdnative/godot/vector3.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector3.cpp */ +/* vector3.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_vector3.h" +#include "vector3.h" #include "core/variant.h" #include "core/vector.h" @@ -90,11 +90,12 @@ godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self) { return dest; } -godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by) { +godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by) { godot_vector3 dest; const Vector3 *self = (const Vector3 *)p_self; + const Vector3 *snap_axis = (const Vector3 *)p_by; - *((Vector3 *)&dest) = self->snapped(p_by); + *((Vector3 *)&dest) = self->snapped(*snap_axis); return dest; } diff --git a/modules/gdnative/godot/godot_vector3.h b/modules/gdnative/godot/vector3.h index 8e2aed8173..b5f8d0f49a 100644 --- a/modules/gdnative/godot/godot_vector3.h +++ b/modules/gdnative/godot/vector3.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector3.h */ +/* vector3.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_VECTOR3_SIZE 12 + #ifndef GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED #define GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED -typedef struct godot_vector3 { - uint8_t _dont_touch_that[12]; +typedef struct { + uint8_t _dont_touch_that[GODOT_VECTOR3_SIZE]; } godot_vector3; #endif -#include "../godot.h" -#include "godot_basis.h" +#include "basis.h" +#include "gdnative.h" typedef enum { GODOT_VECTOR3_AXIS_X, @@ -70,7 +72,7 @@ godot_vector3 GDAPI godot_vector3_normalized(const godot_vector3 *p_self); godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self); -godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by); +godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by); godot_vector3 GDAPI godot_vector3_rotated(const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi); diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 8789c9a267..d180d5aada 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -33,34 +33,47 @@ #include "io/resource_loader.h" #include "io/resource_saver.h" -GDNativeScriptLanguage *script_language_gdn = NULL; -ResourceFormatLoaderGDNativeScript *resource_loader_gdn = NULL; -ResourceFormatSaverGDNativeScript *resource_saver_gdn = NULL; -//ResourceFormatLoaderDLLibrary *resource_loader_dllib=NULL; +#include "core/os/os.h" -void register_gdnative_types() { +godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) { + if (handle == NULL) { + ERR_PRINT("No valid library handle, can't call standard varcall procedure"); + godot_variant ret; + godot_variant_new_nil(&ret); + return ret; + } - ClassDB::register_class<GDNativeLibrary>(); - ClassDB::register_class<GDNativeScript>(); + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + handle, + *(String *)p_procedure, + library_proc, + true); // we roll our own message + if (err != OK) { + ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data()); + godot_variant ret; + godot_variant_new_nil(&ret); + return ret; + } + + godot_gdnative_procedure_fn proc; + proc = (godot_gdnative_procedure_fn)library_proc; - script_language_gdn = memnew(GDNativeScriptLanguage); - ScriptServer::register_language(script_language_gdn); - resource_loader_gdn = memnew(ResourceFormatLoaderGDNativeScript); - ResourceLoader::add_resource_format_loader(resource_loader_gdn); - resource_saver_gdn = memnew(ResourceFormatSaverGDNativeScript); - ResourceSaver::add_resource_format_saver(resource_saver_gdn); + return proc(NULL, p_args); } -void unregister_gdnative_types() { +GDNativeCallRegistry *GDNativeCallRegistry::singleton; - ScriptServer::unregister_language(script_language_gdn); +void register_gdnative_types() { - if (script_language_gdn) - memdelete(script_language_gdn); + ClassDB::register_class<GDNativeLibrary>(); + ClassDB::register_class<GDNative>(); + + GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry); - if (resource_loader_gdn) - memdelete(resource_loader_gdn); + GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); +} - if (resource_saver_gdn) - memdelete(resource_saver_gdn); +void unregister_gdnative_types() { + memdelete(GDNativeCallRegistry::singleton); } diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index adf3c8edc4..c88889767c 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -30,8 +30,8 @@ #include "editor/editor_settings.h" #include "gd_compiler.h" #include "gd_script.h" -#include "global_config.h" #include "os/file_access.h" +#include "project_settings.h" #ifdef TOOLS_ENABLED #include "editor/editor_file_system.h" #include "editor/editor_settings.h" @@ -638,7 +638,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: String which = arg1.get_slice("/", 2); if (which != "") { List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); //print_line("find singleton"); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -650,7 +650,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: String name = s.get_slice("/", 1); //print_line("name: "+name+", which: "+which); if (name == which) { - String script = GlobalConfig::get_singleton()->get(s); + String script = ProjectSettings::get_singleton()->get(s); if (!script.begins_with("res://")) { script = "res://" + script; @@ -1105,7 +1105,7 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con //autoloads as singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -1115,7 +1115,7 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con String name = s.get_slice("/", 1); if (name == String(p_identifier)) { - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { String script = path.substr(1, path.length()); @@ -1334,8 +1334,8 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o static const char *_type_names[Variant::VARIANT_MAX] = { "null", "bool", "int", "float", "String", "Vector2", "Rect2", "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", - "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "RawArray", "IntArray", "FloatArray", "StringArray", - "Vector2Array", "Vector3Array", "ColorArray" + "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", + "PoolVector2Array", "PoolVector3Array", "PoolColorArray" }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { @@ -1344,7 +1344,7 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o //autoload singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -1352,7 +1352,7 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o if (!s.begins_with("autoload/")) continue; String name = s.get_slice("/", 1); - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { result.insert(name); } @@ -1685,7 +1685,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N if (p_argidx == 0 && (String(p_method) == "get_node" || String(p_method) == "has_node") && ClassDB::is_parent_class(id.obj_type, "Node")) { List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -2660,7 +2660,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol //guess in autoloads as singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -2670,7 +2670,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol String name = s.get_slice("/", 1); if (name == String(p_symbol)) { - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { String script = path.substr(1, path.length()); diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index e8a8e20927..795371af60 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -1428,8 +1428,24 @@ Variant GDFunctionState::_signal_callback(const Variant **p_args, int p_argcount state.result = arg; Variant ret = function->call(NULL, NULL, 0, r_error, &state); + + bool completed = true; + + // If the return value is a GDFunctionState reference, + // then the function did yield again after resuming. + if (ret.is_ref()) { + GDFunctionState *gdfs = ret.operator Object *()->cast_to<GDFunctionState>(); + if (gdfs && gdfs->function == function) + completed = false; + } + function = NULL; //cleaned up; state.result = Variant(); + + if (completed) { + emit_signal("completed", ret); + } + return ret; } @@ -1468,8 +1484,24 @@ Variant GDFunctionState::resume(const Variant &p_arg) { state.result = p_arg; Variant::CallError err; Variant ret = function->call(NULL, NULL, 0, err, &state); + + bool completed = true; + + // If the return value is a GDFunctionState reference, + // then the function did yield again after resuming. + if (ret.is_ref()) { + GDFunctionState *gdfs = ret.operator Object *()->cast_to<GDFunctionState>(); + if (gdfs && gdfs->function == function) + completed = false; + } + function = NULL; //cleaned up; state.result = Variant(); + + if (completed) { + emit_signal("completed", ret); + } + return ret; } @@ -1478,6 +1510,8 @@ void GDFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("resume:Variant", "arg"), &GDFunctionState::resume, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDFunctionState::is_valid, DEFVAL(false)); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDFunctionState::_signal_callback, MethodInfo("_signal_callback")); + + ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result"))); } GDFunctionState::GDFunctionState() { diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index a361971ef4..8bc3b24a5e 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -1587,13 +1587,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { } break; case TO_JSON: { - MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var:Variant")); + MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var")); mi.return_val.type = Variant::STRING; return mi; } break; case HASH: { - MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var:Variant")); + MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var")); mi.return_val.type = Variant::INT; return mi; } break; diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 75029a020b..36aa249398 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -185,8 +185,8 @@ void GDParser::_make_completable_call(int p_arg) { bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &identifier) { identifier = StringName(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal()) { + identifier = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() == GDTokenizer::TK_CURSOR) { @@ -201,8 +201,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &id completion_ident_is_call = false; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = identifier.operator String() + tokenizer->get_token_identifier().operator String(); + if (tokenizer->is_token_literal()) { + identifier = identifier.operator String() + tokenizer->get_token_literal().operator String(); tokenizer->advance(); } @@ -296,17 +296,6 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool need_identifier = false; } break; - case GDTokenizer::TK_IDENTIFIER: { - if (!need_identifier) { - done = true; - break; - } - - path += String(tokenizer->get_token_identifier()); - tokenizer->advance(); - need_identifier = false; - - } break; case GDTokenizer::TK_OP_DIV: { if (need_identifier) { @@ -320,7 +309,15 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool } break; default: { - done = true; + // Instead of checking for TK_IDENTIFIER, we check with is_token_literal, as this allows us to use match/sync/etc. as a name + if (need_identifier && tokenizer->is_token_literal()) { + path += String(tokenizer->get_token_literal()); + tokenizer->advance(); + need_identifier = false; + } else { + done = true; + } + break; } } @@ -585,7 +582,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool cn->value = Variant::get_numeric_constant_value(bi_type, identifier); expr = cn; - } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_FUNC)) { + } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //function or constructor OperatorNode *op = alloc_node<OperatorNode>(); @@ -627,7 +625,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = op; - } else if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { + } else if (tokenizer->is_token_literal(0, true)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //identifier (reference) const ClassNode *cln = current_class; @@ -827,10 +826,11 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool if (expecting == DICT_EXPECT_KEY) { - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->is_token_literal() && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //lua style identifier, easier to write ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = tokenizer->get_token_identifier(); + cn->value = tokenizer->get_token_literal(); key = cn; tokenizer->advance(2); expecting = DICT_EXPECT_VALUE; @@ -870,7 +870,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = dict; - } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->get_token(1) == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name // parent call tokenizer->advance(); //goto identifier @@ -922,7 +923,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool //indexing using "." - if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && tokenizer->get_token(1) != GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) != GDTokenizer::TK_BUILT_IN_FUNC) { + if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name _set_error("Expected identifier as member"); return NULL; } else if (tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { @@ -2341,12 +2343,12 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { //variale declaration and (eventual) initialization tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for local variable name."); return; } - StringName n = tokenizer->get_token_identifier(); + StringName n = tokenizer->get_token_literal(); tokenizer->advance(); if (current_function) { for (int i = 0; i < current_function->arguments.size(); i++) { @@ -2571,7 +2573,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("identifier expected after 'for'"); } @@ -3108,7 +3110,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); //var before the identifier is allowed } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for argument."); return; @@ -3260,7 +3262,7 @@ void GDParser::_parse_class(ClassNode *p_class) { case GDTokenizer::TK_PR_SIGNAL: { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier after 'signal'."); return; } @@ -3282,7 +3284,7 @@ void GDParser::_parse_class(ClassNode *p_class) { break; } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier in signal argument."); return; } @@ -3847,13 +3849,13 @@ void GDParser::_parse_class(ClassNode *p_class) { bool onready = tokenizer->get_token(-1) == GDTokenizer::TK_PR_ONREADY; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for member variable name."); return; } - member.identifier = tokenizer->get_token_identifier(); + member.identifier = tokenizer->get_token_literal(); member.expression = NULL; member._export.name = member.identifier; member.line = tokenizer->get_token_line(); @@ -3979,11 +3981,11 @@ void GDParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() != GDTokenizer::TK_COMMA) { //just comma means using only getter - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { - _set_error("Expected identifier for setter function after 'notify'."); + if (!tokenizer->is_token_literal()) { + _set_error("Expected identifier for setter function after 'setget'."); } - member.setter = tokenizer->get_token_identifier(); + member.setter = tokenizer->get_token_literal(); tokenizer->advance(); } @@ -3992,11 +3994,11 @@ void GDParser::_parse_class(ClassNode *p_class) { //there is a getter tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier for getter function after ','."); } - member.getter = tokenizer->get_token_identifier(); + member.getter = tokenizer->get_token_literal(); tokenizer->advance(); } } @@ -4014,13 +4016,13 @@ void GDParser::_parse_class(ClassNode *p_class) { ClassNode::Constant constant; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected name (identifier) for constant."); return; } - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); if (tokenizer->get_token() != GDTokenizer::TK_OP_ASSIGN) { @@ -4061,8 +4063,8 @@ void GDParser::_parse_class(ClassNode *p_class) { Dictionary enum_dict; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - enum_name = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal(0, true)) { + enum_name = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() != GDTokenizer::TK_CURLY_BRACKET_OPEN) { @@ -4079,7 +4081,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); break; // End of enum - } else if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + } else if (!tokenizer->is_token_literal(0, true)) { if (tokenizer->get_token() == GDTokenizer::TK_EOF) { _set_error("Unexpected end of file."); @@ -4088,10 +4090,10 @@ void GDParser::_parse_class(ClassNode *p_class) { } return; - } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER + } else { // tokenizer->is_token_literal(0, true) ClassNode::Constant constant; - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 1dcc442234..fe87433a89 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -29,11 +29,11 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" -#include "global_config.h" #include "global_constants.h" #include "io/file_access_encrypted.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" /////////////////////////// @@ -1454,9 +1454,9 @@ void GDScriptLanguage::init() { //populate singletons - List<GlobalConfig::Singleton> singletons; - GlobalConfig::get_singleton()->get_singletons(&singletons); - for (List<GlobalConfig::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + List<ProjectSettings::Singleton> singletons; + ProjectSettings::get_singleton()->get_singletons(&singletons); + for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { _add_global(E->get().name, E->get().ptr); } @@ -1885,7 +1885,7 @@ GDScriptLanguage::GDScriptLanguage() { script_frame_time = 0; _debug_call_stack_pos = 0; - int dmcs = GLOBAL_DEF("debug/script/max_call_stack", 1024); + int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024); if (ScriptDebugger::get_singleton()) { //debugging enabled! diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index f4e0cc8e29..5803046185 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -130,12 +130,222 @@ const char *GDTokenizer::token_names[TK_MAX] = { "Cursor" }; +struct _bit { + Variant::Type type; + const char *text; +}; +//built in types + +static const _bit _type_list[] = { + //types + { Variant::BOOL, "bool" }, + { Variant::INT, "int" }, + { Variant::REAL, "float" }, + { Variant::STRING, "String" }, + { Variant::VECTOR2, "Vector2" }, + { Variant::RECT2, "Rect2" }, + { Variant::TRANSFORM2D, "Transform2D" }, + { Variant::VECTOR3, "Vector3" }, + { Variant::RECT3, "Rect3" }, + { Variant::PLANE, "Plane" }, + { Variant::QUAT, "Quat" }, + { Variant::BASIS, "Basis" }, + { Variant::TRANSFORM, "Transform" }, + { Variant::COLOR, "Color" }, + { Variant::_RID, "RID" }, + { Variant::OBJECT, "Object" }, + { Variant::NODE_PATH, "NodePath" }, + { Variant::DICTIONARY, "Dictionary" }, + { Variant::ARRAY, "Array" }, + { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, + { Variant::POOL_INT_ARRAY, "PoolIntArray" }, + { Variant::POOL_REAL_ARRAY, "PoolRealArray" }, + { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, + { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, + { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, + { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, + { Variant::VARIANT_MAX, NULL }, +}; + +struct _kws { + GDTokenizer::Token token; + const char *text; +}; + +static const _kws _keyword_list[] = { + //ops + { GDTokenizer::TK_OP_IN, "in" }, + { GDTokenizer::TK_OP_NOT, "not" }, + { GDTokenizer::TK_OP_OR, "or" }, + { GDTokenizer::TK_OP_AND, "and" }, + //func + { GDTokenizer::TK_PR_FUNCTION, "func" }, + { GDTokenizer::TK_PR_CLASS, "class" }, + { GDTokenizer::TK_PR_EXTENDS, "extends" }, + { GDTokenizer::TK_PR_IS, "is" }, + { GDTokenizer::TK_PR_ONREADY, "onready" }, + { GDTokenizer::TK_PR_TOOL, "tool" }, + { GDTokenizer::TK_PR_STATIC, "static" }, + { GDTokenizer::TK_PR_EXPORT, "export" }, + { GDTokenizer::TK_PR_SETGET, "setget" }, + { GDTokenizer::TK_PR_VAR, "var" }, + { GDTokenizer::TK_PR_PRELOAD, "preload" }, + { GDTokenizer::TK_PR_ASSERT, "assert" }, + { GDTokenizer::TK_PR_YIELD, "yield" }, + { GDTokenizer::TK_PR_SIGNAL, "signal" }, + { GDTokenizer::TK_PR_BREAKPOINT, "breakpoint" }, + { GDTokenizer::TK_PR_REMOTE, "remote" }, + { GDTokenizer::TK_PR_MASTER, "master" }, + { GDTokenizer::TK_PR_SLAVE, "slave" }, + { GDTokenizer::TK_PR_SYNC, "sync" }, + { GDTokenizer::TK_PR_CONST, "const" }, + { GDTokenizer::TK_PR_ENUM, "enum" }, + //controlflow + { GDTokenizer::TK_CF_IF, "if" }, + { GDTokenizer::TK_CF_ELIF, "elif" }, + { GDTokenizer::TK_CF_ELSE, "else" }, + { GDTokenizer::TK_CF_FOR, "for" }, + { GDTokenizer::TK_CF_WHILE, "while" }, + { GDTokenizer::TK_CF_DO, "do" }, + { GDTokenizer::TK_CF_SWITCH, "switch" }, + { GDTokenizer::TK_CF_CASE, "case" }, + { GDTokenizer::TK_CF_BREAK, "break" }, + { GDTokenizer::TK_CF_CONTINUE, "continue" }, + { GDTokenizer::TK_CF_RETURN, "return" }, + { GDTokenizer::TK_CF_MATCH, "match" }, + { GDTokenizer::TK_CF_PASS, "pass" }, + { GDTokenizer::TK_SELF, "self" }, + { GDTokenizer::TK_CONST_PI, "PI" }, + { GDTokenizer::TK_WILDCARD, "_" }, + { GDTokenizer::TK_CONST_INF, "INF" }, + { GDTokenizer::TK_CONST_NAN, "NAN" }, + { GDTokenizer::TK_ERROR, NULL } +}; + const char *GDTokenizer::get_token_name(Token p_token) { ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>"); return token_names[p_token]; } +bool GDTokenizer::is_token_literal(int p_offset, bool variable_safe) const { + switch (get_token(p_offset)) { + // Can always be literal: + case TK_IDENTIFIER: + + case TK_PR_ONREADY: + case TK_PR_TOOL: + case TK_PR_STATIC: + case TK_PR_EXPORT: + case TK_PR_SETGET: + case TK_PR_SIGNAL: + case TK_PR_REMOTE: + case TK_PR_MASTER: + case TK_PR_SLAVE: + case TK_PR_SYNC: + return true; + + // Literal for non-variables only: + case TK_BUILT_IN_TYPE: + case TK_BUILT_IN_FUNC: + + case TK_OP_IN: + //case TK_OP_NOT: + //case TK_OP_OR: + //case TK_OP_AND: + + case TK_PR_CLASS: + case TK_PR_CONST: + case TK_PR_ENUM: + case TK_PR_PRELOAD: + case TK_PR_FUNCTION: + case TK_PR_EXTENDS: + case TK_PR_ASSERT: + case TK_PR_YIELD: + case TK_PR_VAR: + + case TK_CF_IF: + case TK_CF_ELIF: + case TK_CF_ELSE: + case TK_CF_FOR: + case TK_CF_WHILE: + case TK_CF_DO: + case TK_CF_SWITCH: + case TK_CF_CASE: + case TK_CF_BREAK: + case TK_CF_CONTINUE: + case TK_CF_RETURN: + case TK_CF_MATCH: + case TK_CF_PASS: + case TK_SELF: + case TK_CONST_PI: + case TK_WILDCARD: + case TK_CONST_INF: + case TK_CONST_NAN: + case TK_ERROR: + return !variable_safe; + + case TK_CONSTANT: { + switch (get_token_constant(p_offset).get_type()) { + case Variant::NIL: + case Variant::BOOL: + return true; + default: + return false; + } + } + default: + return false; + } +} + +StringName GDTokenizer::get_token_literal(int p_offset) const { + Token token = get_token(p_offset); + switch (token) { + case TK_IDENTIFIER: + return get_token_identifier(p_offset); + case TK_BUILT_IN_TYPE: { + Variant::Type type = get_token_type(p_offset); + int idx = 0; + + while (_type_list[idx].text) { + if (type == _type_list[idx].type) { + return _type_list[idx].text; + } + idx++; + } + } break; // Shouldn't get here, stuff happens + case TK_BUILT_IN_FUNC: + return GDFunctions::get_func_name(get_token_built_in_func(p_offset)); + case TK_CONSTANT: { + const Variant value = get_token_constant(p_offset); + + switch (value.get_type()) { + case Variant::NIL: + return "null"; + case Variant::BOOL: + return value ? "true" : "false"; + default: {} + } + } + case TK_OP_AND: + case TK_OP_OR: + break; // Don't get into default, since they can be non-literal + default: { + int idx = 0; + + while (_keyword_list[idx].text) { + if (token == _keyword_list[idx].token) { + return _keyword_list[idx].text; + } + idx++; + } + } + } + ERR_EXPLAIN("Failed to get token literal"); + ERR_FAIL_V(""); +} + static bool _is_text_char(CharType c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; @@ -779,51 +989,14 @@ void GDTokenizerText::_advance() { bool found = false; - struct _bit { - Variant::Type type; - const char *text; - }; - //built in types - - static const _bit type_list[] = { - //types - { Variant::BOOL, "bool" }, - { Variant::INT, "int" }, - { Variant::REAL, "float" }, - { Variant::STRING, "String" }, - { Variant::VECTOR2, "Vector2" }, - { Variant::RECT2, "Rect2" }, - { Variant::TRANSFORM2D, "Transform2D" }, - { Variant::VECTOR3, "Vector3" }, - { Variant::RECT3, "Rect3" }, - { Variant::PLANE, "Plane" }, - { Variant::QUAT, "Quat" }, - { Variant::BASIS, "Basis" }, - { Variant::TRANSFORM, "Transform" }, - { Variant::COLOR, "Color" }, - { Variant::_RID, "RID" }, - { Variant::OBJECT, "Object" }, - { Variant::NODE_PATH, "NodePath" }, - { Variant::DICTIONARY, "Dictionary" }, - { Variant::ARRAY, "Array" }, - { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, - { Variant::POOL_INT_ARRAY, "PoolIntArray" }, - { Variant::POOL_REAL_ARRAY, "PoolFloatArray" }, - { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, - { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, - { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, - { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, - { Variant::VARIANT_MAX, NULL }, - }; - { int idx = 0; - while (type_list[idx].text) { + while (_type_list[idx].text) { - if (str == type_list[idx].text) { - _make_type(type_list[idx].type); + if (str == _type_list[idx].text) { + _make_type(_type_list[idx].type); found = true; break; } @@ -844,74 +1017,18 @@ void GDTokenizerText::_advance() { break; } } - - //keywor } if (!found) { - - struct _kws { - Token token; - const char *text; - }; - - static const _kws keyword_list[] = { - //ops - { TK_OP_IN, "in" }, - { TK_OP_NOT, "not" }, - { TK_OP_OR, "or" }, - { TK_OP_AND, "and" }, - //func - { TK_PR_FUNCTION, "func" }, - { TK_PR_CLASS, "class" }, - { TK_PR_EXTENDS, "extends" }, - { TK_PR_IS, "is" }, - { TK_PR_ONREADY, "onready" }, - { TK_PR_TOOL, "tool" }, - { TK_PR_STATIC, "static" }, - { TK_PR_EXPORT, "export" }, - { TK_PR_SETGET, "setget" }, - { TK_PR_VAR, "var" }, - { TK_PR_PRELOAD, "preload" }, - { TK_PR_ASSERT, "assert" }, - { TK_PR_YIELD, "yield" }, - { TK_PR_SIGNAL, "signal" }, - { TK_PR_BREAKPOINT, "breakpoint" }, - { TK_PR_REMOTE, "remote" }, - { TK_PR_MASTER, "master" }, - { TK_PR_SLAVE, "slave" }, - { TK_PR_SYNC, "sync" }, - { TK_PR_CONST, "const" }, - { TK_PR_ENUM, "enum" }, - //controlflow - { TK_CF_IF, "if" }, - { TK_CF_ELIF, "elif" }, - { TK_CF_ELSE, "else" }, - { TK_CF_FOR, "for" }, - { TK_CF_WHILE, "while" }, - { TK_CF_DO, "do" }, - { TK_CF_SWITCH, "switch" }, - { TK_CF_CASE, "case" }, - { TK_CF_BREAK, "break" }, - { TK_CF_CONTINUE, "continue" }, - { TK_CF_RETURN, "return" }, - { TK_CF_MATCH, "match" }, - { TK_CF_PASS, "pass" }, - { TK_SELF, "self" }, - { TK_CONST_PI, "PI" }, - { TK_WILDCARD, "_" }, - { TK_CONST_INF, "INF" }, - { TK_CONST_NAN, "NAN" }, - { TK_ERROR, NULL } - }; + //keyword int idx = 0; found = false; - while (keyword_list[idx].text) { + while (_keyword_list[idx].text) { - if (str == keyword_list[idx].text) { - _make_token(keyword_list[idx].token); + if (str == _keyword_list[idx].text) { + _make_token(_keyword_list[idx].token); found = true; break; } @@ -992,6 +1109,7 @@ const Variant &GDTokenizerText::get_token_constant(int p_offset) const { ERR_FAIL_COND_V(tk_rb[ofs].type != TK_CONSTANT, tk_rb[0].constant); return tk_rb[ofs].constant; } + StringName GDTokenizerText::get_token_identifier(int p_offset) const { ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, StringName()); diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index c051176097..4e868301a3 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -149,6 +149,9 @@ protected: public: static const char *get_token_name(Token p_token); + bool is_token_literal(int p_offset = 0, bool variable_safe = false) const; + StringName get_token_literal(int p_offset = 0) const; + virtual const Variant &get_token_constant(int p_offset = 0) const = 0; virtual Token get_token(int p_offset = 0) const = 0; virtual StringName get_token_identifier(int p_offset = 0) const = 0; diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 9d3da8227c..8c2c2ea345 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -380,6 +380,7 @@ void GridMap::set_cell_item(int p_x, int p_y, int p_z, int p_item, int p_rot) { ii.multimesh->set_mesh(ii.mesh); ii.multimesh_instance = VS::get_singleton()->instance_create(); VS::get_singleton()->instance_set_base(ii.multimesh_instance, ii.multimesh->get_rid()); + VS::get_singleton()->instance_geometry_set_flag(ii.multimesh_instance, VS::INSTANCE_FLAG_USE_BAKED_LIGHT, true); g.items[p_item] = ii; } diff --git a/modules/nativescript/SCsub b/modules/nativescript/SCsub new file mode 100644 index 0000000000..e980e40e8e --- /dev/null +++ b/modules/nativescript/SCsub @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +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']) + +Export('mod_env') diff --git a/modules/gdnative/api_generator.cpp b/modules/nativescript/api_generator.cpp index d5f22ee7a3..47162bfc49 100644 --- a/modules/gdnative/api_generator.cpp +++ b/modules/nativescript/api_generator.cpp @@ -32,8 +32,8 @@ #ifdef TOOLS_ENABLED #include "class_db.h" -#include "core/global_config.h" #include "core/global_constants.h" +#include "core/project_settings.h" #include "os/file_access.h" // helper stuff @@ -150,7 +150,7 @@ List<ClassAPI> generate_c_api_classes() { if (name.begins_with("_")) { name.remove(0); } - class_api.is_singleton = GlobalConfig::get_singleton()->has_singleton(name); + class_api.is_singleton = ProjectSettings::get_singleton()->has_singleton(name); } class_api.is_instanciable = !class_api.is_singleton && ClassDB::can_instance(class_name); @@ -268,6 +268,8 @@ List<ClassAPI> generate_c_api_classes() { method_api.method_name = method_api.method_name.get_slice(":", 0); } else if (m->get().return_val.type != Variant::NIL) { method_api.return_type = m->get().return_val.hint == PROPERTY_HINT_RESOURCE_TYPE ? m->get().return_val.hint_string : Variant::get_type_name(m->get().return_val.type); + } else if (m->get().return_val.name != "") { + method_api.return_type = m->get().return_val.name; } else { method_api.return_type = "void"; } diff --git a/modules/gdnative/api_generator.h b/modules/nativescript/api_generator.h index a108d7a7b6..a108d7a7b6 100644 --- a/modules/gdnative/api_generator.h +++ b/modules/nativescript/api_generator.h diff --git a/modules/nativescript/config.py b/modules/nativescript/config.py new file mode 100644 index 0000000000..9f57b9bb74 --- /dev/null +++ b/modules/nativescript/config.py @@ -0,0 +1,8 @@ + + +def can_build(platform): + return True + + +def configure(env): + env.use_ptrcall = True diff --git a/modules/nativescript/godot_nativescript.cpp b/modules/nativescript/godot_nativescript.cpp new file mode 100644 index 0000000000..453cee3a18 --- /dev/null +++ b/modules/nativescript/godot_nativescript.cpp @@ -0,0 +1,205 @@ +/*************************************************************************/ +/* godot_nativescript.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 "godot_nativescript.h" + +#include "nativescript.h" + +#include "class_db.h" +#include "error_macros.h" +#include "gdnative.h" +#include "global_constants.h" +#include "project_settings.h" +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern "C" void _native_script_hook() { +} + +#define NSL NativeScriptLanguage::get_singleton() + +// Script API + +void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; + + NativeScriptDesc desc; + + desc.create_func = p_create_func; + desc.destroy_func = p_destroy_func; + desc.is_tool = false; + + desc.base = p_base; + + if (classes->has(p_base)) { + desc.base_data = &(*classes)[p_base]; + desc.base_native_type = desc.base_data->base_native_type; + } else { + desc.base_data = NULL; + desc.base_native_type = p_base; + } + + classes->insert(p_name, desc); +} + +void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; + + NativeScriptDesc desc; + + desc.create_func = p_create_func; + desc.destroy_func = p_destroy_func; + desc.is_tool = true; + desc.base = p_base; + + if (classes->has(p_base)) { + desc.base_data = &(*classes)[p_base]; + desc.base_native_type = desc.base_data->base_native_type; + } else { + desc.base_data = NULL; + desc.base_native_type = p_base; + } + + classes->insert(p_name, desc); +} + +void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + NativeScriptDesc::Method method; + method.method = p_method; + method.rpc_mode = p_attr.rpc_type; + method.info = MethodInfo(p_function_name); + + E->get().methods.insert(p_function_name, method); +} + +void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + NativeScriptDesc::Property property; + property.default_value = *(Variant *)&p_attr->default_value; + property.getter = p_get_func; + property.rset_mode = p_attr->rset_type; + property.setter = p_set_func; + property.info = PropertyInfo((Variant::Type)p_attr->type, + p_path, + (PropertyHint)p_attr->hint, + *(String *)&p_attr->hint_string, + (PropertyUsageFlags)p_attr->usage); + + E->get().properties.insert(p_path, property); +} + +void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_signal *p_signal) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + List<PropertyInfo> args; + Vector<Variant> default_args; + + for (int i = 0; i < p_signal->num_args; i++) { + PropertyInfo info; + + godot_signal_argument arg = p_signal->args[i]; + + info.hint = (PropertyHint)arg.hint; + info.hint_string = *(String *)&arg.hint_string; + info.name = *(String *)&arg.name; + info.type = (Variant::Type)arg.type; + info.usage = (PropertyUsageFlags)arg.usage; + + args.push_back(info); + } + + for (int i = 0; i < p_signal->num_default_args; i++) { + Variant *v; + godot_signal_argument attrib = p_signal->args[i]; + + v = (Variant *)&attrib.default_value; + + default_args.push_back(*v); + } + + MethodInfo method_info; + method_info.name = *(String *)&p_signal->name; + method_info.arguments = args; + method_info.default_arguments = default_args; + + NativeScriptDesc::Signal signal; + signal.signal = method_info; + + E->get().signals_.insert(*(String *)&p_signal->name, signal); +} + +void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) { + Object *instance = (Object *)p_instance; + if (!instance) + return NULL; + if (instance->get_script_instance() && instance->get_script_instance()->get_language() == NativeScriptLanguage::get_singleton()) { + return ((NativeScriptInstance *)instance->get_script_instance())->userdata; + } + return NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/gdnative/godot.h b/modules/nativescript/godot_nativescript.h index 1d86998291..cfd445086b 100644 --- a/modules/gdnative/godot.h +++ b/modules/nativescript/godot_nativescript.h @@ -27,8 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_C_H -#define GODOT_C_H +#ifndef GODOT_NATIVESCRIPT_H +#define GODOT_NATIVESCRIPT_H + +#include <godot/gdnative.h> #ifdef __cplusplus extern "C" { @@ -70,203 +72,7 @@ extern "C" { #include <stdbool.h> #include <stdint.h> -#define GODOT_API_VERSION 1 - -////// Error - -typedef enum godot_error { - GODOT_OK, - GODOT_FAILED, ///< Generic fail error - GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable - GODOT_ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet - GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource - GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5) - GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory - GODOT_ERR_FILE_NOT_FOUND, - GODOT_ERR_FILE_BAD_DRIVE, - GODOT_ERR_FILE_BAD_PATH, - GODOT_ERR_FILE_NO_PERMISSION, // (10) - GODOT_ERR_FILE_ALREADY_IN_USE, - GODOT_ERR_FILE_CANT_OPEN, - GODOT_ERR_FILE_CANT_WRITE, - GODOT_ERR_FILE_CANT_READ, - GODOT_ERR_FILE_UNRECOGNIZED, // (15) - GODOT_ERR_FILE_CORRUPT, - GODOT_ERR_FILE_MISSING_DEPENDENCIES, - GODOT_ERR_FILE_EOF, - GODOT_ERR_CANT_OPEN, ///< Can't open a resource/socket/file - GODOT_ERR_CANT_CREATE, // (20) - GODOT_ERR_QUERY_FAILED, - GODOT_ERR_ALREADY_IN_USE, - GODOT_ERR_LOCKED, ///< resource is locked - GODOT_ERR_TIMEOUT, - GODOT_ERR_CANT_CONNECT, // (25) - GODOT_ERR_CANT_RESOLVE, - GODOT_ERR_CONNECTION_ERROR, - GODOT_ERR_CANT_AQUIRE_RESOURCE, - GODOT_ERR_CANT_FORK, - GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30) - GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid - GODOT_ERR_ALREADY_EXISTS, ///< When adding, item already exists - GODOT_ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist - GODOT_ERR_DATABASE_CANT_READ, ///< database is full - GODOT_ERR_DATABASE_CANT_WRITE, ///< database is full (35) - GODOT_ERR_COMPILATION_FAILED, - GODOT_ERR_METHOD_NOT_FOUND, - GODOT_ERR_LINK_FAILED, - GODOT_ERR_SCRIPT_FAILED, - GODOT_ERR_CYCLIC_LINK, // (40) - GODOT_ERR_INVALID_DECLARATION, - GODOT_ERR_DUPLICATE_SYMBOL, - GODOT_ERR_PARSE_ERROR, - GODOT_ERR_BUSY, - GODOT_ERR_SKIP, // (45) - GODOT_ERR_HELP, ///< user requested help!! - GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. - GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames - GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though - GODOT_ERR_WTF = GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above -} godot_error; - -////// bool - -typedef bool godot_bool; - -#define GODOT_TRUE 1 -#define GODOT_FALSE 0 - -/////// int - -typedef int godot_int; - -/////// real - -typedef float godot_real; - -/////// Object (forward declared) -typedef void godot_object; - -/////// Brute force forward declarations for the rest -typedef struct godot_variant godot_variant; -typedef struct godot_string godot_string; -typedef struct godot_vector2 godot_vector2; -typedef struct godot_rect2 godot_rect2; -typedef struct godot_vector3 godot_vector3; -typedef struct godot_transform2d godot_transform2d; -typedef struct godot_plane godot_plane; -typedef struct godot_quat godot_quat; -typedef struct godot_rect3 godot_rect3; -typedef struct godot_basis godot_basis; -typedef struct godot_transform godot_transform; -typedef struct godot_color godot_color; -typedef struct godot_node_path godot_node_path; -typedef struct godot_rid godot_rid; -typedef struct godot_dictionary godot_dictionary; -typedef struct godot_array godot_array; -typedef struct godot_pool_byte_array godot_pool_byte_array; -typedef struct godot_pool_int_array godot_pool_int_array; -typedef struct godot_pool_real_array godot_pool_real_array; -typedef struct godot_pool_string_array godot_pool_string_array; -typedef struct godot_pool_vector2_array godot_pool_vector2_array; -typedef struct godot_pool_vector3_array godot_pool_vector3_array; -typedef struct godot_pool_color_array godot_pool_color_array; - -/////// String - -#include "godot/godot_string.h" - -////// Vector2 - -#include "godot/godot_vector2.h" - -////// Rect2 - -#include "godot/godot_rect2.h" - -////// Vector3 - -#include "godot/godot_vector3.h" - -////// Transform2D - -#include "godot/godot_transform2d.h" - -/////// Plane - -#include "godot/godot_plane.h" - -/////// Quat - -#include "godot/godot_quat.h" - -/////// Rect3 - -#include "godot/godot_rect3.h" - -/////// Basis - -#include "godot/godot_basis.h" - -/////// Transform - -#include "godot/godot_transform.h" - -/////// Color - -#include "godot/godot_color.h" - -/////// NodePath - -#include "godot/godot_node_path.h" - -/////// RID - -#include "godot/godot_rid.h" - -/////// Dictionary - -#include "godot/godot_dictionary.h" - -/////// Array - -#include "godot/godot_array.h" - -// single API file for Pool*Array -#include "godot/godot_pool_arrays.h" - -void GDAPI godot_object_destroy(godot_object *p_o); - -////// Variant - -#include "godot/godot_variant.h" - -////// Singleton API - -godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed - -////// MethodBind API - -typedef struct godot_method_bind { - uint8_t _dont_touch_that[1]; // TODO -} godot_method_bind; - -godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname); -void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret); -godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error); -////// Script API - -typedef struct godot_native_init_options { - godot_bool in_editor; - uint64_t core_api_hash; - uint64_t editor_api_hash; - uint64_t no_api_hash; -} godot_native_init_options; - -typedef struct godot_native_terminate_options { - godot_bool in_editor; -} godot_native_terminate_options; - -typedef enum godot_method_rpc_mode { +typedef enum { GODOT_METHOD_RPC_MODE_DISABLED, GODOT_METHOD_RPC_MODE_REMOTE, GODOT_METHOD_RPC_MODE_SYNC, @@ -274,11 +80,7 @@ typedef enum godot_method_rpc_mode { GODOT_METHOD_RPC_MODE_SLAVE, } godot_method_rpc_mode; -typedef struct godot_method_attributes { - godot_method_rpc_mode rpc_type; -} godot_method_attributes; - -typedef enum godot_property_hint { +typedef enum { GODOT_PROPERTY_HINT_NONE, ///< no hint provided. GODOT_PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" GODOT_PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit @@ -315,7 +117,7 @@ typedef enum godot_property_hint { GODOT_PROPERTY_HINT_MAX, } godot_property_hint; -typedef enum godot_property_usage_flags { +typedef enum { GODOT_PROPERTY_USAGE_STORAGE = 1, GODOT_PROPERTY_USAGE_EDITOR = 2, @@ -340,7 +142,7 @@ typedef enum godot_property_usage_flags { GODOT_PROPERTY_USAGE_NOEDITOR = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_NETWORK, } godot_property_usage_flags; -typedef struct godot_property_attributes { +typedef struct { godot_method_rpc_mode rset_type; godot_int type; @@ -350,50 +152,54 @@ typedef struct godot_property_attributes { godot_variant default_value; } godot_property_attributes; -typedef struct godot_instance_create_func { +typedef struct { // instance pointer, method_data - return user data GDCALLINGCONV void *(*create_func)(godot_object *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_create_func; -typedef struct godot_instance_destroy_func { +typedef struct { // instance pointer, method data, user data GDCALLINGCONV void (*destroy_func)(godot_object *, void *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_destroy_func; -void GDAPI godot_script_register_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); +void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); -void GDAPI godot_script_register_tool_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); +void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); + +typedef struct { + godot_method_rpc_mode rpc_type; +} godot_method_attributes; -typedef struct godot_instance_method { +typedef struct { // instance pointer, method data, user data, num args, args - return result as varaint GDCALLINGCONV godot_variant (*method)(godot_object *, void *, void *, int, godot_variant **); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_method; -void GDAPI godot_script_register_method(const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method); +void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method); -typedef struct godot_property_set_func { +typedef struct { // instance pointer, method data, user data, value - GDCALLINGCONV void (*set_func)(godot_object *, void *, void *, godot_variant); + GDCALLINGCONV void (*set_func)(godot_object *, void *, void *, godot_variant *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_property_set_func; -typedef struct godot_property_get_func { +typedef struct { // instance pointer, method data, user data, value GDCALLINGCONV godot_variant (*get_func)(godot_object *, void *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_property_get_func; -void GDAPI godot_script_register_property(const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func); +void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func); -typedef struct godot_signal_argument { +typedef struct { godot_string name; godot_int type; godot_property_hint hint; @@ -402,7 +208,7 @@ typedef struct godot_signal_argument { godot_variant default_value; } godot_signal_argument; -typedef struct godot_signal { +typedef struct { godot_string name; int num_args; godot_signal_argument *args; @@ -410,31 +216,12 @@ typedef struct godot_signal { godot_variant *default_args; } godot_signal; -void GDAPI godot_script_register_signal(const char *p_name, const godot_signal *p_signal); - -void GDAPI *godot_native_get_userdata(godot_object *p_instance); - -// Calling convention? -typedef godot_object *(*godot_class_constructor)(); - -godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname); +void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_signal *p_signal); -godot_dictionary GDAPI godot_get_global_constants(); - -////// System Functions - -//using these will help Godot track how much memory is in use in debug mode -void GDAPI *godot_alloc(int p_bytes); -void GDAPI *godot_realloc(void *p_ptr, int p_bytes); -void GDAPI godot_free(void *p_ptr); - -//print using Godot's error handler list -void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print(const godot_string *p_message); +void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance); #ifdef __cplusplus } #endif -#endif // GODOT_C_H +#endif diff --git a/modules/nativescript/nativescript.cpp b/modules/nativescript/nativescript.cpp new file mode 100644 index 0000000000..e7445e6da9 --- /dev/null +++ b/modules/nativescript/nativescript.cpp @@ -0,0 +1,1232 @@ +/*************************************************************************/ +/* nativescript.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 "nativescript.h" + +#include "modules/gdnative/godot/gdnative.h" + +#include "global_constants.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" + +#ifndef NO_THREADS +#include "os/thread.h" +#endif + +#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) +#include "api_generator.h" +#endif + +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + +////// Script stuff + +void NativeScript::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_class_name", "class_name:String"), &NativeScript::set_class_name); + ClassDB::bind_method(D_METHOD("get_class_name:String"), &NativeScript::get_class_name); + + ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &NativeScript::set_library); + ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &NativeScript::get_library); + + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new")); +} + +#define NSL NativeScriptLanguage::get_singleton() + +#ifdef TOOLS_ENABLED + +void NativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { + NativeScriptDesc *script_data = get_script_desc(); + + ERR_FAIL_COND(!script_data); + + List<PropertyInfo> info; + Map<StringName, Variant> values; + + for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { + PropertyInfo p = E->get().info; + p.name = String(E->key()); + + info.push_back(p); + values[p.name] = E->get().default_value; + } + + p_placeholder->update(info, values); +} + +void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + placeholders.erase(p_placeholder); +} + +#endif + +void NativeScript::set_class_name(String p_class_name) { + class_name = p_class_name; +} + +String NativeScript::get_class_name() const { + return class_name; +} + +void NativeScript::set_library(Ref<GDNativeLibrary> p_library) { + if (!library.is_null()) { + WARN_PRINT("library on NativeScript already set. Do nothing."); + return; + } + library = p_library; + lib_path = library->get_active_library_path(); + +#ifndef NO_THREADS + if (Thread::get_caller_ID() != Thread::get_main_ID()) { + NSL->defer_init_library(p_library, this); + } else +#endif + { + NSL->init_library(p_library); + NSL->register_script(this); + } +} + +Ref<GDNativeLibrary> NativeScript::get_library() const { + return library; +} + +bool NativeScript::can_instance() const { + + NativeScriptDesc *script_data = get_script_desc(); + +#ifdef TOOLS_ENABLED + + return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); +#else + return script_data; +#endif +} + +// TODO(karroffel): implement this +Ref<Script> NativeScript::get_base_script() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return Ref<Script>(); + + Ref<NativeScript> ns = Ref<NativeScript>(NSL->create_script()); + ns->set_class_name(script_data->base); + ns->set_library(get_library()); + return ns; +} + +StringName NativeScript::get_instance_base_type() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return ""; + + return script_data->base_native_type; +} + +ScriptInstance *NativeScript::instance_create(Object *p_this) { + + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + return NULL; + } + +#ifdef TOOLS_ENABLED + if (!ScriptServer::is_scripting_enabled() && !is_tool()) { + // placeholder for nodes. For tools we want the rool thing. + + PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); + placeholders.insert(sins); + + if (script_data->create_func.create_func) { + script_data->create_func.create_func( + (godot_object *)p_this, + script_data->create_func.method_data); + } + + _update_placeholder(sins); + + return sins; + } +#endif + + NativeScriptInstance *nsi = memnew(NativeScriptInstance); + + nsi->owner = p_this; + nsi->script = Ref<NativeScript>(this); + +#ifndef TOOLS_ENABLED + if (!ScriptServer::is_scripting_enabled()) { + nsi->userdata = NULL; + } else { + nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); + } +#else + nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); +#endif + +#ifndef NO_THREADS + owners_lock->lock(); +#endif + + instance_owners.insert(p_this); + +#ifndef NO_THREADS + owners_lock->unlock(); +#endif + + // try to call _init + // we don't care if it doesn't exist, so we ignore errors. + Variant::CallError err; + call("_init", NULL, 0, err); + + return nsi; +} + +bool NativeScript::instance_has(const Object *p_this) const { + return instance_owners.has((Object *)p_this); +} + +bool NativeScript::has_source_code() const { + return false; +} + +String NativeScript::get_source_code() const { + return ""; +} + +void NativeScript::set_source_code(const String &p_code) { +} + +Error NativeScript::reload(bool p_keep_state) { + return FAILED; +} + +bool NativeScript::has_method(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + while (script_data) { + if (script_data->methods.has(p_method)) + return true; + + script_data = script_data->base_data; + } + return false; +} + +MethodInfo NativeScript::get_method_info(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return MethodInfo(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *M = script_data->methods.find(p_method); + + if (M) + return M->get().info; + + script_data = script_data->base_data; + } + return MethodInfo(); +} + +bool NativeScript::is_tool() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (script_data) + return script_data->is_tool; + + return false; +} + +String NativeScript::get_node_type() const { + return ""; // NOTE(karroffel): uhm? +} + +ScriptLanguage *NativeScript::get_language() const { + return NativeScriptLanguage::get_singleton(); +} + +bool NativeScript::has_script_signal(const StringName &p_signal) const { + NativeScriptDesc *script_data = get_script_desc(); + + while (script_data) { + if (script_data->signals_.has(p_signal)) + return true; + script_data = script_data->base_data; + } + return false; +} + +void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<MethodInfo> signals_; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Signal>::Element *S = script_data->signals_.front(); S; S = S->next()) { + signals_.insert(S->get().signal); + } + + script_data = script_data->base_data; + } + + for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) { + r_signals->push_back(E->get()); + } +} + +bool NativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return false; + + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_property); + + if (!P) + return false; + + r_value = P->get().default_value; + return true; +} + +void NativeScript::update_exports() { +} + +void NativeScript::get_script_method_list(List<MethodInfo> *p_list) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<MethodInfo> methods; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { + methods.insert(E->get().info); + } + + script_data = script_data->base_data; + } + + for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } +} + +void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<PropertyInfo> properties; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { + properties.insert(E->get().info); + } + + script_data = script_data->base_data; + } + + for (Set<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } +} + +Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + if (lib_path.empty() || class_name.empty() || library.is_null()) { + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return Variant(); + } + + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return Variant(); + } + + r_error.error = Variant::CallError::CALL_OK; + + REF ref; + Object *owner = NULL; + + if (!(script_data->base_native_type == "")) { + owner = ClassDB::instance(script_data->base_native_type); + } else { + owner = memnew(Reference); + } + + Reference *r = owner->cast_to<Reference>(); + if (r) { + ref = REF(r); + } + + NativeScriptInstance *instance = (NativeScriptInstance *)instance_create(owner); + + owner->set_script_instance(instance); + + if (!instance) { + if (ref.is_null()) { + memdelete(owner); //no owner, sorry + } + return Variant(); + } + + if (ref.is_valid()) { + return ref; + } else { + return owner; + } +} + +// TODO(karroffel): implement this +NativeScript::NativeScript() { + library = Ref<GDNative>(); + lib_path = ""; + class_name = ""; +#ifndef NO_THREADS + owners_lock = Mutex::create(); +#endif +} + +// TODO(karroffel): implement this +NativeScript::~NativeScript() { + NSL->unregister_script(this); + +#ifndef NO_THREADS + memdelete(owners_lock); +#endif +} + +////// ScriptInstance stuff + +#define GET_SCRIPT_DESC() script->get_script_desc() + +void NativeScriptInstance::_ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount) { + if (script_data->base_data) { + _ml_call_reversed(script_data->base_data, p_method, p_args, p_argcount); + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant res = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); + godot_variant_destroy(&res); + } +} + +bool NativeScriptInstance::set(const StringName &p_name, const Variant &p_value) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + P->get().setter.set_func((godot_object *)owner, + P->get().setter.method_data, + userdata, + (godot_variant *)&p_value); + return true; + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_set"); + if (E) { + Variant name = p_name; + const Variant *args[2] = { &name, &p_value }; + + E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 2, + (godot_variant **)args); + return true; + } + + script_data = script_data->base_data; + } + return false; +} +bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + godot_variant value; + value = P->get().getter.get_func((godot_object *)owner, + P->get().getter.method_data, + userdata); + r_ret = *(Variant *)&value; + godot_variant_destroy(&value); + return true; + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get"); + if (E) { + Variant name = p_name; + const Variant *args[1] = { &name }; + + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 1, + (godot_variant **)args); + r_ret = *(Variant *)&result; + godot_variant_destroy(&result); + if (r_ret.get_type() == Variant::NIL) { + return false; + } + return true; + } + + script_data = script_data->base_data; + } + return false; +} + +void NativeScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { + script->get_script_property_list(p_properties); + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get_property_list"); + if (E) { + + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 0, + NULL); + Variant res = *(Variant *)&result; + godot_variant_destroy(&result); + + if (res.get_type() != Variant::ARRAY) { + ERR_EXPLAIN("_get_property_list must return an array of dictionaries"); + ERR_FAIL(); + } + + Array arr = res; + for (int i = 0; i < arr.size(); i++) { + Dictionary d = arr[i]; + + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("type")); + + PropertyInfo info; + + info.type = Variant::Type(d["type"].operator int64_t()); + ERR_CONTINUE(info.type < 0 || info.type >= Variant::VARIANT_MAX); + + info.name = d["name"]; + ERR_CONTINUE(info.name == ""); + + if (d.has("hint")) { + info.hint = PropertyHint(d["hint"].operator int64_t()); + } + + if (d.has("hint_string")) { + info.hint_string = d["hint_string"]; + } + + if (d.has("usage")) { + info.usage = d["usage"]; + } + + p_properties->push_back(info); + } + } + + script_data = script_data->base_data; + } + return; +} + +Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + *r_is_valid = true; + return P->get().info.type; + } + + script_data = script_data->base_data; + } + return Variant::NIL; +} + +void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + script->get_method_list(p_list); +} + +bool NativeScriptInstance::has_method(const StringName &p_method) const { + return script->has_method(p_method); +} + +Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + p_argcount, + (godot_variant **)p_args); + Variant res = *(Variant *)&result; + godot_variant_destroy(&result); + r_error.error = Variant::CallError::CALL_OK; + return res; + } + + script_data = script_data->base_data; + } + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + +void NativeScriptInstance::notification(int p_notification) { + Variant value = p_notification; + const Variant *args[1] = { &value }; + call_multilevel("_notification", args, 1); +} + +void NativeScriptInstance::refcount_incremented() { + Variant::CallError err; + call("_refcount_incremented", NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK && err.error != Variant::CallError::CALL_ERROR_INVALID_METHOD) { + ERR_PRINT("Failed to invoke _refcount_incremented - should not happen"); + } +} + +bool NativeScriptInstance::refcount_decremented() { + Variant::CallError err; + Variant ret = call("_refcount_decremented", NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK && err.error != Variant::CallError::CALL_ERROR_INVALID_METHOD) { + ERR_PRINT("Failed to invoke _refcount_decremented - should not happen"); + return true; // assume we can destroy the object + } + if (err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { + // the method does not exist, default is true + return true; + } + return ret; +} + +Ref<Script> NativeScriptInstance::get_script() const { + return script; +} + +NativeScriptInstance::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + switch (E->get().rpc_mode) { + case GODOT_METHOD_RPC_MODE_DISABLED: + return RPC_MODE_DISABLED; + case GODOT_METHOD_RPC_MODE_REMOTE: + return RPC_MODE_REMOTE; + case GODOT_METHOD_RPC_MODE_SYNC: + return RPC_MODE_SYNC; + case GODOT_METHOD_RPC_MODE_MASTER: + return RPC_MODE_MASTER; + case GODOT_METHOD_RPC_MODE_SLAVE: + return RPC_MODE_SLAVE; + default: + return RPC_MODE_DISABLED; + } + } + + script_data = script_data->base_data; + } + + return RPC_MODE_DISABLED; +} + +// TODO(karroffel): implement this +NativeScriptInstance::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.find(p_variable); + if (E) { + switch (E->get().rset_mode) { + case GODOT_METHOD_RPC_MODE_DISABLED: + return RPC_MODE_DISABLED; + case GODOT_METHOD_RPC_MODE_REMOTE: + return RPC_MODE_REMOTE; + case GODOT_METHOD_RPC_MODE_SYNC: + return RPC_MODE_SYNC; + case GODOT_METHOD_RPC_MODE_MASTER: + return RPC_MODE_MASTER; + case GODOT_METHOD_RPC_MODE_SLAVE: + return RPC_MODE_SLAVE; + default: + return RPC_MODE_DISABLED; + } + } + + script_data = script_data->base_data; + } + + return RPC_MODE_DISABLED; +} + +ScriptLanguage *NativeScriptInstance::get_language() { + return NativeScriptLanguage::get_singleton(); +} + +void NativeScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant res = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + p_argcount, + (godot_variant **)p_args); + godot_variant_destroy(&res); + } + script_data = script_data->base_data; + } +} + +void NativeScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + if (script_data) { + _ml_call_reversed(script_data, p_method, p_args, p_argcount); + } +} + +NativeScriptInstance::~NativeScriptInstance() { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + if (!script_data) + return; + + script_data->destroy_func.destroy_func((godot_object *)owner, script_data->destroy_func.method_data, userdata); + + if (owner) { + +#ifndef NO_THREADS + script->owners_lock->lock(); +#endif + + script->instance_owners.erase(owner); + +#ifndef NO_THREADS + script->owners_lock->unlock(); +#endif + } +} + +////// ScriptingLanguage stuff + +NativeScriptLanguage *NativeScriptLanguage::singleton; + +extern "C" void _native_script_hook(); +void NativeScriptLanguage::_hacky_api_anchor() { + _native_script_hook(); +} + +void NativeScriptLanguage::_unload_stuff() { + for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) { + for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) { + + // free property stuff first + for (Map<StringName, NativeScriptDesc::Property>::Element *P = C->get().properties.front(); P; P = P->next()) { + if (P->get().getter.free_func) + P->get().getter.free_func(P->get().getter.method_data); + + if (P->get().setter.free_func) + P->get().setter.free_func(P->get().setter.method_data); + } + + // free method stuff + for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) { + if (M->get().method.free_func) + M->get().method.free_func(M->get().method.method_data); + } + + // free constructor/destructor + if (C->get().create_func.free_func) + C->get().create_func.free_func(C->get().create_func.method_data); + + if (C->get().destroy_func.free_func) + C->get().destroy_func.free_func(C->get().destroy_func.method_data); + } + } +} + +NativeScriptLanguage::NativeScriptLanguage() { + NativeScriptLanguage::singleton = this; +#ifndef NO_THREADS + mutex = Mutex::create(); +#endif +} + +// TODO(karroffel): implement this +NativeScriptLanguage::~NativeScriptLanguage() { + // _unload_stuff(); // NOTE(karroffel): This gets called in ::finish() + + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + L->get()->terminate(); + NSL->library_classes.clear(); + NSL->library_gdnatives.clear(); + NSL->library_script_users.clear(); + } + +#ifndef NO_THREADS + memdelete(mutex); +#endif +} + +String NativeScriptLanguage::get_name() const { + return "NativeScript"; +} + +void _add_reload_node() { +#ifdef TOOLS_ENABLED + NativeReloadNode *rn = memnew(NativeReloadNode); + EditorNode::get_singleton()->add_child(rn); +#endif +} + +// TODO(karroffel): implement this +void NativeScriptLanguage::init() { + +#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) + + List<String> args = OS::get_singleton()->get_cmdline_args(); + + List<String>::Element *E = args.find("--gdnative-generate-json-api"); + + if (E && E->next()) { + if (generate_c_api(E->next()->get()) != OK) { + ERR_PRINT("Failed to generate C API\n"); + } + } +#endif + +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(&_add_reload_node); +#endif +} +String NativeScriptLanguage::get_type() const { + return "NativeScript"; +} +String NativeScriptLanguage::get_extension() const { + return "gdns"; +} +Error NativeScriptLanguage::execute_file(const String &p_path) { + return OK; // Qué? +} +void NativeScriptLanguage::finish() { + _unload_stuff(); +} +void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const { +} +void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { +} +void NativeScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { +} + +// TODO(karroffel): implement this +Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { + NativeScript *s = memnew(NativeScript); + s->set_class_name(p_class_name); + // TODO(karroffel): use p_base_class_name + return Ref<NativeScript>(s); +} +bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { + return false; +} + +Script *NativeScriptLanguage::create_script() const { + NativeScript *script = memnew(NativeScript); + return script; +} +bool NativeScriptLanguage::has_named_classes() const { + return true; +} +int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const { + return -1; +} +String NativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { + return ""; +} +void NativeScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { +} +void NativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { +} + +// Debugging stuff here. Not used for now. +String NativeScriptLanguage::debug_get_error() const { + return ""; +} +int NativeScriptLanguage::debug_get_stack_level_count() const { + return -1; +} +int NativeScriptLanguage::debug_get_stack_level_line(int p_level) const { + return -1; +} +String NativeScriptLanguage::debug_get_stack_level_function(int p_level) const { + return ""; +} +String NativeScriptLanguage::debug_get_stack_level_source(int p_level) const { + return ""; +} +void NativeScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +void NativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +void NativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +String NativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { + return ""; +} +// Debugging stuff end. + +void NativeScriptLanguage::reload_all_scripts() { +} + +void NativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { +} +void NativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("gdns"); +} + +void NativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { +} + +void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { +} + +void NativeScriptLanguage::profiling_start() { +} + +void NativeScriptLanguage::profiling_stop() { +} + +int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { + return -1; +} + +int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { + return -1; +} + +#ifndef NO_THREADS +void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) { + MutexLock lock(mutex); + libs_to_init.insert(lib); + scripts_to_register.insert(script); + has_objects_to_register = true; +} +#endif + +void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + // See if this library was "registered" already. + const String &lib_path = lib->get_active_library_path(); + Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path); + + if (!E) { + Ref<GDNative> gdn; + gdn.instance(); + gdn->set_library(lib); + + // TODO(karroffel): check the return value? + gdn->initialize(); + + library_gdnatives.insert(lib_path, gdn); + + library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>()); + + if (!library_script_users.has(lib_path)) + library_script_users.insert(lib_path, Set<NativeScript *>()); + + void *args[1] = { + (void *)&lib_path + }; + + // here the library registers all the classes and stuff. + gdn->call_native_raw(_init_call_type, + _init_call_name, + NULL, + 1, + args, + NULL); + } else { + // already initialized. Nice. + } +} + +void NativeScriptLanguage::register_script(NativeScript *script) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + library_script_users[script->lib_path].insert(script); +} + +void NativeScriptLanguage::unregister_script(NativeScript *script) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + Map<String, Set<NativeScript *> >::Element *S = library_script_users.find(script->lib_path); + if (S) { + S->get().erase(script); + if (S->get().size() == 0) { + library_script_users.erase(S); + } + } +#ifndef NO_THREADS + scripts_to_register.erase(script); +#endif +} + +#ifndef NO_THREADS + +void NativeScriptLanguage::frame() { + if (has_objects_to_register) { + MutexLock lock(mutex); + for (Set<Ref<GDNativeLibrary> >::Element *L = libs_to_init.front(); L; L = L->next()) { + init_library(L->get()); + } + libs_to_init.clear(); + for (Set<NativeScript *>::Element *S = scripts_to_register.front(); S; S = S->next()) { + register_script(S->get()); + } + scripts_to_register.clear(); + has_objects_to_register = false; + } +} + +void NativeScriptLanguage::thread_enter() { + Vector<Ref<GDNative> > libs; + { + MutexLock lock(mutex); + for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) { + libs.push_back(L->get()); + } + } + for (int i = 0; i < libs.size(); ++i) { + libs[i]->call_native_raw( + _thread_cb_call_type, + _thread_enter_call_name, + NULL, + 0, + NULL, + NULL); + } +} + +void NativeScriptLanguage::thread_exit() { + Vector<Ref<GDNative> > libs; + { + MutexLock lock(mutex); + for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) { + libs.push_back(L->get()); + } + } + for (int i = 0; i < libs.size(); ++i) { + libs[i]->call_native_raw( + _thread_cb_call_type, + _thread_exit_call_name, + NULL, + 0, + NULL, + NULL); + } +} + +#endif // NO_THREADS + +void NativeReloadNode::_bind_methods() { + ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification); +} + +void NativeReloadNode::_notification(int p_what) { +#ifdef TOOLS_ENABLED + + switch (p_what) { + case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + + if (unloaded) + break; +#ifndef NO_THREADS + MutexLock lock(NSL->mutex); +#endif + NSL->_unload_stuff(); + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + L->get()->terminate(); + NSL->library_classes.erase(L->key()); + } + + unloaded = true; + + } break; + + case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + + if (!unloaded) + break; +#ifndef NO_THREADS + MutexLock lock(NSL->mutex); +#endif + Set<StringName> libs_to_remove; + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + if (!L->get()->initialize()) { + libs_to_remove.insert(L->key()); + continue; + } + + NSL->library_classes.insert(L->key(), Map<StringName, NativeScriptDesc>()); + + void *args[1] = { + (void *)&L->key() + }; + + // here the library registers all the classes and stuff. + L->get()->call_native_raw(NSL->_init_call_type, + NSL->_init_call_name, + NULL, + 1, + args, + NULL); + + 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()) { + NativeScript *script = S->get(); + + if (script->placeholders.size() == 0) + continue; + + for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { + script->_update_placeholder(P->get()); + } + } + } + } + + unloaded = false; + + for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) { + NSL->library_gdnatives.erase(R->get()); + } + + } break; + default: { + }; + } +#endif +} + +RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) { + ResourceFormatLoaderText rsflt; + return rsflt.load(p_path, p_original_path, r_error); +} + +void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("gdns"); +} + +bool ResourceFormatLoaderNativeScript::handles_type(const String &p_type) const { + return (p_type == "Script" || p_type == "NativeScript"); +} + +String ResourceFormatLoaderNativeScript::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "gdns") + return "NativeScript"; + return ""; +} + +Error ResourceFormatSaverNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + ResourceFormatSaverText rfst; + return rfst.save(p_path, p_resource, p_flags); +} + +bool ResourceFormatSaverNativeScript::recognize(const RES &p_resource) const { + return p_resource->cast_to<NativeScript>() != NULL; +} + +void ResourceFormatSaverNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + if (p_resource->cast_to<NativeScript>()) { + p_extensions->push_back("gdns"); + } +} diff --git a/modules/nativescript/nativescript.h b/modules/nativescript/nativescript.h new file mode 100644 index 0000000000..95b4954171 --- /dev/null +++ b/modules/nativescript/nativescript.h @@ -0,0 +1,317 @@ +/*************************************************************************/ +/* nativescript.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 NATIVE_SCRIPT_H +#define NATIVE_SCRIPT_H + +#include "io/resource_loader.h" +#include "io/resource_saver.h" +#include "os/thread_safe.h" +#include "resource.h" +#include "scene/main/node.h" +#include "script_language.h" +#include "self_list.h" + +#include "godot_nativescript.h" +#include "modules/gdnative/gdnative.h" + +#ifndef NO_THREADS +#include "os/mutex.h" +#endif + +struct NativeScriptDesc { + + struct Method { + godot_instance_method method; + MethodInfo info; + int rpc_mode; + }; + struct Property { + godot_property_set_func setter; + godot_property_get_func getter; + PropertyInfo info; + Variant default_value; + int rset_mode; + }; + + struct Signal { + MethodInfo signal; + }; + + Map<StringName, Method> methods; + Map<StringName, Property> properties; + Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals + StringName base; + StringName base_native_type; + NativeScriptDesc *base_data; + godot_instance_create_func create_func; + godot_instance_destroy_func destroy_func; + + bool is_tool; + + inline NativeScriptDesc() + : methods(), + properties(), + signals_(), + base(), + base_native_type() { + zeromem(&create_func, sizeof(godot_instance_create_func)); + zeromem(&destroy_func, sizeof(godot_instance_destroy_func)); + } +}; + +class NativeScript : public Script { + GDCLASS(NativeScript, Script) + +#ifdef TOOLS_ENABLED + Set<PlaceHolderScriptInstance *> placeholders; + void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); +#endif + + friend class NativeScriptInstance; + friend class NativeScriptLanguage; + friend class NativeReloadNode; + friend class GDNativeLibrary; + + Ref<GDNativeLibrary> library; + + String lib_path; + + String class_name; + +#ifndef NO_THREADS + Mutex *owners_lock; +#endif + Set<Object *> instance_owners; + +protected: + static void _bind_methods(); + +public: + inline NativeScriptDesc *get_script_desc() const; + + void set_class_name(String p_class_name); + String get_class_name() const; + + void set_library(Ref<GDNativeLibrary> library); + Ref<GDNativeLibrary> get_library() const; + + 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); + + virtual bool has_method(const StringName &p_method) const; + virtual MethodInfo get_method_info(const StringName &p_method) const; + + virtual bool is_tool() const; + + 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(); //editor tool + virtual void get_script_method_list(List<MethodInfo> *p_list) const; + virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + + Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + + NativeScript(); + ~NativeScript(); +}; + +class NativeScriptInstance : public ScriptInstance { + + friend class NativeScript; + + Object *owner; + Ref<NativeScript> script; + + void _ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount); + +public: + void *userdata; + + 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) 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); + virtual void notification(int p_notification); + virtual Ref<Script> get_script() const; + virtual RPCMode get_rpc_mode(const StringName &p_method) const; + virtual RPCMode get_rset_mode(const StringName &p_variable) const; + virtual ScriptLanguage *get_language(); + + 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); + + virtual void refcount_incremented(); + virtual bool refcount_decremented(); + + ~NativeScriptInstance(); +}; + +class NativeReloadNode; + +class NativeScriptLanguage : public ScriptLanguage { + + friend class NativeScript; + friend class NativeScriptInstance; + friend class NativeReloadNode; + +private: + static NativeScriptLanguage *singleton; + + void _unload_stuff(); + +#ifndef NO_THREADS + Mutex *mutex; + + Set<Ref<GDNativeLibrary> > libs_to_init; + Set<NativeScript *> scripts_to_register; + volatile bool has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed + void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script); +#endif + + void init_library(const Ref<GDNativeLibrary> &lib); + void register_script(NativeScript *script); + void unregister_script(NativeScript *script); + +public: + Map<String, Map<StringName, NativeScriptDesc> > library_classes; + Map<String, Ref<GDNative> > library_gdnatives; + + Map<String, Set<NativeScript *> > library_script_users; + + const StringName _init_call_type = "nativescript_init"; + const StringName _init_call_name = "godot_nativescript_init"; + + const StringName _thread_cb_call_type = "godot_nativescript_thread_cb"; + const StringName _thread_enter_call_name = "godot_nativescript_thread_enter"; + const StringName _thread_exit_call_name = "godot_nativescript_thread_exit"; + + NativeScriptLanguage(); + ~NativeScriptLanguage(); + + inline static NativeScriptLanguage *get_singleton() { + return singleton; + } + + void _hacky_api_anchor(); + +#ifndef NO_THREADS + virtual void thread_enter(); + virtual void thread_exit(); + + virtual void frame(); +#endif + + virtual String get_name() const; + virtual void init(); + virtual String get_type() const; + virtual String get_extension() const; + virtual Error execute_file(const String &p_path); + virtual void finish(); + 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) const; + virtual Script *create_script() const; + virtual bool has_named_classes() const; + 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 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); + 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, int p_max_depth); + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth); + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth); + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth); + virtual void reload_all_scripts(); + virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + 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); +}; + +inline NativeScriptDesc *NativeScript::get_script_desc() const { + Map<StringName, NativeScriptDesc>::Element *E = NativeScriptLanguage::singleton->library_classes[lib_path].find(class_name); + return E ? &E->get() : NULL; +} + +class NativeReloadNode : public Node { + GDCLASS(NativeReloadNode, Node) + bool unloaded = false; + +public: + static void _bind_methods(); + void _notification(int p_what); +}; + +class ResourceFormatLoaderNativeScript : public ResourceFormatLoader { +public: + 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 ResourceFormatSaverNativeScript : public ResourceFormatSaver { + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; +}; + +#endif // GDNATIVE_H diff --git a/modules/nativescript/register_types.cpp b/modules/nativescript/register_types.cpp new file mode 100644 index 0000000000..dfa16d8a2a --- /dev/null +++ b/modules/nativescript/register_types.cpp @@ -0,0 +1,124 @@ +/*************************************************************************/ +/* 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 "io/resource_loader.h" +#include "io/resource_saver.h" + +#include "nativescript.h" + +#include "core/os/os.h" + +NativeScriptLanguage *native_script_language; + +typedef void (*native_script_init_fn)(void *); + +void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { + if (p_handle == NULL) { + ERR_PRINT("No valid library handle, can't call nativescript init procedure"); + return; + } + + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + p_handle, + *(String *)p_proc_name, + library_proc, + true); // we print our own message + if (err != OK) { + ERR_PRINT((String("GDNative procedure \"" + *(String *)p_proc_name) + "\" does not exists and can't be called").utf8().get_data()); + return; + } + + native_script_init_fn fn = (native_script_init_fn)library_proc; + + fn(args[0]); +} + +#ifndef NO_THREADS + +typedef void (*native_script_empty_callback)(); + +void thread_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { + if (p_handle == NULL) { + ERR_PRINT("No valid library handle, can't call nativescript thread enter/exit callback"); + return; + } + + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + p_handle, + *(String *)p_proc_name, + library_proc, + true); + if (err != OK) { + // it's fine if thread callbacks are not present in the library. + return; + } + + native_script_empty_callback fn = (native_script_empty_callback)library_proc; + fn(); +} + +#endif // NO_THREADS + +ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL; +ResourceFormatSaverNativeScript *resource_saver_gdns = NULL; + +void register_nativescript_types() { + native_script_language = memnew(NativeScriptLanguage); + + ClassDB::register_class<NativeScript>(); + + ScriptServer::register_language(native_script_language); + + GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_init_call_type, init_call_cb); +#ifndef NO_THREADS + GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_thread_cb_call_type, thread_call_cb); +#endif + + resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); + ResourceSaver::add_resource_format_saver(resource_saver_gdns); + + resource_loader_gdns = memnew(ResourceFormatLoaderNativeScript); + ResourceLoader::add_resource_format_loader(resource_loader_gdns); +} + +void unregister_nativescript_types() { + + memdelete(resource_loader_gdns); + + memdelete(resource_saver_gdns); + + if (native_script_language) { + ScriptServer::unregister_language(native_script_language); + memdelete(native_script_language); + } +} diff --git a/modules/nativescript/register_types.h b/modules/nativescript/register_types.h new file mode 100644 index 0000000000..319da9c42f --- /dev/null +++ b/modules/nativescript/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_nativescript_types(); +void unregister_nativescript_types(); diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp index 8159296b3c..7a9d5195a9 100644 --- a/modules/openssl/stream_peer_openssl.cpp +++ b/modules/openssl/stream_peer_openssl.cpp @@ -560,7 +560,7 @@ void StreamPeerOpenSSL::initialize_ssl() { ERR_load_BIO_strings(); // Load BIO error strings OpenSSL_add_all_algorithms(); // Load all available encryption algorithms String certs_path = GLOBAL_DEF("network/ssl/certificates", ""); - GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt")); + ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt")); if (certs_path != "") { FileAccess *f = FileAccess::open(certs_path, FileAccess::READ); @@ -581,7 +581,7 @@ void StreamPeerOpenSSL::initialize_ssl() { } } String config_path = GLOBAL_DEF("network/ssl/config", ""); - GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/config", PropertyInfo(Variant::STRING, "network/ssl/config", PROPERTY_HINT_FILE, "*.cnf")); + ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/config", PropertyInfo(Variant::STRING, "network/ssl/config", PROPERTY_HINT_FILE, "*.cnf")); if (config_path != "") { Vector<uint8_t> data = FileAccess::get_file_as_array(config_path); diff --git a/modules/openssl/stream_peer_openssl.h b/modules/openssl/stream_peer_openssl.h index 5c830ebf37..b1da5e1d95 100644 --- a/modules/openssl/stream_peer_openssl.h +++ b/modules/openssl/stream_peer_openssl.h @@ -30,9 +30,9 @@ #ifndef STREAM_PEER_OPEN_SSL_H #define STREAM_PEER_OPEN_SSL_H -#include "global_config.h" #include "io/stream_peer_ssl.h" #include "os/file_access.h" +#include "project_settings.h" #include "thirdparty/misc/curl_hostcheck.h" diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index c645a55703..7b8b2abebb 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -39,7 +39,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra int todo = p_frames; - while (todo) { + while (todo && active) { int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, (float *)p_buffer, todo * 2); todo -= mixed; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index d895f60280..977062dd14 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "video_stream_theora.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "thirdparty/misc/yuv2rgb.h" @@ -728,7 +728,7 @@ void VideoStreamPlaybackTheora::play() { } playing = true; - delay_compensation = GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms"); delay_compensation /= 1000.0; }; diff --git a/modules/tinyexr/config.py b/modules/tinyexr/config.py index fb920482f5..2e4b96a6b0 100644 --- a/modules/tinyexr/config.py +++ b/modules/tinyexr/config.py @@ -4,4 +4,8 @@ def can_build(platform): def configure(env): - pass + # Tools only, disabled for non-tools + # TODO: Find a cleaner way to achieve that + if (env["tools"] == "no"): + env["module_tinyexr_enabled"] = "no" + env.disabled_modules.append("tinyexr") diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index c0467a901b..a54d306aff 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -90,6 +90,7 @@ void register_visual_script_types() { ClassDB::register_class<VisualScriptSequence>(); //ClassDB::register_class<VisualScriptInputFilter>(); ClassDB::register_class<VisualScriptSwitch>(); + ClassDB::register_class<VisualScriptSelect>(); ClassDB::register_class<VisualScriptYield>(); ClassDB::register_class<VisualScriptYieldSignal>(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index bb8111ce99..f15abec7e2 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "visual_script.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "visual_script_nodes.h" @@ -140,7 +140,7 @@ VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inp tg.type = pinfo.type; if (pinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { - tg.GDCLASS = pinfo.hint_string; + tg.gdclass = pinfo.hint_string; } return tg; @@ -660,6 +660,9 @@ void VisualScript::set_variable_export(const StringName &p_name, bool p_export) ERR_FAIL_COND(!variables.has(p_name)); variables[p_name]._export = p_export; +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif } bool VisualScript::get_variable_export(const StringName &p_name) const { @@ -1067,9 +1070,11 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { get_variable_list(&vars); for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { - if (!variables[E->get()]._export) - continue; - p_list->push_back(variables[E->get()].info); + //if (!variables[E->get()]._export) + // continue; + PropertyInfo pi = variables[E->get()].info; + pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + p_list->push_back(pi); } } @@ -1259,14 +1264,14 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function); ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function); ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function); - ClassDB::bind_method(D_METHOD("set_function_scroll", "ofs"), &VisualScript::set_function_scroll); - ClassDB::bind_method(D_METHOD("get_function_scroll"), &VisualScript::get_function_scroll); + ClassDB::bind_method(D_METHOD("set_function_scroll", "name", "ofs"), &VisualScript::set_function_scroll); + ClassDB::bind_method(D_METHOD("get_function_scroll", "name"), &VisualScript::get_function_scroll); - ClassDB::bind_method(D_METHOD("add_node", "func", "id", "node", "pos"), &VisualScript::add_node, DEFVAL(Point2())); + ClassDB::bind_method(D_METHOD("add_node", "func", "id", "node:VisualScriptNode", "pos"), &VisualScript::add_node, DEFVAL(Point2())); ClassDB::bind_method(D_METHOD("remove_node", "func", "id"), &VisualScript::remove_node); ClassDB::bind_method(D_METHOD("get_function_node_id", "name"), &VisualScript::get_function_node_id); - ClassDB::bind_method(D_METHOD("get_node", "func", "id"), &VisualScript::get_node); + ClassDB::bind_method(D_METHOD("get_node:VisualScriptNode", "func", "id"), &VisualScript::get_node); ClassDB::bind_method(D_METHOD("has_node", "func", "id"), &VisualScript::has_node); ClassDB::bind_method(D_METHOD("set_node_pos", "func", "id", "pos"), &VisualScript::set_node_pos); ClassDB::bind_method(D_METHOD("get_node_pos", "func", "id"), &VisualScript::get_node_pos); @@ -1297,7 +1302,7 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("custom_signal_get_argument_type", "name", "argidx"), &VisualScript::custom_signal_get_argument_type); ClassDB::bind_method(D_METHOD("custom_signal_set_argument_name", "name", "argidx", "argname"), &VisualScript::custom_signal_set_argument_name); ClassDB::bind_method(D_METHOD("custom_signal_get_argument_name", "name", "argidx"), &VisualScript::custom_signal_get_argument_name); - ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "argidx"), &VisualScript::custom_signal_remove_argument); + ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "name", "argidx"), &VisualScript::custom_signal_remove_argument); ClassDB::bind_method(D_METHOD("custom_signal_get_argument_count", "name"), &VisualScript::custom_signal_get_argument_count); ClassDB::bind_method(D_METHOD("custom_signal_swap_argument", "name", "argidx", "withidx"), &VisualScript::custom_signal_swap_argument); ClassDB::bind_method(D_METHOD("remove_custom_signal", "name"), &VisualScript::remove_custom_signal); @@ -1358,6 +1363,7 @@ void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) c continue; PropertyInfo p = E->get().info; p.name = String(E->key()); + p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_properties->push_back(p); } } @@ -2652,7 +2658,7 @@ VisualScriptLanguage::VisualScriptLanguage() { _debug_parse_err_node = -1; _debug_parse_err_file = ""; _debug_call_stack_pos = 0; - int dmcs = GLOBAL_DEF("debug/script/max_call_stack", 1024); + int dmcs = GLOBAL_DEF("debug/settings/visual_script/max_call_stack", 1024); if (ScriptDebugger::get_singleton()) { //debugging enabled! _debug_max_call_stack = dmcs; diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 20a1cf49c5..cdd7eded18 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -89,7 +89,7 @@ public: struct TypeGuess { Variant::Type type; - StringName GDCLASS; + StringName gdclass; Ref<Script> script; TypeGuess() { diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 941668d474..35358d5a1f 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -52,11 +52,13 @@ public: protected: static void _bind_methods() { ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed); + ADD_SIGNAL(MethodInfo("changed")); } void _sig_changed() { _change_notify(); + emit_signal("changed"); } bool _set(const StringName &p_name, const Variant &p_value) { @@ -191,15 +193,18 @@ protected: static void _bind_methods() { ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed); ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed); + ADD_SIGNAL(MethodInfo("changed")); } void _var_changed() { _change_notify(); + emit_signal("changed"); } void _var_value_changed() { _change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general + emit_signal("changed"); } bool _set(const StringName &p_name, const Variant &p_value) { @@ -261,6 +266,7 @@ protected: if (String(p_name) == "export") { script->set_variable_export(var, p_value); + EditorNode::get_singleton()->get_property_editor()->update_tree(); return true; } @@ -486,7 +492,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { } if (EditorSettings::get_singleton()->has("editors/visual_script/color_" + node->get_category())) { - gnode->set_modulate(EditorSettings::get_singleton()->get("editors/visual_script/color_" + node->get_category())); + Color c = EditorSettings::get_singleton()->get("editors/visual_script/color_" + node->get_category()); + gnode->set_self_modulate(c); } gnode->set_meta("__vnode", node); @@ -699,7 +706,7 @@ void VisualScriptEditor::_update_members() { ti->set_selectable(0, true); ti->set_editable(0, true); //ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (E->get() == edited_func) { ti->set_custom_bg_color(0, get_color("prop_category", "Editor")); @@ -757,8 +764,8 @@ void VisualScriptEditor::_update_members() { ti->set_selectable(0, true); ti->set_editable(0, true); - ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (selected == E->get()) ti->select(0); @@ -777,8 +784,8 @@ void VisualScriptEditor::_update_members() { ti->set_text(0, E->get()); ti->set_selectable(0, true); ti->set_editable(0, true); - ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (selected == E->get()) ti->select(0); @@ -1068,105 +1075,6 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt undo_redo->commit_action(); return; //or crash because it will become invalid } - - } else { - - if (ti->get_parent() == root->get_children()) { - //edit/remove function - String name = ti->get_metadata(0); - - if (p_button == 1) { - //delete the function - undo_redo->create_action(TTR("Remove Function")); - undo_redo->add_do_method(script.ptr(), "remove_function", name); - undo_redo->add_undo_method(script.ptr(), "add_function", name); - List<int> nodes; - script->get_node_list(name, &nodes); - for (List<int>::Element *E = nodes.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_pos(name, E->get())); - } - - List<VisualScript::SequenceConnection> seq_connections; - - script->get_sequence_connection_list(name, &seq_connections); - - for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node); - } - - List<VisualScript::DataConnection> data_connections; - - script->get_data_connection_list(name, &data_connections); - - for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); - } - - /* - for(int i=0;i<script->function_get_argument_count(name);i++) { - undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); - } - */ - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - } else if (p_button == 0) { - } - return; //or crash because it will become invalid - } - - if (ti->get_parent() == root->get_children()->get_next()) { - //edit/remove variable - - String name = ti->get_metadata(0); - - if (p_button == 1) { - - undo_redo->create_action(TTR("Remove Variable")); - undo_redo->add_do_method(script.ptr(), "remove_variable", name); - undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name)); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - return; //or crash because it will become invalid - } else if (p_button == 0) { - - variable_editor->edit(name); - edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name); - edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE); - } - } - - if (ti->get_parent() == root->get_children()->get_next()->get_next()) { - //edit/remove variable - String name = ti->get_metadata(0); - - if (p_button == 1) { - - undo_redo->create_action(TTR("Remove Signal")); - undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name); - undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name); - - for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) { - undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i)); - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - } else if (p_button == 0) { - - signal_editor->edit(name); - edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name); - edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE); - } - - return; //or crash because it will become invalid - } } } @@ -2269,6 +2177,11 @@ void VisualScriptEditor::_change_base_type() { select_base_type->popup_create(true); } +void VisualScriptEditor::clear_edit_menu() { + memdelete(edit_menu); + memdelete(left_vsplit); +} + void VisualScriptEditor::_change_base_type_callback() { String bt = select_base_type->get_selected_type(); @@ -2415,6 +2328,16 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, p_from.to_int(), from_port, p_to.to_int()); undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, p_from.to_int(), from_port, p_to.to_int()); } else { + + // disconect current, and connect the new one + if (script->is_input_value_port_connected(edited_func, p_to.to_int(), to_port)) { + int conn_from; + int conn_port; + script->get_input_value_port_connection_source(edited_func, p_to.to_int(), to_port, &conn_from, &conn_port); + undo_redo->add_do_method(script.ptr(), "data_disconnect", edited_func, conn_from, conn_port, p_to.to_int(), to_port); + undo_redo->add_undo_method(script.ptr(), "data_connect", edited_func, conn_from, conn_port, p_to.to_int(), to_port); + } + undo_redo->add_do_method(script.ptr(), "data_connect", edited_func, p_from.to_int(), from_port, p_to.to_int(), to_port); undo_redo->add_undo_method(script.ptr(), "data_disconnect", edited_func, p_from.to_int(), from_port, p_to.to_int(), to_port); //update nodes in sgraph @@ -2556,7 +2479,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_node, i if (obj) { g.type = Variant::OBJECT; - g.GDCLASS = obj->get_class(); + g.gdclass = obj->get_class(); g.script = obj->get_script(); } } @@ -2596,8 +2519,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2627,8 +2550,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2657,8 +2580,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2833,13 +2756,18 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) { void VisualScriptEditor::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { - node_filter_icon->set_texture(Control::get_icon("Zoom", "EditorIcons")); + node_filter->add_icon_override("right_icon", Control::get_icon("Search", "EditorIcons")); + variable_editor->connect("changed", this, "_update_members"); + signal_editor->connect("changed", this, "_update_members"); + } + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + left_vsplit->set_visible(is_visible_in_tree()); } } void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) { - if (updating_graph) + if (updating_graph || !script.is_valid()) return; updating_graph = true; @@ -3053,6 +2981,142 @@ void VisualScriptEditor::_menu_option(int p_what) { } } +void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { + + TreeItem *ti = members->get_selected(); + ERR_FAIL_COND(!ti); + + member_popup->clear(); + member_popup->set_position(members->get_global_position() + p_pos); + member_popup->set_size(Vector2()); + + TreeItem *root = members->get_root(); + + Ref<Texture> del_icon = Control::get_icon("Del", "EditorIcons"); + + Ref<Texture> edit_icon = Control::get_icon("Edit", "EditorIcons"); + + if (ti->get_parent() == root->get_children()) { + + member_type = MEMBER_FUNCTION; + member_name = ti->get_text(0); + member_popup->add_icon_item(del_icon, TTR("Remove Function"), MEMBER_REMOVE); + member_popup->popup(); + return; + } + + if (ti->get_parent() == root->get_children()->get_next()) { + + member_type = MEMBER_VARIABLE; + member_name = ti->get_text(0); + member_popup->add_icon_item(edit_icon, TTR("Edit Variable"), MEMBER_EDIT); + member_popup->add_separator(); + member_popup->add_icon_item(del_icon, TTR("Remove Variable"), MEMBER_REMOVE); + member_popup->popup(); + return; + } + + if (ti->get_parent() == root->get_children()->get_next()->get_next()) { + + member_type = MEMBER_SIGNAL; + member_name = ti->get_text(0); + member_popup->add_icon_item(edit_icon, TTR("Edit Signal"), MEMBER_EDIT); + member_popup->add_separator(); + member_popup->add_icon_item(del_icon, TTR("Remove Signal"), MEMBER_REMOVE); + member_popup->popup(); + return; + } +} + +void VisualScriptEditor::_member_option(int p_option) { + + switch (member_type) { + case MEMBER_FUNCTION: { + + if (p_option == MEMBER_REMOVE) { + //delete the function + String name = member_name; + + undo_redo->create_action(TTR("Remove Function")); + undo_redo->add_do_method(script.ptr(), "remove_function", name); + undo_redo->add_undo_method(script.ptr(), "add_function", name); + List<int> nodes; + script->get_node_list(name, &nodes); + for (List<int>::Element *E = nodes.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_pos(name, E->get())); + } + + List<VisualScript::SequenceConnection> seq_connections; + + script->get_sequence_connection_list(name, &seq_connections); + + for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node); + } + + List<VisualScript::DataConnection> data_connections; + + script->get_data_connection_list(name, &data_connections); + + for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + + /* + for(int i=0;i<script->function_get_argument_count(name);i++) { + undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); + } + */ + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + } + } break; + case MEMBER_VARIABLE: { + + String name = member_name; + + if (p_option == MEMBER_REMOVE) { + undo_redo->create_action(TTR("Remove Variable")); + undo_redo->add_do_method(script.ptr(), "remove_variable", name); + undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name)); + undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->commit_action(); + } else if (p_option == MEMBER_EDIT) { + variable_editor->edit(name); + edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name); + edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE); + } + } break; + case MEMBER_SIGNAL: { + String name = member_name; + + if (p_option == MEMBER_REMOVE) { + undo_redo->create_action(TTR("Remove Signal")); + undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name); + undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name); + + for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) { + undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i)); + } + + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->commit_action(); + } else if (p_option == MEMBER_EDIT) { + + signal_editor->edit(name); + edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name); + edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE); + } + } break; + } +} + void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_member_button", &VisualScriptEditor::_member_button); @@ -3101,6 +3165,10 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_selected_method", &VisualScriptEditor::_selected_method); ClassDB::bind_method("_draw_color_over_button", &VisualScriptEditor::_draw_color_over_button); + + ClassDB::bind_method("_member_rmb_selected", &VisualScriptEditor::_member_rmb_selected); + + ClassDB::bind_method("_member_option", &VisualScriptEditor::_member_option); } VisualScriptEditor::VisualScriptEditor() { @@ -3122,17 +3190,16 @@ VisualScriptEditor::VisualScriptEditor() { edit_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - main_hsplit = memnew(HSplitContainer); - add_child(main_hsplit); - main_hsplit->set_area_as_parent_rect(); - left_vsplit = memnew(VSplitContainer); - main_hsplit->add_child(left_vsplit); + ScriptEditor::get_singleton()->get_left_list_split()->call_deferred("add_child", left_vsplit); //add but wait until done settig up this + left_vsplit->set_v_size_flags(SIZE_EXPAND_FILL); + left_vsplit->set_stretch_ratio(2); + left_vsplit->hide(); VBoxContainer *left_vb = memnew(VBoxContainer); left_vsplit->add_child(left_vb); left_vb->set_v_size_flags(SIZE_EXPAND_FILL); - left_vb->set_custom_minimum_size(Size2(230, 1) * EDSCALE); + //left_vb->set_custom_minimum_size(Size2(230, 1) * EDSCALE); base_type_select = memnew(Button); left_vb->add_margin_child(TTR("Base Type:"), base_type_select); @@ -3158,9 +3225,6 @@ VisualScriptEditor::VisualScriptEditor() { node_filter->connect("text_changed", this, "_node_filter_changed"); hbc_nodes->add_child(node_filter); node_filter->set_h_size_flags(SIZE_EXPAND_FILL); - node_filter_icon = memnew(TextureRect); - node_filter_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - hbc_nodes->add_child(node_filter_icon); vbc_nodes->add_child(hbc_nodes); nodes = memnew(Tree); @@ -3174,7 +3238,8 @@ VisualScriptEditor::VisualScriptEditor() { nodes->set_drag_forwarding(this); graph = memnew(GraphEdit); - main_hsplit->add_child(graph); + add_child(graph); + graph->set_area_as_parent_rect(); graph->set_h_size_flags(SIZE_EXPAND_FILL); graph->connect("node_selected", this, "_node_selected"); graph->connect("_begin_node_move", this, "_begin_node_move"); @@ -3190,7 +3255,8 @@ VisualScriptEditor::VisualScriptEditor() { select_func_text->set_align(Label::ALIGN_CENTER); select_func_text->set_valign(Label::VALIGN_CENTER); select_func_text->set_h_size_flags(SIZE_EXPAND_FILL); - main_hsplit->add_child(select_func_text); + add_child(select_func_text); + graph->set_area_as_parent_rect(); hint_text = memnew(Label); hint_text->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, 100); @@ -3280,6 +3346,12 @@ VisualScriptEditor::VisualScriptEditor() { port_action_popup = memnew(PopupMenu); add_child(port_action_popup); port_action_popup->connect("id_pressed", this, "_port_action_menu"); + + member_popup = memnew(PopupMenu); + add_child(member_popup); + members->connect("item_rmb_selected", this, "_member_rmb_selected"); + members->set_allow_rmb_select(true); + member_popup->connect("id_pressed", this, "_member_option"); } VisualScriptEditor::~VisualScriptEditor() { @@ -3311,7 +3383,7 @@ static void register_editor_callback() { EditorSettings::get_singleton()->set("editors/visual_script/color_functions", Color(1, 0.9, 0.9)); EditorSettings::get_singleton()->set("editors/visual_script/color_data", Color(0.9, 1.0, 0.9)); EditorSettings::get_singleton()->set("editors/visual_script/color_operators", Color(0.9, 0.9, 1.0)); - EditorSettings::get_singleton()->set("editors/visual_script/color_flow_control", Color(1.0, 1.0, 0.8)); + EditorSettings::get_singleton()->set("editors/visual_script/color_flow_control", Color(1.0, 1.0, 1.0)); EditorSettings::get_singleton()->set("editors/visual_script/color_custom", Color(0.8, 1.0, 1.0)); EditorSettings::get_singleton()->set("editors/visual_script/color_constants", Color(1.0, 0.8, 1.0)); diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 92f31f20da..fee4e27bd5 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -72,15 +72,25 @@ class VisualScriptEditor : public ScriptEditorBase { CREATE_RETURN, }; + enum MemberAction { + MEMBER_EDIT, + MEMBER_REMOVE + + }; + + enum MemberType { + MEMBER_FUNCTION, + MEMBER_VARIABLE, + MEMBER_SIGNAL + }; + + VSplitContainer *left_vsplit; MenuButton *edit_menu; Ref<VisualScript> script; Button *base_type_select; - HSplitContainer *main_hsplit; - VSplitContainer *left_vsplit; - GraphEdit *graph; LineEdit *node_filter; @@ -154,6 +164,10 @@ class VisualScriptEditor : public ScriptEditorBase { static Clipboard *clipboard; PopupMenu *port_action_popup; + PopupMenu *member_popup; + + MemberType member_type; + String member_name; PortAction port_action; int port_action_node; @@ -223,6 +237,9 @@ class VisualScriptEditor : public ScriptEditorBase { VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes); + void _member_rmb_selected(const Vector2 &p_pos); + void _member_option(int p_option); + protected: void _notification(int p_what); static void _bind_methods(); @@ -252,6 +269,7 @@ public: virtual void set_debugger_active(bool p_active); virtual void set_tooltip_request_func(String p_method, Object *p_obj); virtual Control *get_edit_menu(); + virtual void clear_edit_menu(); virtual bool can_lose_focus_on_node_selection() { return false; } static void register_editor(); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index 791b5d99ff..78b70934c0 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -68,12 +68,12 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val return true; } - if (String(p_name).begins_with("input/")) { + if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slice("/", 1).to_int(); + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); ERR_FAIL_INDEX_V(idx, inputs.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { @@ -115,12 +115,12 @@ bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) cons return true; } - if (String(p_name).begins_with("input/")) { + if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slice("/", 1).to_int(); + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); ERR_FAIL_INDEX_V(idx, inputs.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { @@ -151,8 +151,8 @@ void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) cons for (int i = 0; i < inputs.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "input/" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "input/" + itos(i) + "/name")); + p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt)); + p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name")); } } diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index 07d69db207..77f3111d94 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -29,8 +29,9 @@ /*************************************************************************/ #include "visual_script_flow_control.h" -#include "global_config.h" +#include "io/resource_loader.h" #include "os/keyboard.h" +#include "project_settings.h" ////////////////////////////////////////// ////////////////RETURN//////////////////// @@ -119,8 +120,8 @@ void VisualScriptReturn::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_value/enabled"), "set_enable_return_value", "is_return_value_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "return_value/type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_enabled"), "set_enable_return_value", "is_return_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "return_type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type"); } class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { @@ -137,11 +138,11 @@ public: if (with_value) { *p_working_mem = *p_inputs[0]; + return STEP_EXIT_FUNCTION_BIT; } else { *p_working_mem = Variant(); + return 0; } - - return 0; } }; @@ -874,7 +875,7 @@ String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const case Ref<InputEvent>::ACTION: { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; text = "No Action"; @@ -943,7 +944,7 @@ bool VisualScriptInputFilter::_set(const StringName &p_name, const Variant &p_va filters[idx] = Ref<InputEvent>(); filters[idx].type = Ref<InputEvent>::Type(int(p_value)); if (filters[idx].type == Ref<InputEvent>::JOYPAD_MOTION) { - filters[idx].joy_motion.axis_value = 0.5; //for treshold + filters[idx].joy_motion.axis_value = 0.5; //for threshold } else if (filters[idx].type == Ref<InputEvent>::KEY) { filters[idx]->is_pressed() = true; //put these as true to make it more user friendly } else if (filters[idx].type == Ref<InputEvent>::MOUSE_BUTTON) { @@ -1070,7 +1071,7 @@ bool VisualScriptInputFilter::_set(const StringName &p_name, const Variant &p_va filters[idx].joy_motion.axis = int(p_value) << 1 | filters[idx].joy_motion.axis; } else if (what == "mode") { filters[idx].joy_motion.axis |= int(p_value); - } else if (what == "treshold") { + } else if (what == "threshold") { filters[idx].joy_motion.axis_value = p_value; } else { return false; @@ -1118,7 +1119,7 @@ bool VisualScriptInputFilter::_set(const StringName &p_name, const Variant &p_va if (what == "action_name") { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -1280,7 +1281,7 @@ bool VisualScriptInputFilter::_get(const StringName &p_name, Variant &r_ret) con r_ret = filters[idx].joy_motion.axis >> 1; } else if (what == "mode") { r_ret = filters[idx].joy_motion.axis & 1; - } else if (what == "treshold") { + } else if (what == "threshold") { r_ret = filters[idx].joy_motion.axis_value; } else { return false; @@ -1324,7 +1325,7 @@ bool VisualScriptInputFilter::_get(const StringName &p_name, Variant &r_ret) con if (what == "action_name") { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -1433,7 +1434,7 @@ void VisualScriptInputFilter::_get_property_list(List<PropertyInfo> *p_list) con p_list->push_back(PropertyInfo(Variant::INT, base + "axis_index")); p_list->push_back(PropertyInfo(Variant::INT, base + "mode", PROPERTY_HINT_ENUM, "Min,Max")); - p_list->push_back(PropertyInfo(Variant::REAL, base + "treshold", PROPERTY_HINT_RANGE, "0,1,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, base + "threshold", PROPERTY_HINT_RANGE, "0,1,0.01")); } break; case Ref<InputEvent>::JOYPAD_BUTTON: { p_list->push_back(PropertyInfo(Variant::INT, base + "button_index")); @@ -1455,7 +1456,7 @@ void VisualScriptInputFilter::_get_property_list(List<PropertyInfo> *p_list) con actions = "None"; List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); Vector<String> al; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -1725,6 +1726,20 @@ String VisualScriptTypeCast::get_base_script() const { return script; } +VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGuess *p_inputs, int p_output) const { + + TypeGuess tg; + tg.type = Variant::OBJECT; + if (script != String()) { + tg.script = ResourceLoader::load(script); + } + //if (!tg.script.is_valid()) { + // tg.gdclass = base_type; + //} + + return tg; +} + class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance { public: VisualScriptInstance *instance; @@ -1815,8 +1830,8 @@ void VisualScriptTypeCast::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); } VisualScriptTypeCast::VisualScriptTypeCast() { diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index 314804602e..d27fd47f84 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -261,6 +261,7 @@ public: VisualScriptInputFilter(); }; #endif + class VisualScriptTypeCast : public VisualScriptNode { GDCLASS(VisualScriptTypeCast, VisualScriptNode) @@ -293,6 +294,8 @@ public: void set_base_script(const String &p_path); String get_base_script() const; + virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); VisualScriptTypeCast(); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index e0e1a217b3..c438edd21f 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "visual_script_func_nodes.h" -#include "global_config.h" #include "io/resource_loader.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" #include "visual_script_nodes.h" @@ -347,7 +347,7 @@ void VisualScriptFunctionCall::set_singleton(const StringName &p_path) { return; singleton = p_path; - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { base_type = obj->get_class(); } @@ -383,7 +383,7 @@ void VisualScriptFunctionCall::_update_method_cache() { } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { type = obj->get_class(); script = obj->get_script(); @@ -546,33 +546,33 @@ Dictionary VisualScriptFunctionCall::_get_argument_cache() const { void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const { - if (property.name == "function/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "function/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "function/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "function/singleton") { + if (property.name == "singleton") { if (call_mode != CALL_MODE_SINGLETON) { property.usage = 0; } else { - List<GlobalConfig::Singleton> names; - GlobalConfig::get_singleton()->get_singletons(&names); + List<ProjectSettings::Singleton> names; + ProjectSettings::get_singleton()->get_singletons(&names); property.hint = PROPERTY_HINT_ENUM; String sl; - for (List<GlobalConfig::Singleton>::Element *E = names.front(); E; E = E->next()) { + for (List<ProjectSettings::Singleton>::Element *E = names.front(); E; E = E->next()) { if (sl != String()) sl += ","; sl += E->get().name; @@ -581,7 +581,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -594,7 +594,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/function") { + if (property.name == "function") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -606,7 +606,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const property.hint_string = itos(get_visual_script()->get_instance_ID()); } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; property.hint_string = itos(obj->get_instance_ID()); @@ -648,7 +648,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/use_default_args") { + if (property.name == "use_default_args") { property.hint = PROPERTY_HINT_RANGE; @@ -673,7 +673,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "rpc/call_mode") { + if (property.name == "rpc_call_mode") { if (call_mode == CALL_MODE_BASIC_TYPE) { property.usage = 0; } @@ -735,17 +735,17 @@ void VisualScriptFunctionCall::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/singleton"), "set_singleton", "get_singleton"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "function/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "function/argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_argument_cache", "_get_argument_cache"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/use_default_args"), "set_use_default_args", "get_use_default_args"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "function/validate"), "set_validate", "get_validate"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc/call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "singleton"), "set_singleton", "get_singleton"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_argument_cache", "_get_argument_cache"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT, "use_default_args"), "set_use_default_args", "get_use_default_args"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "validate"), "set_validate", "get_validate"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc_call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count. BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); @@ -867,7 +867,7 @@ public: } break; case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { - Object *object = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *object = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (!object) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid singleton name: '" + String(singleton) + "'"; @@ -1020,6 +1020,18 @@ String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const return String(); } +void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const { + + if (index != StringName()) { + + Variant v; + Variant::CallError ce; + v = Variant::construct(pinfo.type, NULL, 0, ce); + Variant i = v.get(index); + pinfo.type = i.get_type(); + } +} + PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const { if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { @@ -1027,6 +1039,7 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const PropertyInfo pi; pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); + _adjust_input_index(pi); return pi; } else { p_idx--; @@ -1035,6 +1048,7 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const PropertyInfo pinfo = type_cache; pinfo.name = "value"; + _adjust_input_index(pinfo); return pinfo; } @@ -1051,13 +1065,16 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons String VisualScriptPropertySet::get_caption() const { static const char *cname[4] = { - "SelfSet", - "NodeSet", - "InstanceSet", - "BasicSet" + "Self", + "Node", + "Instance", + "Basic" }; - return cname[call_mode]; + static const char *opname[ASSIGN_OP_MAX] = { + "Set", "Add", "Sub", "Mul", "Div", "Mod", "ShiftLeft", "ShiftRight", "BitAnd", "BitOr", "BitXor" + }; + return String(cname[call_mode]) + opname[assign_op]; } String VisualScriptPropertySet::get_text() const { @@ -1073,6 +1090,9 @@ String VisualScriptPropertySet::get_text() const { else if (call_mode == CALL_MODE_INSTANCE) prop = String(base_type) + ":" + property; + if (index != StringName()) { + prop += "." + String(index); + } return prop; } @@ -1236,6 +1256,7 @@ void VisualScriptPropertySet::set_property(const StringName &p_type) { return; property = p_type; + index = StringName(); _update_cache(); _change_notify(); ports_changed_notify(); @@ -1285,27 +1306,58 @@ Dictionary VisualScriptPropertySet::_get_type_cache() const { return type_cache; } +void VisualScriptPropertySet::set_index(const StringName &p_type) { + + if (index == p_type) + return; + index = p_type; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertySet::get_index() const { + + return index; +} + +void VisualScriptPropertySet::set_assign_op(AssignOp p_op) { + + ERR_FAIL_INDEX(p_op, ASSIGN_OP_MAX); + if (assign_op == p_op) + return; + + assign_op = p_op; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const { + return assign_op; +} + void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { - if (property.name == "property/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "property/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "property/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "property/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -1318,7 +1370,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } } - if (property.name == "property/property") { + if (property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -1360,6 +1412,24 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } } } + + if (property.name == "index") { + + Variant::CallError ce; + Variant v = Variant::construct(type_cache.type, NULL, 0, ce); + List<PropertyInfo> plist; + v.get_property_list(&plist); + String options = ""; + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + options += "," + E->get().name; + } + + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = options; + property.type = Variant::STRING; + if (options == "") + property.usage = 0; //hide if type has no usable index + } } void VisualScriptPropertySet::_bind_methods() { @@ -1385,6 +1455,12 @@ void VisualScriptPropertySet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertySet::set_base_path); ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertySet::get_base_path); + ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertySet::set_index); + ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertySet::get_index); + + ClassDB::bind_method(D_METHOD("set_assign_op", "assign_op"), &VisualScriptPropertySet::set_assign_op); + ClassDB::bind_method(D_METHOD("get_assign_op"), &VisualScriptPropertySet::get_assign_op); + String bt; for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (i > 0) @@ -1405,14 +1481,15 @@ void VisualScriptPropertySet::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "property/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/property"), "set_property", "get_property"); - + ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "index"), "set_index", "get_index"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "assign_op", PROPERTY_HINT_ENUM, "Assign,Add,Sub,Mul,Div,Mod,ShiftLeft,ShiftRight,BitAnd,BitOr,Bitxor"), "set_assign_op", "get_assign_op"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); BIND_CONSTANT(CALL_MODE_INSTANCE); @@ -1426,11 +1503,72 @@ public: VisualScriptPropertySet *node; VisualScriptInstance *instance; + VisualScriptPropertySet::AssignOp assign_op; + StringName index; + bool needs_get; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + _FORCE_INLINE_ void _process_get(Variant &source, const Variant &p_argument, bool &valid) { + + if (index != StringName() && assign_op == VisualScriptPropertySet::ASSIGN_OP_NONE) { + source.set_named(index, p_argument, &valid); + } else { + + Variant value; + if (index != StringName()) { + value = source.get_named(index, &valid); + } else { + value = source; + } + + switch (assign_op) { + case VisualScriptPropertySet::ASSIGN_OP_NONE: { + //should never get here + } break; + case VisualScriptPropertySet::ASSIGN_OP_ADD: { + value = Variant::evaluate(Variant::OP_ADD, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SUB: { + value = Variant::evaluate(Variant::OP_SUBSTRACT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_MUL: { + value = Variant::evaluate(Variant::OP_MULTIPLY, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_DIV: { + value = Variant::evaluate(Variant::OP_DIVIDE, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_MOD: { + value = Variant::evaluate(Variant::OP_MODULE, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SHIFT_LEFT: { + value = Variant::evaluate(Variant::OP_SHIFT_LEFT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SHIFT_RIGHT: { + value = Variant::evaluate(Variant::OP_SHIFT_RIGHT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_AND: { + value = Variant::evaluate(Variant::OP_BIT_AND, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_OR: { + value = Variant::evaluate(Variant::OP_BIT_OR, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_XOR: { + value = Variant::evaluate(Variant::OP_BIT_XOR, value, p_argument); + } break; + default: {} + } + + if (index != StringName()) { + source.set_named(index, value, &valid); + } else { + source = value; + } + } + } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { switch (call_mode) { @@ -1441,7 +1579,13 @@ public: bool valid; - object->set(property, *p_inputs[0], &valid); + if (needs_get) { + Variant value = object->get(property, &valid); + _process_get(value, *p_inputs[0], valid); + object->set(property, value, &valid); + } else { + object->set(property, *p_inputs[0], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1466,7 +1610,14 @@ public: bool valid; - another->set(property, *p_inputs[0], &valid); + if (needs_get) { + + Variant value = another->get(property, &valid); + _process_get(value, *p_inputs[0], valid); + another->set(property, value, &valid); + } else { + another->set(property, *p_inputs[0], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1481,7 +1632,14 @@ public: bool valid; - v.set(property, *p_inputs[1], &valid); + if (needs_get) { + Variant value = v.get_named(property, &valid); + _process_get(value, *p_inputs[1], valid); + v.set_named(property, value, &valid); + + } else { + v.set_named(property, *p_inputs[1], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1504,6 +1662,9 @@ VisualScriptNodeInstance *VisualScriptPropertySet::instance(VisualScriptInstance instance->property = property; instance->call_mode = call_mode; instance->node_path = base_path; + instance->assign_op = assign_op; + instance->index = index; + instance->needs_get = index != StringName() || assign_op != ASSIGN_OP_NONE; return instance; } @@ -1517,6 +1678,7 @@ VisualScriptPropertySet::TypeGuess VisualScriptPropertySet::guess_output_type(Ty } VisualScriptPropertySet::VisualScriptPropertySet() { + assign_op = ASSIGN_OP_NONE; call_mode = CALL_MODE_SELF; base_type = "Object"; basic_type = Variant::NIL; @@ -1641,6 +1803,15 @@ PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const { + if (index != StringName()) { + + Variant v; + Variant::CallError ce; + v = Variant::construct(type_cache, NULL, 0, ce); + Variant i = v.get(index); + return PropertyInfo(i.get_type(), "value." + String(index)); + } + return PropertyInfo(type_cache, "value"); } @@ -1867,27 +2038,42 @@ Variant::Type VisualScriptPropertyGet::_get_type_cache() const { return type_cache; } +void VisualScriptPropertyGet::set_index(const StringName &p_type) { + + if (index == p_type) + return; + index = p_type; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertyGet::get_index() const { + + return index; +} + void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { - if (property.name == "property/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "property/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "property/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "property/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -1900,7 +2086,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { } } - if (property.name == "property/property") { + if (property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -1941,6 +2127,24 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { } } } + + if (property.name == "index") { + + Variant::CallError ce; + Variant v = Variant::construct(type_cache, NULL, 0, ce); + List<PropertyInfo> plist; + v.get_property_list(&plist); + String options = ""; + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + options += "," + E->get().name; + } + + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = options; + property.type = Variant::STRING; + if (options == "") + property.usage = 0; //hide if type has no usable index + } } void VisualScriptPropertyGet::_bind_methods() { @@ -1966,6 +2170,9 @@ void VisualScriptPropertyGet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertyGet::set_base_path); ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertyGet::get_base_path); + ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertyGet::set_index); + ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertyGet::get_index); + String bt; for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (i > 0) @@ -1986,13 +2193,14 @@ void VisualScriptPropertyGet::_bind_methods() { script_ext_hint += "." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "property/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "index", PROPERTY_HINT_ENUM), "set_index", "get_index"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); @@ -2004,6 +2212,7 @@ public: VisualScriptPropertyGet::CallMode call_mode; NodePath node_path; StringName property; + StringName index; VisualScriptPropertyGet *node; VisualScriptInstance *instance; @@ -2020,6 +2229,10 @@ public: *p_outputs[0] = object->get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } + if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("Invalid index property name."); @@ -2046,6 +2259,10 @@ public: *p_outputs[0] = another->get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } + if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = vformat(RTR("Invalid index property name '%s' in node %s."), String(property), another->get_name()); @@ -2059,6 +2276,9 @@ public: Variant v = *p_inputs[0]; *p_outputs[0] = v.get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -2079,6 +2299,7 @@ VisualScriptNodeInstance *VisualScriptPropertyGet::instance(VisualScriptInstance instance->property = property; instance->call_mode = call_mode; instance->node_path = base_path; + instance->index = index; return instance; } @@ -2182,7 +2403,7 @@ StringName VisualScriptEmitSignal::get_signal() const { void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "signal/signal") { + if (property.name == "signal") { property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; @@ -2210,7 +2431,7 @@ void VisualScriptEmitSignal::_bind_methods() { ClassDB::bind_method(D_METHOD("set_signal", "name"), &VisualScriptEmitSignal::set_signal); ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptEmitSignal::get_signal); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/signal"), "set_signal", "get_signal"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); } class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 3b284952c5..7839748661 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -146,6 +146,21 @@ public: }; + enum AssignOp { + ASSIGN_OP_NONE, + ASSIGN_OP_ADD, + ASSIGN_OP_SUB, + ASSIGN_OP_MUL, + ASSIGN_OP_DIV, + ASSIGN_OP_MOD, + ASSIGN_OP_SHIFT_LEFT, + ASSIGN_OP_SHIFT_RIGHT, + ASSIGN_OP_BIT_AND, + ASSIGN_OP_BIT_OR, + ASSIGN_OP_BIT_XOR, + ASSIGN_OP_MAX + }; + private: PropertyInfo type_cache; @@ -155,6 +170,8 @@ private: String base_script; NodePath base_path; StringName property; + StringName index; + AssignOp assign_op; Node *_get_base_node() const; StringName _get_base_type() const; @@ -166,6 +183,8 @@ private: void _set_type_cache(const Dictionary &p_type); Dictionary _get_type_cache() const; + void _adjust_input_index(PropertyInfo &pinfo) const; + protected: virtual void _validate_property(PropertyInfo &property) const; @@ -205,6 +224,12 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; + void set_index(const StringName &p_type); + StringName get_index() const; + + void set_assign_op(AssignOp p_op); + AssignOp get_assign_op() const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const; @@ -212,6 +237,7 @@ public: }; VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode); +VARIANT_ENUM_CAST(VisualScriptPropertySet::AssignOp); class VisualScriptPropertyGet : public VisualScriptNode { @@ -234,6 +260,7 @@ private: String base_script; NodePath base_path; StringName property; + StringName index; void _update_base_type(); Node *_get_base_node() const; @@ -283,6 +310,9 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; + void set_index(const StringName &p_type); + StringName get_index() const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); VisualScriptPropertyGet(); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 86c98d076e..69aa10ebca 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "visual_script_nodes.h" -#include "global_config.h" #include "global_constants.h" #include "os/input.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" @@ -59,10 +59,10 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value _change_notify(); return true; } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; + if (String(p_name).begins_with("argument_")) { + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); @@ -104,10 +104,10 @@ bool VisualScriptFunction::_get(const StringName &p_name, Variant &r_ret) const r_ret = arguments.size(); return true; } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; + if (String(p_name).begins_with("argument_")) { + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { r_ret = arguments[idx].type; return true; @@ -144,8 +144,8 @@ void VisualScriptFunction::_get_property_list(List<PropertyInfo> *p_list) const } for (int i = 0; i < arguments.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name")); + p_list->push_back(PropertyInfo(Variant::INT, "argument_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); + p_list->push_back(PropertyInfo(Variant::STRING, "argument_" + itos(i + 1) + "/name")); } if (!stack_less) { p_list->push_back(PropertyInfo(Variant::INT, "stack/size", PROPERTY_HINT_RANGE, "1,100000")); @@ -559,8 +559,8 @@ void VisualScriptOperator::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator_value/type", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "typed_value/typed", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); } class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { @@ -621,6 +621,113 @@ static Ref<VisualScriptNode> create_op_node(const String &p_name) { } ////////////////////////////////////////// +////////////////OPERATOR////////////////// +////////////////////////////////////////// + +int VisualScriptSelect::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSelect::has_input_sequence_port() const { + + return false; +} + +int VisualScriptSelect::get_input_value_port_count() const { + + return 3; +} +int VisualScriptSelect::get_output_value_port_count() const { + + return 1; +} + +String VisualScriptSelect::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSelect::get_input_value_port_info(int p_idx) const { + + if (p_idx == 0) { + return PropertyInfo(Variant::BOOL, "cond"); + } else if (p_idx == 1) { + return PropertyInfo(typed, "a"); + } else { + return PropertyInfo(typed, "b"); + } +} +PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { + + return PropertyInfo(typed, "out"); +} + +String VisualScriptSelect::get_caption() const { + + return "Select"; +} + +String VisualScriptSelect::get_text() const { + + return "a if cond, else b"; +} + +void VisualScriptSelect::set_typed(Variant::Type p_op) { + + if (typed == p_op) + return; + + typed = p_op; + ports_changed_notify(); +} + +Variant::Type VisualScriptSelect::get_typed() const { + + return typed; +} + +void VisualScriptSelect::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptSelect::set_typed); + ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptSelect::get_typed); + + String argt = "Any"; + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + argt += "," + Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); +} + +class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { +public: + //virtual int get_working_memory_size() const { return 0; } + + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { + + bool cond = *p_inputs[0]; + if (cond) + *p_outputs[0] = *p_inputs[1]; + else + *p_outputs[0] = *p_inputs[2]; + + return 0; + } +}; + +VisualScriptNodeInstance *VisualScriptSelect::instance(VisualScriptInstance *p_instance) { + + VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); + return instance; +} + +VisualScriptSelect::VisualScriptSelect() { + + typed = Variant::NIL; +} + +////////////////////////////////////////// ////////////////VARIABLE GET////////////////// ////////////////////////////////////////// @@ -691,7 +798,7 @@ StringName VisualScriptVariableGet::get_variable() const { void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { - if (property.name == "variable/name" && get_visual_script().is_valid()) { + if (property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -714,7 +821,7 @@ void VisualScriptVariableGet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableGet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableGet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_variable", "get_variable"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { @@ -816,7 +923,7 @@ StringName VisualScriptVariableSet::get_variable() const { void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { - if (property.name == "variable/name" && get_visual_script().is_valid()) { + if (property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -839,7 +946,7 @@ void VisualScriptVariableSet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableSet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableSet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_variable", "get_variable"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { @@ -956,7 +1063,7 @@ Variant VisualScriptConstant::get_constant_value() const { void VisualScriptConstant::_validate_property(PropertyInfo &property) const { - if (property.name == "constant/value") { + if (property.name == "value") { property.type = type; if (type == Variant::NIL) property.usage = 0; //do not save if nil @@ -969,15 +1076,15 @@ void VisualScriptConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("get_constant_type"), &VisualScriptConstant::get_constant_type); ClassDB::bind_method(D_METHOD("set_constant_value", "value"), &VisualScriptConstant::set_constant_value); - ClassDB::bind_method(D_METHOD("get_constant_value"), &VisualScriptConstant::get_constant_value); + ClassDB::bind_method(D_METHOD("get_constant_value:Variant"), &VisualScriptConstant::get_constant_value); String argt = "Null"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "constant/type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "constant/value"), "set_constant_value", "get_constant_value"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); + ADD_PROPERTY(PropertyInfo(Variant::NIL, "value"), "set_constant_value", "get_constant_value"); } class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { @@ -1083,8 +1190,8 @@ Ref<Resource> VisualScriptPreload::get_preload() const { void VisualScriptPreload::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_preload", "resource"), &VisualScriptPreload::set_preload); - ClassDB::bind_method(D_METHOD("get_preload"), &VisualScriptPreload::get_preload); + ClassDB::bind_method(D_METHOD("set_preload", "resource:Resource"), &VisualScriptPreload::set_preload); + ClassDB::bind_method(D_METHOD("get_preload:Resource"), &VisualScriptPreload::get_preload); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "set_preload", "get_preload"); } @@ -1832,17 +1939,17 @@ public: VisualScriptNodeInstance *VisualScriptEngineSingleton::instance(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); - instance->singleton = GlobalConfig::get_singleton()->get_singleton_object(singleton); + instance->singleton = ProjectSettings::get_singleton()->get_singleton_object(singleton); return instance; } VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess *p_inputs, int p_output) const { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); TypeGuess tg; tg.type = Variant::OBJECT; if (obj) { - tg.GDCLASS = obj->get_class(); + tg.gdclass = obj->get_class(); tg.script = obj->get_script(); } @@ -1856,11 +1963,11 @@ void VisualScriptEngineSingleton::_bind_methods() { String cc; - List<GlobalConfig::Singleton> singletons; + List<ProjectSettings::Singleton> singletons; - GlobalConfig::get_singleton()->get_singletons(&singletons); + ProjectSettings::get_singleton()->get_singletons(&singletons); - for (List<GlobalConfig::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { if (E->get().name == "VS" || E->get().name == "PS" || E->get().name == "PS2D" || E->get().name == "AS" || E->get().name == "TS" || E->get().name == "SS" || E->get().name == "SS2D") continue; //skip these, too simple named @@ -2002,7 +2109,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "Node"; + tg.gdclass = "Node"; #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); @@ -2031,7 +2138,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu Node *another = script_node->get_node(path); if (another) { - tg.GDCLASS = another->get_class(); + tg.gdclass = another->get_class(); tg.script = another->get_script(); } #endif @@ -2173,7 +2280,7 @@ VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGu TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "SceneTree"; + tg.gdclass = "SceneTree"; return tg; } @@ -2353,13 +2460,13 @@ VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess *p_inp VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "Object"; + tg.gdclass = "Object"; Ref<Script> script = get_visual_script(); if (!script.is_valid()) return tg; - tg.GDCLASS = script->get_instance_base_type(); + tg.gdclass = script->get_instance_base_type(); tg.script = script; return tg; @@ -2489,10 +2596,10 @@ public: in_values.resize(in_count); for (int i = 0; i < in_count; i++) { - in_values[i] = p_inputs[i]; + in_values[i] = *p_inputs[i]; } - out_values.resize(in_count); + out_values.resize(out_count); work_mem.resize(work_mem_size); @@ -2538,6 +2645,7 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode); instance->instance = p_instance; + instance->node = this; instance->in_count = get_input_value_port_count(); instance->out_count = get_output_value_port_count(); @@ -2550,6 +2658,10 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance return instance; } +void VisualScriptCustomNode::_script_changed() { + ports_changed_notify(); +} + void VisualScriptCustomNode::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_sequence_port_count")); @@ -2572,6 +2684,8 @@ void VisualScriptCustomNode::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::INT, "_get_working_memory_size")); BIND_VMETHOD(MethodInfo(Variant::NIL, "_step:Variant", PropertyInfo(Variant::ARRAY, "inputs"), PropertyInfo(Variant::ARRAY, "outputs"), PropertyInfo(Variant::INT, "start_mode"), PropertyInfo(Variant::ARRAY, "working_mem"))); + ClassDB::bind_method(D_METHOD("_script_changed"), &VisualScriptCustomNode::_script_changed); + BIND_CONSTANT(START_MODE_BEGIN_SEQUENCE); BIND_CONSTANT(START_MODE_CONTINUE_SEQUENCE); BIND_CONSTANT(START_MODE_RESUME_YIELD); @@ -2584,6 +2698,7 @@ void VisualScriptCustomNode::_bind_methods() { } VisualScriptCustomNode::VisualScriptCustomNode() { + connect("script_changed", this, "_script_changed"); } ////////////////////////////////////////// @@ -3088,8 +3203,8 @@ void VisualScriptLocalVar::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "variable/type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); } VisualScriptLocalVar::VisualScriptLocalVar() { @@ -3210,8 +3325,8 @@ void VisualScriptLocalVarSet::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "variable/type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); } VisualScriptLocalVarSet::VisualScriptLocalVarSet() { @@ -3253,32 +3368,33 @@ PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const } PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::BOOL, "pressed"); -} - -String VisualScriptInputAction::get_caption() const { - - return "Action"; -} - -String VisualScriptInputAction::get_text() const { - + String mstr; switch (mode) { case MODE_PRESSED: { - return name; + mstr = "pressed"; } break; case MODE_RELEASED: { - return "not " + name; + mstr = "not pressed"; } break; case MODE_JUST_PRESSED: { - return String(name) + " " + TTR("just pressed"); + mstr = "just pressed"; } break; case MODE_JUST_RELEASED: { - return String(name) + " " + TTR("just released"); + mstr = "just released"; } break; } - return String(); + return PropertyInfo(Variant::BOOL, mstr); +} + +String VisualScriptInputAction::get_caption() const { + + return "Action"; +} + +String VisualScriptInputAction::get_text() const { + + return name; } String VisualScriptInputAction::get_category() const { @@ -3319,8 +3435,6 @@ public: StringName action; VisualScriptInputAction::Mode mode; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { switch (mode) { @@ -3360,7 +3474,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { String actions; List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); Vector<String> al; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -3628,6 +3742,7 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("operators/logic/xor", create_op_node<Variant::OP_XOR>); VisualScriptLanguage::singleton->add_register_func("operators/logic/not", create_op_node<Variant::OP_NOT>); VisualScriptLanguage::singleton->add_register_func("operators/logic/in", create_op_node<Variant::OP_IN>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct", create_node_generic<VisualScriptDeconstruct>); diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 402093fa80..7a3b26fe55 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -127,6 +127,39 @@ public: VisualScriptOperator(); }; +class VisualScriptSelect : public VisualScriptNode { + + GDCLASS(VisualScriptSelect, VisualScriptNode) + + Variant::Type typed; + +protected: + static void _bind_methods(); + +public: + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + virtual String get_output_sequence_port_text(int p_port) const; + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "operators"; } + + void set_typed(Variant::Type p_op); + Variant::Type get_typed() const; + + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); + + VisualScriptSelect(); +}; + class VisualScriptVariableGet : public VisualScriptNode { GDCLASS(VisualScriptVariableGet, VisualScriptNode) @@ -679,6 +712,8 @@ public: virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); + void _script_changed(); + VisualScriptCustomNode(); }; diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index be5b218d0a..2e111511b7 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -419,13 +419,13 @@ VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "signal/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "signal/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -438,7 +438,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { } } - if (property.name == "signal/signal") { + if (property.name == "signal") { property.hint = PROPERTY_HINT_ENUM; List<MethodInfo> methods; @@ -488,10 +488,10 @@ void VisualScriptYieldSignal::_bind_methods() { bt += Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "signal/call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "signal/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/signal"), "set_signal", "get_signal"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index eaf4215302..72f10b4f45 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -34,8 +34,8 @@ #include "mkvparser/mkvparser.h" -#include "global_config.h" #include "os/file_access.h" +#include "project_settings.h" #include "thirdparty/misc/yuv2rgb.h" @@ -168,7 +168,7 @@ void VideoStreamPlaybackWebm::play() { stop(); - delay_compensation = GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms"); delay_compensation /= 1000.0; playing = true; |