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 {  |