summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/string_buffer.cpp103
-rw-r--r--core/string_buffer.h82
-rw-r--r--core/variant_parser.cpp6
-rw-r--r--doc/classes/@GDScript.xml1
-rw-r--r--doc/classes/JSON.xml2
-rw-r--r--doc/classes/JSONParseResult.xml11
-rw-r--r--editor/animation_editor.cpp2
-rw-r--r--editor/editor_node.cpp53
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp10
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_editor_plugin.cpp121
-rw-r--r--editor/plugins/script_editor_plugin.h5
-rw-r--r--editor/plugins/script_text_editor.cpp26
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/project_settings_editor.h2
-rw-r--r--editor/scene_tree_dock.cpp3
-rw-r--r--editor/spatial_editor_gizmos.cpp14
-rw-r--r--modules/bullet/bullet_physics_server.cpp30
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/constraint_bullet.cpp12
-rw-r--r--modules/bullet/constraint_bullet.h4
-rw-r--r--modules/gdnative/SCsub60
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml38
-rw-r--r--modules/gdnative/gdnative_api.json103
-rw-r--r--modules/gdnative/include/gdnative/variant.h2
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h46
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp164
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp216
-rw-r--r--modules/gdnative/nativescript/nativescript.h32
-rw-r--r--modules/gdnative/nativescript/register_types.cpp1
-rw-r--r--modules/openssl/stream_peer_openssl.cpp5
-rw-r--r--scene/2d/area_2d.cpp2
-rw-r--r--scene/2d/joints_2d.cpp3
-rw-r--r--scene/3d/physics_joint.cpp3
-rw-r--r--scene/gui/spin_box.cpp16
-rw-r--r--scene/gui/spin_box.h2
-rw-r--r--servers/physics/constraint_sw.h5
-rw-r--r--servers/physics/physics_server_sw.cpp27
-rw-r--r--servers/physics/physics_server_sw.h3
-rw-r--r--servers/physics_2d/constraint_2d_sw.h5
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp27
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h3
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h3
-rw-r--r--servers/physics_2d_server.h3
-rw-r--r--servers/physics_server.h3
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 {