diff options
46 files changed, 992 insertions, 280 deletions
diff --git a/core/string_buffer.cpp b/core/string_buffer.cpp deleted file mode 100644 index aac2090378..0000000000 --- a/core/string_buffer.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************/ -/* string_buffer.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 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 "string_buffer.h" - -#include <string.h> - -StringBuffer &StringBuffer::append(CharType p_char) { - reserve(string_length + 2); - current_buffer_ptr()[string_length++] = p_char; - return *this; -} - -StringBuffer &StringBuffer::append(const String &p_string) { - return append(p_string.c_str()); -} - -StringBuffer &StringBuffer::append(const char *p_str) { - int len = strlen(p_str); - reserve(string_length + len + 1); - - CharType *buf = current_buffer_ptr(); - for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) { - buf[string_length++] = *c_ptr; - } - return *this; -} - -StringBuffer &StringBuffer::append(const CharType *p_str, int p_clip_to_len) { - int len = 0; - while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) { - ++len; - } - reserve(string_length + len + 1); - memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType)); - string_length += len; - - return *this; -} - -StringBuffer &StringBuffer::reserve(int p_size) { - if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size()) - return *this; - - bool need_copy = string_length > 0 && buffer.empty(); - buffer.resize(next_power_of_2(p_size)); - if (need_copy) { - memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType)); - } - - return *this; -} - -int StringBuffer::length() const { - return string_length; -} - -String StringBuffer::as_string() { - current_buffer_ptr()[string_length] = '\0'; - if (buffer.empty()) { - return String(short_buffer); - } else { - buffer.resize(string_length + 1); - return buffer; - } -} - -double StringBuffer::as_double() { - current_buffer_ptr()[string_length] = '\0'; - return String::to_double(current_buffer_ptr()); -} - -int64_t StringBuffer::as_int() { - current_buffer_ptr()[string_length] = '\0'; - return String::to_int(current_buffer_ptr()); -} diff --git a/core/string_buffer.h b/core/string_buffer.h index f0ead66bb8..b148e45544 100644 --- a/core/string_buffer.h +++ b/core/string_buffer.h @@ -32,9 +32,10 @@ #define STRING_BUFFER_H #include "ustring.h" +#include <string.h> +template <int SHORT_BUFFER_SIZE = 64> class StringBuffer { - static const int SHORT_BUFFER_SIZE = 64; CharType short_buffer[SHORT_BUFFER_SIZE]; String buffer; @@ -80,4 +81,83 @@ public: } }; +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharType p_char) { + reserve(string_length + 2); + current_buffer_ptr()[string_length++] = p_char; + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const String &p_string) { + return append(p_string.c_str()); +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char *p_str) { + int len = strlen(p_str); + reserve(string_length + len + 1); + + CharType *buf = current_buffer_ptr(); + for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) { + buf[string_length++] = *c_ptr; + } + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const CharType *p_str, int p_clip_to_len) { + int len = 0; + while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) { + ++len; + } + reserve(string_length + len + 1); + memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType)); + string_length += len; + + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_size) { + if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size()) + return *this; + + bool need_copy = string_length > 0 && buffer.empty(); + buffer.resize(next_power_of_2(p_size)); + if (need_copy) { + memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType)); + } + + return *this; +} + +template <int SHORT_BUFFER_SIZE> +int StringBuffer<SHORT_BUFFER_SIZE>::length() const { + return string_length; +} + +template <int SHORT_BUFFER_SIZE> +String StringBuffer<SHORT_BUFFER_SIZE>::as_string() { + current_buffer_ptr()[string_length] = '\0'; + if (buffer.empty()) { + return String(short_buffer); + } else { + buffer.resize(string_length + 1); + return buffer; + } +} + +template <int SHORT_BUFFER_SIZE> +double StringBuffer<SHORT_BUFFER_SIZE>::as_double() { + current_buffer_ptr()[string_length] = '\0'; + return String::to_double(current_buffer_ptr()); +} + +template <int SHORT_BUFFER_SIZE> +int64_t StringBuffer<SHORT_BUFFER_SIZE>::as_int() { + current_buffer_ptr()[string_length] = '\0'; + return String::to_int(current_buffer_ptr()); +} + #endif diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 54edb02347..446aee286d 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -178,7 +178,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri }; case '#': { - StringBuffer color_str; + StringBuffer<> color_str; color_str += '#'; while (true) { CharType ch = p_stream->get_char(); @@ -299,7 +299,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri if (cchar == '-' || (cchar >= '0' && cchar <= '9')) { //a number - StringBuffer num; + StringBuffer<> num; #define READING_SIGN 0 #define READING_INT 1 #define READING_DEC 2 @@ -378,7 +378,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') { - StringBuffer id; + StringBuffer<> id; bool first = true; while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) { diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index d4bd937f49..4e9a6a5fc0 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -608,6 +608,7 @@ <description> Parse JSON text to a Variant (use [method typeof] to check if it is what you expect). Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to [float] types. + Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: [codeblock] p = parse_json('["a", "b", "c"]') if typeof(p) == TYPE_ARRAY: diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index e69c05c3df..078c293fc0 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -4,7 +4,7 @@ Helper class for parsing JSON data. </brief_description> <description> - Helper class for parsing JSON data. For usage example, see [JSONParseResult]. + Helper class for parsing JSON data. For usage example and other important hints, see [JSONParseResult]. </description> <tutorials> </tutorials> diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml index 424720a871..18313beaf8 100644 --- a/doc/classes/JSONParseResult.xml +++ b/doc/classes/JSONParseResult.xml @@ -4,7 +4,7 @@ Data class wrapper for decoded JSON. </brief_description> <description> - Returned by [method JSON.parse], [code]JSONParseResult[/code] contains decoded JSON or error information if JSON source not successfully parsed. You can check if JSON source was successfully parsed with [code]if json_result.error == 0[/code]. + Returned by [method JSON.parse], [code]JSONParseResult[/code] contains decoded JSON or error information if JSON source not successfully parsed. You can check if JSON source was successfully parsed with [code]if json_result.error == OK[/code]. </description> <tutorials> </tutorials> @@ -24,11 +24,12 @@ </member> <member name="result" type="Variant" setter="set_result" getter="get_result"> A [Variant] containing the parsed JSON. Use typeof() to check if it is what you expect. For example, if JSON source starts with curly braces ([code]{}[/code]) a [Dictionary] will be returned, if JSON source starts with braces ([code][][/code]) an [Array] will be returned. - [i]Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to float types.[/i] + [i]Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to float types. + Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:[/i] [codeblock] - p = JSON.parse('["hello", "world", "!"]') - if typeof(p) == TYPE_ARRAY: - print(p[0]) # prints 'hello' + var p = JSON.parse('["hello", "world", "!"]') + if typeof(p.result) == TYPE_ARRAY: + print(p.result[0]) # prints 'hello' else: print("unexpected results") [/codeblock] diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 91aa189c8f..cd8233e460 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1359,7 +1359,7 @@ void AnimationKeyEditor::_track_editor_draw() { Color ncol = color; if (n && editor_selection->is_selected(n)) ncol = track_select_color; - te->draw_string(font, Point2(ofs + Point2(left_check_ofs + sep + type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5); + te->draw_string(font, Point2(ofs + Point2(left_check_ofs + sep + type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (left_check_ofs + sep) - (type_icon[0]->get_width() + sep) - 5); // Draw separator line below track area if (!obj) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 98991cd7c0..bec6d581f8 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -339,7 +339,7 @@ void EditorNode::_notification(int p_what) { if (ScriptEditor::get_singleton()->get_debugger()->is_visible()) bottom_panel->add_style_override("panel", gui_base->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")); - //_update_icons + // update_icons for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { Ref<Texture> icon = singleton->main_editor_buttons[i]->get_icon(); @@ -709,7 +709,7 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) { case ERR_CANT_OPEN: { - accept->set_text(vformat(TTR("Can't open '%s'."), p_file.get_file())); + accept->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file())); } break; case ERR_PARSE_ERROR: { @@ -1110,7 +1110,7 @@ void EditorNode::_dialog_action(String p_file) { if (res.is_null()) { current_option = -1; - accept->get_ok()->set_text("ok :("); + accept->get_ok()->set_text("Ugh"); accept->set_text(TTR("Failed to load resource.")); return; }; @@ -1145,6 +1145,7 @@ void EditorNode::_dialog_action(String p_file) { _save_default_environment(); _save_scene_with_preview(p_file, scene_idx); + _add_to_recent_scenes(p_file); if (scene_idx != -1) _discard_changes(); @@ -1919,7 +1920,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!scene) { current_option = -1; - //confirmation->get_cancel()->hide(); accept->get_ok()->set_text(TTR("I see..")); accept->set_text(TTR("This operation can't be done without a tree root.")); accept->popup_centered_minsize(); @@ -1937,7 +1937,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } - //file->set_current_path(current_path); if (scene->get_filename() != "") { file->set_current_path(scene->get_filename()); if (extensions.size()) { @@ -1987,7 +1986,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!editor_data.get_edited_scene_root()) { current_option = -1; - //confirmation->get_cancel()->hide(); accept->get_ok()->set_text(TTR("I see..")); accept->set_text(TTR("This operation can't be done without a scene.")); accept->popup_centered_minsize(); @@ -2036,8 +2034,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case FILE_IMPORT_SUBSCENE: { - //import_subscene->popup_centered_ratio(); - if (!editor_data.get_edited_scene_root()) { current_option = -1; @@ -2056,7 +2052,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (unsaved_cache && !p_confirmed) { confirmation->get_ok()->set_text(TTR("Open")); - //confirmation->get_cancel()->show(); confirmation->set_text(TTR("Current scene not saved. Open anyway?")); confirmation->popup_centered_minsize(); break; @@ -2843,7 +2838,7 @@ void EditorNode::_remove_scene(int index) { //Scene to remove is current scene _remove_edited_scene(); } else { - // Scene to remove is not active scene + //Scene to remove is not active scene editor_data.remove_scene(index); } } @@ -3240,48 +3235,47 @@ void EditorNode::_show_messages() { void EditorNode::_add_to_recent_scenes(const String &p_scene) { - String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); - Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); - String name = p_scene; - name = name.replace("res://", ""); - if (rc.find(name) != -1) - rc.erase(name); - rc.insert(0, name); + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scenes", Array()); + if (rc.find(p_scene) != -1) + rc.erase(p_scene); + rc.push_front(p_scene); if (rc.size() > 10) rc.resize(10); - EditorSettings::get_singleton()->set(base + "/_recent_scenes", rc); - EditorSettings::get_singleton()->save(); + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", rc); _update_recent_scenes(); } void EditorNode::_open_recent_scene(int p_idx) { - String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); - if (p_idx == recent_scenes->get_item_count() - 1) { - EditorSettings::get_singleton()->erase(base + "/_recent_scenes"); + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", Array()); call_deferred("_update_recent_scenes"); } else { - Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scenes", Array()); ERR_FAIL_INDEX(p_idx, rc.size()); - String path = "res://" + rc[p_idx]; - load_scene(path); + if (load_scene(rc[p_idx]) != OK) { + + rc.remove(p_idx); + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", rc); + _update_recent_scenes(); + } } } void EditorNode::_update_recent_scenes() { - String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); - Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scenes", Array()); recent_scenes->clear(); + String path; for (int i = 0; i < rc.size(); i++) { - recent_scenes->add_item(rc[i], i); + path = rc[i]; + recent_scenes->add_item(path.replace("res://", ""), i); } recent_scenes->add_separator(); @@ -5118,7 +5112,6 @@ EditorNode::EditorNode() { gui_base->add_child(dependency_fixer); settings_config_dialog = memnew(EditorSettingsDialog); - // settings_config_dialog->add_style_override("panel", gui_base->get_stylebox("EditorSettingsDialog", "EditorStyles")); gui_base->add_child(settings_config_dialog); project_settings = memnew(ProjectSettingsEditor(&editor_data)); @@ -5192,7 +5185,6 @@ EditorNode::EditorNode() { p->add_item(TTR("Project Settings"), RUN_SETTINGS); p->add_separator(); p->connect("id_pressed", this, "_menu_option"); - //p->add_item(TTR("Run Script"), FILE_RUN_SCRIPT, KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_R); p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); PopupMenu *tool_menu = memnew(PopupMenu); @@ -5283,7 +5275,6 @@ EditorNode::EditorNode() { menu_hb->add_child(play_cc); play_button_panel = memnew(PanelContainer); - // play_button_panel->add_style_override("panel", gui_base->get_stylebox("PlayButtonPanel", "EditorStyles")); play_cc->add_child(play_button_panel); HBoxContainer *play_hb = memnew(HBoxContainer); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 433f501fc8..c6676a1f0f 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -382,8 +382,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/completion/callhint_tooltip_offset", Vector2()); _initial_set("text_editor/files/restore_scripts_on_load", true); _initial_set("text_editor/completion/complete_file_paths", true); - _initial_set("text_editor/files/maximum_recent_files", 20); - hints["text_editor/files/maximum_recent_files"] = PropertyInfo(Variant::INT, "text_editor/files/maximum_recent_files", PROPERTY_HINT_RANGE, "1, 200, 1"); _initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false); _initial_set("docks/scene_tree/draw_relationship_lines", false); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 915132c75c..b8bf2b97f6 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -316,7 +316,6 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data) { String error_text; - print_line("COMPLETED: " + itos(p_status) + " code: " + itos(p_code) + " data size: " + itos(p_data.size())); switch (p_status) { @@ -371,7 +370,6 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int progress->set_max(download->get_body_size()); progress->set_value(download->get_downloaded_bytes()); - print_line("max: " + itos(download->get_body_size()) + " bytes: " + itos(download->get_downloaded_bytes())); install->set_disabled(false); progress->set_value(download->get_downloaded_bytes()); @@ -747,8 +745,6 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons if (p_status == HTTPRequest::RESULT_SUCCESS) { - print_line("GOT IMAGE YAY!"); - if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag @@ -811,7 +807,6 @@ void EditorAssetLibrary::_update_image_queue() { } } - print_line("REQUEST ICON FOR: " + itos(E->get().asset_id)); Error err = E->get().request->request(E->get().image_url, headers); if (err != OK) { to_delete.push_back(E->key()); @@ -855,7 +850,6 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag void EditorAssetLibrary::_repository_changed(int p_repository_id) { host = repository->get_item_metadata(p_repository_id); - print_line(".." + host); if (templates_only) { _api_request("configure", REQUESTING_CONFIG, "?type=project"); } else { @@ -1066,8 +1060,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const return; } - print_line("response: " + itos(p_status) + " code: " + itos(p_code)); - Dictionary d; { Variant js; @@ -1077,8 +1069,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const d = js; } - print_line(Variant(d).get_construct_string()); - RequestType requested = requesting; requesting = REQUESTING_NONE; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 7d6025cb03..90969752d3 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4225,9 +4225,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p = view_menu->get_popup(); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid"), KEY_G), SHOW_GRID); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show helpers"), KEY_H), SHOW_HELPERS); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show rulers"), KEY_R), SHOW_RULERS); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show guides"), KEY_Y), SHOW_GUIDES); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers"), KEY_R), SHOW_RULERS); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d18422c0c0..5befbbae8d 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -429,36 +429,32 @@ void ScriptEditor::_add_recent_script(String p_path) { return; } - // remove if already stored - int already_recent = previous_scripts.find(p_path); - if (already_recent >= 0) { - previous_scripts.remove(already_recent); + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); + if (rc.find(p_path) != -1) { + rc.erase(p_path); + } + rc.push_front(p_path); + if (rc.size() > 10) { + rc.resize(10); } - // add to list - previous_scripts.insert(0, p_path); - + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", rc); _update_recent_scripts(); } void ScriptEditor::_update_recent_scripts() { - // make sure we don't exceed max size - const int max_history = EDITOR_DEF("text_editor/files/maximum_recent_files", 20); - if (previous_scripts.size() > max_history) { - previous_scripts.resize(max_history); - } - + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); recent_scripts->clear(); recent_scripts->add_shortcut(ED_SHORTCUT("script_editor/open_recent", TTR("Open Recent"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T)); recent_scripts->add_separator(); - const int max_shown = 8; - for (int i = 0; i < previous_scripts.size() && i <= max_shown; i++) { - String path = previous_scripts.get(i); - // just show script name and last dir - recent_scripts->add_item(path.get_slice("/", path.get_slice_count("/") - 2) + "/" + path.get_file()); + String path; + for (int i = 0; i < rc.size(); i++) { + + path = rc[i]; + recent_scripts->add_item(path.replace("res://", "")); } recent_scripts->add_separator(); @@ -471,7 +467,7 @@ void ScriptEditor::_open_recent_script(int p_idx) { // clear button if (p_idx == recent_scripts->get_item_count() - 1) { - previous_scripts.clear(); + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", Array()); call_deferred("_update_recent_scripts"); return; } @@ -481,22 +477,34 @@ void ScriptEditor::_open_recent_script(int p_idx) { p_idx -= 2; } - if (p_idx < previous_scripts.size() && p_idx >= 0) { + Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); + ERR_FAIL_INDEX(p_idx, rc.size()); - String path = previous_scripts.get(p_idx); - // if its not on disk its a help file or deleted - if (FileAccess::exists(path)) { - Ref<Script> script = ResourceLoader::load(path); - if (script.is_valid()) { - edit(script, true); - } - // if it's a path then its most likely a delted file not help - } else if (!path.is_resource_file()) { - _help_class_open(path); + String path = rc[p_idx]; + // if its not on disk its a help file or deleted + if (FileAccess::exists(path)) { + Ref<Script> script = ResourceLoader::load(path); + if (script.is_valid()) { + edit(script, true); + return; } - previous_scripts.remove(p_idx); - _update_recent_scripts(); + + // if it's a path then its most likely a deleted file not help + } else if (!path.is_resource_file()) { + _help_class_open(path); + return; } + + rc.remove(p_idx); + EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", rc); + _update_recent_scripts(); + _show_error_dialog(path); +} + +void ScriptEditor::_show_error_dialog(String p_path) { + + error_dialog->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_path)); + error_dialog->popup_centered_minsize(); } void ScriptEditor::_close_tab(int p_idx, bool p_save) { @@ -508,14 +516,10 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { Node *tselected = tab_container->get_child(selected); ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); if (current) { - _add_recent_script(current->get_edited_script()->get_path()); if (p_save) { apply_scripts(); } notify_script_close(current->get_edited_script()); - } else { - EditorHelp *help = Object::cast_to<EditorHelp>(tab_container->get_child(selected)); - _add_recent_script(help->get_class()); } // roll back to previous tab @@ -1690,28 +1694,42 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); - Dictionary keys; - keys["project"] = ProjectSettings::get_singleton()->get_resource_path(); - keys["file"] = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); - keys["line"] = p_line >= 0 ? p_line : 0; - keys["col"] = p_col; - - flags = flags.format(keys).strip_edges().replace("\\\\", "\\"); - List<String> args; if (flags.size()) { - int from = 0, to = 0; + String project_path = ProjectSettings::get_singleton()->get_resource_path(); + String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); + + flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0)); + flags = flags.replacen("{col}", itos(p_col)); + flags = flags.strip_edges().replace("\\\\", "\\"); + + int from = 0; + int num_chars = 0; bool inside_quotes = false; + for (int i = 0; i < flags.size(); i++) { + if (flags[i] == '"' && (!i || flags[i - 1] != '\\')) { + + if (!inside_quotes) { + from++; + } inside_quotes = !inside_quotes; + } else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) { - args.push_back(flags.substr(from, to)); + + String arg = flags.substr(from, num_chars); + + // do path replacement here, else there will be issues with spaces and quotes + arg = arg.replacen("{project}", project_path); + arg = arg.replacen("{file}", script_path); + args.push_back(arg); + from = i + 1; - to = 0; + num_chars = 0; } else { - to++; + num_chars++; } } } @@ -1787,6 +1805,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool se->goto_line(p_line - 1); notify_script_changed(p_script); + _add_recent_script(p_script->get_path()); return true; } @@ -2304,6 +2323,7 @@ void ScriptEditor::_help_class_open(const String &p_class) { _go_to_tab(tab_container->get_tab_count() - 1); eh->go_to_class(p_class, 0); eh->connect("go_to_help", this, "_help_class_goto"); + _add_recent_script(p_class); _update_script_names(); _save_layout(); } @@ -2332,6 +2352,7 @@ void ScriptEditor::_help_class_goto(const String &p_desc) { _go_to_tab(tab_container->get_tab_count() - 1); eh->go_to_help(p_desc); eh->connect("go_to_help", this, "_help_class_goto"); + _add_recent_script(eh->get_class()); _update_script_names(); _save_layout(); } @@ -2738,6 +2759,10 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { add_child(file_dialog); file_dialog->connect("file_selected", this, "_file_dialog_action"); + error_dialog = memnew(AcceptDialog); + add_child(error_dialog); + error_dialog->get_ok()->set_text(TTR("I see..")); + debugger = memnew(ScriptEditorDebugger(editor)); debugger->connect("goto_script_line", this, "_goto_script_line"); debugger->connect("show_debugger", this, "_show_debugger"); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index e60e4cf8c0..e98a4c97a6 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -198,6 +198,7 @@ class ScriptEditor : public PanelContainer { VSplitContainer *list_split; TabContainer *tab_container; EditorFileDialog *file_dialog; + AcceptDialog *error_dialog; ConfirmationDialog *erase_tab_confirm; ScriptCreateDialog *script_create_dialog; ScriptEditorDebugger *debugger; @@ -227,8 +228,6 @@ class ScriptEditor : public PanelContainer { Vector<ScriptHistory> history; int history_pos; - Vector<String> previous_scripts; - EditorHelpIndex *help_index; void _tab_changed(int p_which); @@ -250,6 +249,8 @@ class ScriptEditor : public PanelContainer { void _update_recent_scripts(); void _open_recent_script(int p_idx); + void _show_error_dialog(String p_path); + void _close_tab(int p_idx, bool p_save = true); void _close_current_tab(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index a3728a1d46..87e92f0807 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -519,6 +519,7 @@ void ScriptTextEditor::tag_saved_version() { void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { TextEdit *tx = code_editor->get_text_edit(); + tx->deselect(); tx->unfold_line(p_line); tx->call_deferred("cursor_set_line", p_line); } @@ -1283,12 +1284,9 @@ Variant ScriptTextEditor::get_drag_data_fw(const Point2 &p_point, Control *p_fro bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { Dictionary d = p_data; - if (d.has("type") && - ( - - String(d["type"]) == "resource" || - String(d["type"]) == "files" || - String(d["type"]) == "nodes")) { + if (d.has("type") && (String(d["type"]) == "resource" || + String(d["type"]) == "files" || + String(d["type"]) == "nodes")) { return true; } @@ -1329,6 +1327,10 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data Dictionary d = p_data; + TextEdit *te = code_editor->get_text_edit(); + int row, col; + te->_get_mouse_pos(p_point, row, col); + if (d.has("type") && String(d["type"]) == "resource") { Ref<Resource> res = d["resource"]; @@ -1341,7 +1343,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data return; } - code_editor->get_text_edit()->insert_text_at_cursor(res->get_path()); + te->cursor_set_line(row); + te->cursor_set_column(col); + te->insert_text_at_cursor(res->get_path()); } if (d.has("type") && String(d["type"]) == "files") { @@ -1356,7 +1360,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } - code_editor->get_text_edit()->insert_text_at_cursor(text_to_drop); + te->cursor_set_line(row); + te->cursor_set_column(col); + te->insert_text_at_cursor(text_to_drop); } if (d.has("type") && String(d["type"]) == "nodes") { @@ -1385,7 +1391,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data text_to_drop += "\"" + path.c_escape() + "\""; } - code_editor->get_text_edit()->insert_text_at_cursor(text_to_drop); + te->cursor_set_line(row); + te->cursor_set_column(col); + te->insert_text_at_cursor(text_to_drop); } } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 058f517ae9..9625bc19c0 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1595,7 +1595,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); props_base->add_child(hbc); - search_button = memnew(ToolButton); + search_button = memnew(Button); search_button->set_toggle_mode(true); search_button->set_pressed(false); search_button->set_text(TTR("Search")); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index d6c2c0f5a8..452cf5b060 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -67,7 +67,7 @@ class ProjectSettingsEditor : public AcceptDialog { SectionedPropertyEditor *globals_editor; HBoxContainer *search_bar; - ToolButton *search_button; + Button *search_button; LineEdit *search_box; ToolButton *clear_button; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 41ee5ab286..8506c75a68 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -67,6 +67,9 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { if (get_viewport()->get_modal_stack_top()) return; //ignore because of modal window + if (get_focus_owner() && get_focus_owner()->is_text_field()) + return; + if (!p_event->is_pressed() || p_event->is_echo()) return; diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 72c0f050d2..8c90d86b9e 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -308,15 +308,6 @@ void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), cubem.surface_get_arrays(0)); m->surface_set_material(0, p_material); add_mesh(m); - - Instance ins; - ins.mesh = m; - if (valid) { - ins.create_instance(spatial_node); - VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); - } - - instances.push_back(ins); } void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { @@ -1130,7 +1121,7 @@ void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { Transform gt = camera->get_global_transform(); float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt); - camera->set("fov", a); + camera->set("fov", a * 2.0); } else { Vector3 ra, rb; @@ -1187,7 +1178,8 @@ void CameraSpatialGizmo::redraw() { case Camera::PROJECTION_PERSPECTIVE: { - float fov = camera->get_fov(); + // The real FOV is halved for accurate representation + float fov = camera->get_fov() / 2.0; Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov))); Vector3 nside = side; diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 51de4998fa..b646fc164d 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -70,8 +70,8 @@ return RID(); \ } -#define AddJointToSpace(body, joint, disableCollisionsBetweenLinkedBodies) \ - body->get_space()->add_constraint(joint, disableCollisionsBetweenLinkedBodies); +#define AddJointToSpace(body, joint) \ + body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies()); // <--------------- Joint creation asserts btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty()); @@ -987,6 +987,20 @@ int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const { return 0; } +void BulletPhysicsServer::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); +} + +bool BulletPhysicsServer::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + JointBullet *joint(joint_owner.get(p_joint)); + ERR_FAIL_COND_V(!joint, false); + + return joint->is_disabled_collisions_between_bodies(); +} + RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); @@ -1003,7 +1017,7 @@ RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1071,7 +1085,7 @@ RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hin ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1091,7 +1105,7 @@ RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 & ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1143,7 +1157,7 @@ RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_lo ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1177,7 +1191,7 @@ RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform & } JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1213,7 +1227,7 @@ RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index e0e46cd369..764ec2387c 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -290,6 +290,9 @@ public: virtual void joint_set_solver_priority(RID p_joint, int p_priority); virtual int joint_get_solver_priority(RID p_joint) const; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable); + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const; + virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B); virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value); diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp index b60e89b6fd..d15fb8de01 100644 --- a/modules/bullet/constraint_bullet.cpp +++ b/modules/bullet/constraint_bullet.cpp @@ -39,7 +39,8 @@ ConstraintBullet::ConstraintBullet() : space(NULL), - constraint(NULL) {} + constraint(NULL), + disabled_collisions_between_bodies(true) {} void ConstraintBullet::setup(btTypedConstraint *p_constraint) { constraint = p_constraint; @@ -53,3 +54,12 @@ void ConstraintBullet::set_space(SpaceBullet *p_space) { void ConstraintBullet::destroy_internal_constraint() { space->remove_constraint(this); } + +void ConstraintBullet::disable_collisions_between_bodies(const bool p_disabled) { + disabled_collisions_between_bodies = p_disabled; + + if (space) { + space->remove_constraint(this); + space->add_constraint(this, disabled_collisions_between_bodies); + } +} diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h index 23be5a5063..ed3a318cbc 100644 --- a/modules/bullet/constraint_bullet.h +++ b/modules/bullet/constraint_bullet.h @@ -49,6 +49,7 @@ class ConstraintBullet : public RIDBullet { protected: SpaceBullet *space; btTypedConstraint *constraint; + bool disabled_collisions_between_bodies; public: ConstraintBullet(); @@ -57,6 +58,9 @@ public: virtual void set_space(SpaceBullet *p_space); virtual void destroy_internal_constraint(); + void disable_collisions_between_bodies(const bool p_disabled); + _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } + public: virtual ~ConstraintBullet() { bulletdelete(constraint); diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index c92c3f30a2..acfb83bc10 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -28,7 +28,7 @@ def _build_gdnative_api_struct_header(api): '\textern const godot_gdnative_ext_{0}_api_struct *_gdnative_wrapper_{0}_api_struct;'.format(name)) gdnative_api_init_macro.append('\t_gdnative_wrapper_api_struct = options->api_struct;') - gdnative_api_init_macro.append('\tfor (int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { ') + gdnative_api_init_macro.append('\tfor (unsigned int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { ') gdnative_api_init_macro.append('\t\tswitch (_gdnative_wrapper_api_struct->extensions[i]->type) {') for name in api['extensions']: @@ -66,19 +66,30 @@ def _build_gdnative_api_struct_header(api): out += ['};', ''] - for name in api['extensions']: - out += [ - 'typedef struct godot_gdnative_ext_' + name + '_api_struct {', + + def generate_extension_struct(name, ext, include_version=True): + ret_val = [] + if ext['next']: + ret_val += generate_extension_struct(name, ext['next']) + + ret_val += [ + 'typedef struct godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct {', '\tunsigned int type;', '\tgodot_gdnative_api_version version;', '\tconst godot_gdnative_api_struct *next;' ] - for funcdef in api['extensions'][name]['api']: + for funcdef in ext['api']: args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']]) - out.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args)) + ret_val.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args)) + + ret_val += ['} godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct;', ''] + + return ret_val - out += ['} godot_gdnative_ext_' + name + '_api_struct;', ''] + + for name in api['extensions']: + out += generate_extension_struct(name, api['extensions'][name], False) out += [ 'typedef struct godot_gdnative_core_api_struct {', @@ -113,18 +124,35 @@ def _build_gdnative_api_struct_source(api): '' ] - for name in api['extensions']: - out += [ - 'extern const godot_gdnative_ext_' + name + '_api_struct api_extension_' + name + '_struct = {', - '\tGDNATIVE_EXT_' + api['extensions'][name]['type'] + ',', - '\t{' + str(api['extensions'][name]['version']['major']) + ', ' + str(api['extensions'][name]['version']['minor']) + '},', - '\tNULL,' + def get_extension_struct_name(name, ext, include_version=True): + return 'godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct' + + def get_extension_struct_instance_name(name, ext, include_version=True): + return 'api_extension_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_struct' + + def get_extension_struct_definition(name, ext, include_version=True): + + ret_val = [] + + if ext['next']: + ret_val += get_extension_struct_definition(name, ext['next']) + + ret_val += [ + 'extern const ' + get_extension_struct_name(name, ext, include_version) + ' ' + get_extension_struct_instance_name(name, ext, include_version) + ' = {', + '\tGDNATIVE_EXT_' + ext['type'] + ',', + '\t{' + str(ext['version']['major']) + ', ' + str(ext['version']['minor']) + '},', + '\t' + ('NULL' if not ext['next'] else ('(const godot_gdnative_api_struct *)&' + get_extension_struct_instance_name(name, ext['next']))) + ',' ] - for funcdef in api['extensions'][name]['api']: - out.append('\t%s,' % funcdef['name']) + for funcdef in ext['api']: + ret_val.append('\t%s,' % funcdef['name']) + + ret_val += ['};\n'] - out += ['};\n'] + return ret_val + + for name in api['extensions']: + out += get_extension_struct_definition(name, api['extensions'][name], False) out += ['', 'const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {'] diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index f713e4112e..6a71cd8d4d 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NativeScript" inherits="Script" category="Core" version="3.0-stable"> +<class name="NativeScript" inherits="Script" category="Core" version="3.1-dev"> <brief_description> </brief_description> <description> @@ -9,10 +9,46 @@ <demos> </demos> <methods> + <method name="get_class_documentation" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_class_documentation[/code]. + </description> + </method> + <method name="get_method_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="method" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_method_documentation[/code]. + </description> + </method> + <method name="get_property_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_property_documentation[/code]. + </description> + </method> + <method name="get_signal_documentation" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="signal_name" type="String"> + </argument> + <description> + Returns the documentation string that was previously set with [code]godot_nativescript_set_signal_documentation[/code]. + </description> + </method> <method name="new" qualifiers="vararg"> <return type="Object"> </return> <description> + Constructs a new object of the base type with a script of this type already attached. + [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. </description> </method> </methods> diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 59a9c0b090..a8919f7130 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -5,6 +5,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_color_new_rgba", @@ -3963,7 +3964,7 @@ "name": "godot_variant_new_bool", "return_type": "void", "arguments": [ - ["godot_variant *", "p_v"], + ["godot_variant *", "r_dest"], ["const godot_bool", "p_b"] ] }, @@ -5762,6 +5763,104 @@ "major": 1, "minor": 0 }, + "next": { + "type": "NATIVESCRIPT", + "version": { + "major": 1, + "minor": 1 + }, + "next": null, + "api": [ + { + "name": "godot_nativescript_set_method_argument_information", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_function_name"], + ["int", "p_num_args"], + ["const godot_method_arg *", "p_args"] + ] + }, + { + "name": "godot_nativescript_set_class_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_method_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_function_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_property_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_path"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_signal_documentation", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const char *", "p_signal_name"], + ["godot_string", "p_documentation"] + ] + }, + { + "name": "godot_nativescript_set_type_tag", + "return_type": "void", + "arguments": [ + ["void *", "p_gdnative_handle"], + ["const char *", "p_name"], + ["const void *", "p_type_tag"] + ] + }, + { + "name": "godot_nativescript_get_type_tag", + "return_type": "const void *", + "arguments": [ + ["const godot_object *", "p_object"] + ] + }, + { + "name": "godot_nativescript_register_instance_binding_data_functions", + "return_type": "int", + "arguments": [ + ["godot_instance_binding_functions", "p_binding_functions"] + ] + }, + { + "name": "godot_nativescript_unregister_instance_binding_data_functions", + "return_type": "void", + "arguments": [ + ["int", "p_idx"] + ] + }, + { + "name": "godot_nativescript_get_instance_binding_data", + "return_type": "void *", + "arguments": [ + ["int", "p_idx"], + ["godot_object *", "p_object"] + ] + } + ] + }, "api": [ { "name": "godot_nativescript_register_class", @@ -5832,6 +5931,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_pluginscript_register_language", @@ -5848,6 +5948,7 @@ "major": 1, "minor": 0 }, + "next": null, "api": [ { "name": "godot_arvr_register_interface", diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h index d2e8246bfb..6779dc4092 100644 --- a/modules/gdnative/include/gdnative/variant.h +++ b/modules/gdnative/include/gdnative/variant.h @@ -135,7 +135,7 @@ void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_ void GDAPI godot_variant_new_nil(godot_variant *r_dest); -void GDAPI godot_variant_new_bool(godot_variant *p_v, const godot_bool p_b); +void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b); void GDAPI godot_variant_new_uint(godot_variant *r_dest, const uint64_t p_i); void GDAPI godot_variant_new_int(godot_variant *r_dest, const int64_t p_i); void GDAPI godot_variant_new_real(godot_variant *r_dest, const double p_r); diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h index 11017ae78d..747328bc41 100644 --- a/modules/gdnative/include/nativescript/godot_nativescript.h +++ b/modules/gdnative/include/nativescript/godot_nativescript.h @@ -185,6 +185,52 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance); +/* + * + * + * NativeScript 1.1 + * + * + */ + +// method registering with argument names + +typedef struct { + godot_string name; + + godot_variant_type type; + godot_property_hint hint; + godot_string hint_string; +} godot_method_arg; + +void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args); + +// documentation + +void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation); +void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation); +void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation); +void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation); + +// type tag API + +void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag); +const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object); + +// instance binding API + +typedef struct { + void *(*alloc_instance_binding_data)(void *, godot_object *); + void (*free_instance_binding_data)(void *, void *); + void *data; + void (*free_func)(void *); +} godot_instance_binding_functions; + +int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions); +void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx); + +void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object); + #ifdef __cplusplus } #endif diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp index b4f7e1555e..aea595d0f0 100644 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ b/modules/gdnative/nativescript/godot_nativescript.cpp @@ -106,7 +106,7 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -125,7 +125,7 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -150,7 +150,7 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); if (!E) { - ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_EXPLAIN("Attempted to register method on non-existent class!"); ERR_FAIL(); } @@ -201,6 +201,164 @@ void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) { return NULL; } +/* + * + * + * NativeScript 1.1 + * + * + */ + +void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add argument information for a method on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); + if (!method) { + ERR_EXPLAIN("Attempted to add argument information to non-existent method!"); + ERR_FAIL(); + } + + MethodInfo *method_information = &method->get().info; + + List<PropertyInfo> args; + + for (int i = 0; i < p_num_args; i++) { + godot_method_arg arg = p_args[i]; + String name = *(String *)&arg.name; + String hint_string = *(String *)&arg.hint_string; + + Variant::Type type = (Variant::Type)arg.type; + PropertyHint hint = (PropertyHint)arg.hint; + + args.push_back(PropertyInfo(type, p_name, hint, hint_string)); + } + + method_information->arguments = args; +} + +void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a non-existent class!"); + ERR_FAIL(); + } + + E->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a method on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); + if (!method) { + ERR_EXPLAIN("Attempted to add documentatino to non-existent method!"); + ERR_FAIL(); + } + + method->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a property on a non-existent class!"); + ERR_FAIL(); + } + + OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = E->get().properties.find(p_path); + if (!property) { + ERR_EXPLAIN("Attempted to add documentation to non-existent property!"); + ERR_FAIL(); + } + + property.get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to add documentation to a signal on a non-existent class!"); + ERR_FAIL(); + } + + Map<StringName, NativeScriptDesc::Signal>::Element *signal = E->get().signals_.find(p_signal_name); + if (!signal) { + ERR_EXPLAIN("Attempted to add documentation to non-existent signal!"); + ERR_FAIL(); + } + + signal->get().documentation = *(String *)&p_documentation; +} + +void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag) { + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempted to set type tag on a non-existent class!"); + ERR_FAIL(); + } + + E->get().type_tag = p_type_tag; +} + +const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object) { + + const Object *o = (Object *)p_object; + + if (!o->get_script_instance()) { + ERR_EXPLAIN("Attempted to get type tag on an object without a script!"); + ERR_FAIL_V(NULL); + } else { + NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr()); + if (!script) { + ERR_EXPLAIN("Attempted to get type tag on an object without a nativescript attached"); + ERR_FAIL_V(NULL); + } + + if (script->get_script_desc()) + return script->get_script_desc()->type_tag; + } + + return NULL; +} + #ifdef __cplusplus } #endif + +int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions) { + return NativeScriptLanguage::get_singleton()->register_binding_functions(p_binding_functions); +} + +void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx) { + NativeScriptLanguage::get_singleton()->unregister_binding_functions(p_idx); +} + +void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) { + return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object); +} diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index aaa7d634d1..f2e9bef467 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -68,6 +68,11 @@ void NativeScript::_bind_methods() { ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library); ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library); + ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation); + ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation); + ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation); + ClassDB::bind_method(D_METHOD("get_property_documentation", "path"), &NativeScript::get_property_documentation); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); @@ -373,6 +378,86 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } +String NativeScript::get_class_documentation() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get class documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + return script_data->documentation; +} + +String NativeScript::get_method_documentation(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get method documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *method = script_data->methods.find(p_method); + + if (method) { + return method->get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get method documentation for non-existent method"); + ERR_FAIL_V(""); +} + +String NativeScript::get_signal_documentation(const StringName &p_signal_name) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get signal documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + Map<StringName, NativeScriptDesc::Signal>::Element *signal = script_data->signals_.find(p_signal_name); + + if (signal) { + return signal->get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get signal documentation for non-existent signal"); + ERR_FAIL_V(""); +} + +String NativeScript::get_property_documentation(const StringName &p_path) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + ERR_EXPLAIN("Attempt to get property documentation on invalid NativeScript"); + ERR_FAIL_V(""); + } + + while (script_data) { + + OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = script_data->properties.find(p_path); + + if (property) { + return property.get().documentation; + } + + script_data = script_data->base_data; + } + + ERR_EXPLAIN("Attempt to get property documentation for non-existent signal"); + ERR_FAIL_V(""); +} + Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { if (lib_path.empty() || class_name.empty() || library.is_null()) { @@ -610,7 +695,7 @@ Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, } void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - script->get_method_list(p_list); + script->get_script_method_list(p_list); } bool NativeScriptInstance::has_method(const StringName &p_method) const { @@ -824,6 +909,25 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) { } } + Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path); + Ref<GDNative> gdn; + + if (E) { + gdn = E->get(); + } + + if (gdn.is_valid() && gdn->get_library().is_valid()) { + Ref<GDNativeLibrary> lib = gdn->get_library(); + void *terminate_fn; + Error err = gdn->get_symbol(lib->get_symbol_prefix() + _terminate_call_name, terminate_fn, true); + + if (err == OK) { + void (*terminate)(void *) = (void (*)(void *))terminate_fn; + + terminate((void *)&lib_path); + } + } + for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) { // free property stuff first @@ -1011,6 +1115,116 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in return 0; } +int NativeScriptLanguage::register_binding_functions(godot_instance_binding_functions p_binding_functions) { + + // find index + + int idx = -1; + + for (int i = 0; i < binding_functions.size(); i++) { + if (!binding_functions[i].first) { + // free, we'll take it + idx = i; + break; + } + } + + if (idx == -1) { + idx = binding_functions.size(); + binding_functions.resize(idx + 1); + } + + // set the functions + binding_functions[idx].first = true; + binding_functions[idx].second = p_binding_functions; + + return idx; +} + +void NativeScriptLanguage::unregister_binding_functions(int p_idx) { + ERR_FAIL_INDEX(p_idx, binding_functions.size()); + + for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) { + Vector<void *> &binding_data = *E->get(); + + if (binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data) + binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]); + } + + binding_functions[p_idx].first = false; + + if (binding_functions[p_idx].second.free_func) + binding_functions[p_idx].second.free_func(binding_functions[p_idx].second.data); +} + +void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) { + ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), NULL); + + if (!binding_functions[p_idx].first) { + ERR_EXPLAIN("Tried to get binding data for a nativescript binding that does not exist"); + ERR_FAIL_V(NULL); + } + + Vector<void *> *binding_data = (Vector<void *> *)p_object->get_script_instance_binding(lang_idx); + + if (!binding_data) + return NULL; // should never happen. + + if (binding_data->size() <= p_idx) { + // okay, add new elements here. + int old_size = binding_data->size(); + + binding_data->resize(p_idx + 1); + + for (int i = old_size; i <= p_idx; i++) { + (*binding_data)[i] = NULL; + } + } + + if (!(*binding_data)[p_idx]) { + // no binding data yet, soooooo alloc new one \o/ + (*binding_data)[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, (godot_object *)p_object); + } + + return (*binding_data)[p_idx]; +} + +void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { + + Vector<void *> *binding_data = new Vector<void *>; + + binding_data->resize(binding_functions.size()); + + for (int i = 0; i < binding_functions.size(); i++) { + (*binding_data)[i] = NULL; + } + + binding_instances.insert(binding_data); + + return (void *)binding_data; +} + +void NativeScriptLanguage::free_instance_binding_data(void *p_data) { + + if (!p_data) + return; + + Vector<void *> &binding_data = *(Vector<void *> *)p_data; + + for (int i = 0; i < binding_data.size(); i++) { + if (!binding_data[i]) + continue; + + if (binding_functions[i].first && binding_functions[i].second.free_instance_binding_data) { + binding_functions[i].second.free_instance_binding_data(binding_functions[i].second.data, binding_data[i]); + } + } + + binding_instances.erase(&binding_data); + + delete &binding_data; +} + #ifndef NO_THREADS void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) { MutexLock lock(mutex); diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index ac94c84bc4..17b6ddc747 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -53,6 +53,7 @@ struct NativeScriptDesc { godot_instance_method method; MethodInfo info; int rpc_mode; + String documentation; }; struct Property { godot_property_set_func setter; @@ -60,12 +61,16 @@ struct NativeScriptDesc { PropertyInfo info; Variant default_value; int rset_mode; + String documentation; }; struct Signal { MethodInfo signal; + String documentation; }; + String documentation; + Map<StringName, Method> methods; OrderedHashMap<StringName, Property> properties; Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals @@ -75,6 +80,8 @@ struct NativeScriptDesc { godot_instance_create_func create_func; godot_instance_destroy_func destroy_func; + const void *type_tag; + bool is_tool; inline NativeScriptDesc() : @@ -82,7 +89,9 @@ struct NativeScriptDesc { properties(), signals_(), base(), - base_native_type() { + base_native_type(), + documentation(), + type_tag(NULL) { zeromem(&create_func, sizeof(godot_instance_create_func)); zeromem(&destroy_func, sizeof(godot_instance_destroy_func)); } @@ -154,6 +163,11 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const; virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + String get_class_documentation() const; + String get_method_documentation(const StringName &p_method) const; + String get_signal_documentation(const StringName &p_signal_name) const; + String get_property_documentation(const StringName &p_path) const; + Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); NativeScript(); @@ -204,6 +218,7 @@ class NativeScriptLanguage : public ScriptLanguage { private: static NativeScriptLanguage *singleton; + int lang_idx; void _unload_stuff(bool p_reload = false); @@ -222,6 +237,9 @@ private: void call_libraries_cb(const StringName &name); + Vector<Pair<bool, godot_instance_binding_functions> > binding_functions; + Set<Vector<void *> *> binding_instances; + public: // These two maps must only be touched on the main thread Map<String, Map<StringName, NativeScriptDesc> > library_classes; @@ -232,6 +250,8 @@ public: const StringName _init_call_type = "nativescript_init"; const StringName _init_call_name = "nativescript_init"; + const StringName _terminate_call_name = "nativescript_terminate"; + const StringName _noarg_call_type = "nativescript_no_arg"; const StringName _frame_call_name = "nativescript_frame"; @@ -250,6 +270,8 @@ public: void _hacky_api_anchor(); + _FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; } + #ifndef NO_THREADS virtual void thread_enter(); virtual void thread_exit(); @@ -293,6 +315,14 @@ public: virtual void profiling_stop(); virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); + + int register_binding_functions(godot_instance_binding_functions p_binding_functions); + void unregister_binding_functions(int p_idx); + + void *get_instance_binding_data(int p_idx, Object *p_object); + + virtual void *alloc_instance_binding_data(Object *p_object); + virtual void free_instance_binding_data(void *p_data); }; inline NativeScriptDesc *NativeScript::get_script_desc() const { diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index cb55a13b3e..9a0e764391 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -47,6 +47,7 @@ void register_nativescript_types() { ClassDB::register_class<NativeScript>(); + native_script_language->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(native_script_language); resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp index e3cb9bbdf8..84c4e85006 100644 --- a/modules/openssl/stream_peer_openssl.cpp +++ b/modules/openssl/stream_peer_openssl.cpp @@ -141,9 +141,6 @@ int StreamPeerOpenSSL::_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg X509_NAME_oneline(X509_get_subject_name(server_cert), cert_str, sizeof(cert_str)); - print_line("CERT STR: " + String(cert_str)); - print_line("VALID: " + itos(base_cert_valid)); - if (!base_cert_valid) return 0; @@ -382,7 +379,6 @@ Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_valida // Same as before, try to connect. int result = SSL_connect(ssl); - print_line("CONNECTION RESULT: " + itos(result)); if (result < 1) { ERR_print_errors_fp(stdout); _print_error(result); @@ -392,7 +388,6 @@ Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_valida if (peer) { bool cert_ok = SSL_get_verify_result(ssl) == X509_V_OK; - print_line("cert_ok: " + itos(cert_ok)); } else if (validate_certs) { status = STATUS_ERROR_NO_CERTIFICATE; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 6fff7ac0a4..bb914b90fc 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -399,7 +399,7 @@ void Area2D::set_monitoring(bool p_enable) { if (p_enable == monitoring) return; if (locked) { - ERR_EXPLAIN("Function blocked during in/out signal. Use call_deferred(\"set_enable_monitoring\",true/false)"); + ERR_EXPLAIN("Function blocked during in/out signal. Use call_deferred(\"set_monitoring\",true/false)"); } ERR_FAIL_COND(locked); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 7a96a54854..329382c034 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -75,8 +75,7 @@ void Joint2D::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); - if (exclude_from_collision) - Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); + Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } void Joint2D::set_node_a(const NodePath &p_node_a) { diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index fed6d76f65..2e9f1a241a 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -71,8 +71,7 @@ void Joint::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); - if (exclude_from_collision) - PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); + PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } void Joint::set_node_a(const NodePath &p_node_a) { diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 3c5d524d80..145981d498 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -185,17 +185,22 @@ void SpinBox::_line_edit_focus_exit() { _text_entered(line_edit->get_text()); } +inline void SpinBox::_adjust_width_for_icon(const Ref<Texture> icon) { + + int w = icon->get_width(); + if (w != last_w) { + line_edit->set_margin(MARGIN_RIGHT, -w); + last_w = w; + } +} + void SpinBox::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { Ref<Texture> updown = get_icon("updown"); - int w = updown->get_width(); - if (w != last_w) { - line_edit->set_margin(MARGIN_RIGHT, -w); - last_w = w; - } + _adjust_width_for_icon(updown); RID ci = get_canvas_item(); Size2i size = get_size(); @@ -207,6 +212,7 @@ void SpinBox::_notification(int p_what) { //_value_changed(0); } else if (p_what == NOTIFICATION_ENTER_TREE) { + _adjust_width_for_icon(get_icon("updown")); _value_changed(0); } } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index b8565ec082..8863f44bef 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -62,6 +62,8 @@ class SpinBox : public Range { void _line_edit_focus_exit(); + inline void _adjust_width_for_icon(const Ref<Texture> icon); + protected: void _gui_input(const Ref<InputEvent> &p_event); diff --git a/servers/physics/constraint_sw.h b/servers/physics/constraint_sw.h index a641f06f0c..41789600f6 100644 --- a/servers/physics/constraint_sw.h +++ b/servers/physics/constraint_sw.h @@ -41,6 +41,7 @@ class ConstraintSW : public RID_Data { ConstraintSW *island_next; ConstraintSW *island_list_next; int priority; + bool disabled_collisions_between_bodies; RID self; @@ -50,6 +51,7 @@ protected: _body_count = p_body_count; island_step = 0; priority = 1; + disabled_collisions_between_bodies = true; } public: @@ -71,6 +73,9 @@ public: _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; } _FORCE_INLINE_ int get_priority() const { return priority; } + _FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; } + _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } + virtual bool setup(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index ea0d372281..0f7c6deaac 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -1093,6 +1093,33 @@ int PhysicsServerSW::joint_get_solver_priority(RID p_joint) const { return joint->get_priority(); } +void PhysicsServerSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + JointSW *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); + + if (2 == joint->get_body_count()) { + BodySW *body_a = *joint->get_body_ptr(); + BodySW *body_b = *(joint->get_body_ptr() + 1); + + if (p_disable) { + body_add_collision_exception(body_a->get_self(), body_b->get_self()); + body_add_collision_exception(body_b->get_self(), body_a->get_self()); + } else { + body_remove_collision_exception(body_a->get_self(), body_b->get_self()); + body_remove_collision_exception(body_b->get_self(), body_a->get_self()); + } + } +} + +bool PhysicsServerSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + JointSW *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, true); + + return joint->is_disabled_collisions_between_bodies(); +} + PhysicsServerSW::JointType PhysicsServerSW::joint_get_type(RID p_joint) const { JointSW *joint = joint_owner.get(p_joint); diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 132ac78968..923b59d28f 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -275,6 +275,9 @@ public: virtual void joint_set_solver_priority(RID p_joint, int p_priority); virtual int joint_get_solver_priority(RID p_joint) const; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable); + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const; + /* MISC */ virtual void free(RID p_rid); diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h index a08037bb37..c1954935d3 100644 --- a/servers/physics_2d/constraint_2d_sw.h +++ b/servers/physics_2d/constraint_2d_sw.h @@ -40,6 +40,7 @@ class Constraint2DSW : public RID_Data { uint64_t island_step; Constraint2DSW *island_next; Constraint2DSW *island_list_next; + bool disabled_collisions_between_bodies; RID self; @@ -48,6 +49,7 @@ protected: _body_ptr = p_body_ptr; _body_count = p_body_count; island_step = 0; + disabled_collisions_between_bodies = true; } public: @@ -66,6 +68,9 @@ public: _FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; } _FORCE_INLINE_ int get_body_count() const { return _body_count; } + _FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; } + _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } + virtual bool setup(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 7d7bbbebac..0603287a79 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -1015,6 +1015,33 @@ real_t Physics2DServerSW::joint_get_param(RID p_joint, JointParam p_param) const return 0; } +void Physics2DServerSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + Joint2DSW *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); + + if (2 == joint->get_body_count()) { + Body2DSW *body_a = *joint->get_body_ptr(); + Body2DSW *body_b = *(joint->get_body_ptr() + 1); + + if (p_disable) { + body_add_collision_exception(body_a->get_self(), body_b->get_self()); + body_add_collision_exception(body_b->get_self(), body_a->get_self()); + } else { + body_remove_collision_exception(body_a->get_self(), body_b->get_self()); + body_remove_collision_exception(body_b->get_self(), body_a->get_self()); + } + } +} + +bool Physics2DServerSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + const Joint2DSW *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, true); + + return joint->is_disabled_collisions_between_bodies(); +} + RID Physics2DServerSW::pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b) { Body2DSW *A = body_owner.get(p_body_a); diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index 97edb85582..cf9c2957bf 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -242,6 +242,9 @@ public: virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value); virtual real_t joint_get_param(RID p_joint, JointParam p_param) const; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disabled); + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const; + virtual RID pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b = RID()); virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b); virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 276c37c577..d625bc9892 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -263,6 +263,9 @@ public: FUNC3(joint_set_param, RID, JointParam, real_t); FUNC2RC(real_t, joint_get_param, RID, JointParam); + FUNC2(joint_disable_collisions_between_bodies, RID, const bool); + FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID); + ///FUNC3RID(pin_joint,const Vector2&,RID,RID); ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID); ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index be447ed137..462244c667 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -499,6 +499,9 @@ public: virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value) = 0; virtual real_t joint_get_param(RID p_joint, JointParam p_param) const = 0; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0; + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0; + virtual RID pin_joint_create(const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) = 0; virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) = 0; virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) = 0; diff --git a/servers/physics_server.h b/servers/physics_server.h index 94fc8d479d..2ac405293e 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -491,6 +491,9 @@ public: virtual void joint_set_solver_priority(RID p_joint, int p_priority) = 0; virtual int joint_get_solver_priority(RID p_joint) const = 0; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0; + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0; + virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) = 0; enum PinJointParam { |