diff options
36 files changed, 233 insertions, 168 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8f8bd676..88c9e1a8a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -384,6 +384,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Ogg samples now have an icon in the editor, like WAV samples. - Camera2D drag margins are now disabled by default. - If porting a project from Godot 3.1 where drag margins were used, these must be enabled manually again. +- The Camera2D Offset property now ignores the Limit property. + - To get the old behavior back, move the camera itself instead of changing the offset. - `Camera.project_position()` now requires a second `depth` argument to determine the distance of the point from the camera. - To get the old behavior back, pass the Camera's `near` property value as the second argument. - `Skeleton.set_bone_global_pose()` was replaced by `Skeleton.set_bone_global_pose_override()`. @@ -14,7 +14,6 @@ generous deed immortalized in the next stable release of Godot Engine. Gamblify <https://www.gamblify.com> Heroic Labs <https://heroiclabs.com> - Interblock <http://interblockgaming.com> ## Gold sponsors diff --git a/core/object.h b/core/object.h index f9a12da8f6..12ef600dfc 100644 --- a/core/object.h +++ b/core/object.h @@ -658,7 +658,7 @@ public: Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper void notification(int p_notification, bool p_reversed = false); - String to_string(); + virtual String to_string(); //used mainly by script, get and set all INCLUDING string virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 95b488230d..ec4eea05bf 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -245,22 +245,22 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type); \ } -#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ - CASE_TYPE(m_prefix, m_op_name, m_name) { \ - if (p_b.type == INT) \ - _RETURN(p_a._data.m_type m_op p_b._data._int); \ - if (p_b.type == FLOAT) \ - _RETURN(p_a._data.m_type m_op p_b._data._float); \ - if (p_b.type == VECTOR2) \ - _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ - if (p_b.type == VECTOR3) \ - _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ - if (p_b.type == VECTOR2I) \ - _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ - if (p_b.type == VECTOR3I) \ - _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ - \ - _RETURN_FAIL \ +#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == INT) \ + _RETURN(p_a._data.m_type m_op p_b._data._int); \ + if (p_b.type == FLOAT) \ + _RETURN(p_a._data.m_type m_op p_b._data._float); \ + if (p_b.type == VECTOR2) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ + if (p_b.type == VECTOR3) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ + if (p_b.type == VECTOR2I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2i *>(p_b._data._mem)); \ + if (p_b.type == VECTOR3I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3i *>(p_b._data._mem)); \ + \ + _RETURN_FAIL \ } #define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ diff --git a/doc/classes/AudioEffectDistortion.xml b/doc/classes/AudioEffectDistortion.xml index 3cfeaadb23..24a145b0f3 100644 --- a/doc/classes/AudioEffectDistortion.xml +++ b/doc/classes/AudioEffectDistortion.xml @@ -2,13 +2,14 @@ <class name="AudioEffectDistortion" inherits="AudioEffect" version="4.0"> <brief_description> Adds a distortion audio effect to an Audio bus. - Modify the sound to make it dirty. + Modify the sound to make it distorted. </brief_description> <description> - Modify the sound and make it dirty. Different types are available: clip, tan, lo-fi (bit crushing), overdrive, or waveshape. + Different types are available: clip, tan, lo-fi (bit crushing), overdrive, or waveshape. By distorting the waveform the frequency content change, which will often make the sound "crunchy" or "abrasive". For games, it can simulate sound coming from some saturated device or speaker very efficiently. </description> <tutorials> + <link title="Audio buses">https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html</link> </tutorials> <methods> </methods> diff --git a/doc/classes/AudioEffectFilter.xml b/doc/classes/AudioEffectFilter.xml index f548fb49cc..293848d204 100644 --- a/doc/classes/AudioEffectFilter.xml +++ b/doc/classes/AudioEffectFilter.xml @@ -7,6 +7,7 @@ Allows frequencies other than the [member cutoff_hz] to pass. </description> <tutorials> + <link title="Audio buses">https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html</link> </tutorials> <methods> </methods> @@ -20,7 +21,7 @@ Gain amount of the frequencies after the filter. </member> <member name="resonance" type="float" setter="set_resonance" getter="get_resonance" default="0.5"> - Amount of boost in the overtones near the cutoff frequency. + Amount of boost in the frequency range near the cutoff frequency. </member> </members> <constants> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 367099e455..1efa72a2b2 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -44,7 +44,7 @@ <return type="AABB"> </return> <description> - Returns the smallest [AABB] enclosing this mesh. Not affected by [code]custom_aabb[/code]. + Returns the smallest [AABB] enclosing this mesh in local space. Not affected by [code]custom_aabb[/code]. See also [method VisualInstance3D.get_transformed_aabb]. [b]Note:[/b] This is only implemented for [ArrayMesh] and [PrimitiveMesh]. </description> </method> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 8a6c560cdd..e1b3ffa2e4 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -18,7 +18,7 @@ <return type="AABB"> </return> <description> - Returns the visibility axis-aligned bounding box. + Returns the visibility axis-aligned bounding box in local space. See also [method VisualInstance3D.get_transformed_aabb]. </description> </method> <method name="get_instance_color" qualifiers="const"> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index b342fc0813..1548800901 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -525,7 +525,7 @@ ┠╴Menu ┃ ┠╴Label ┃ ┖╴Camera2D - ┖-SplashScreen + ┖╴SplashScreen ┖╴Camera2D [/codeblock] </description> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 2395ccd211..50d91c7943 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -395,7 +395,7 @@ <argument index="0" name="name" type="String"> </argument> <description> - Removes a given entry from the object's metadata. + Removes a given entry from the object's metadata. See also [method set_meta]. </description> </method> <method name="set"> @@ -464,7 +464,8 @@ <argument index="1" name="value" type="Variant"> </argument> <description> - Adds or changes a given entry in the object's metadata. Metadata are serialized, and can take any [Variant] value. + Adds, changes or removes a given entry in the object's metadata. Metadata are serialized and can take any [Variant] value. + To remove a given entry from the object's metadata, use [method remove_meta]. Metadata is also removed if its value is set to [code]null[/code]. This means you can also use [code]set_meta("name", null)[/code] to remove metadata for [code]"name"[/code]. </description> </method> <method name="set_script"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 38d65f6338..ed8eddda07 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -873,7 +873,7 @@ Size of the hash table used for the broad-phase 2D hash grid algorithm. </member> <member name="physics/2d/cell_size" type="int" setter="" getter="" default="128"> - Cell size used for the broad-phase 2D hash grid algorithm. + Cell size used for the broad-phase 2D hash grid algorithm (in pixels). </member> <member name="physics/2d/default_angular_damp" type="float" setter="" getter="" default="1.0"> The default angular damp in 2D. @@ -1199,7 +1199,7 @@ <member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64"> </member> <member name="world/2d/cell_size" type="int" setter="" getter="" default="100"> - Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses. + Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels). </member> </members> <constants> diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml index 6451b3f330..01d569d9c8 100644 --- a/doc/classes/VisualInstance3D.xml +++ b/doc/classes/VisualInstance3D.xml @@ -13,7 +13,7 @@ <return type="AABB"> </return> <description> - Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D]. + Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D]. See also [method get_transformed_aabb]. </description> </method> <method name="get_base" qualifiers="const"> @@ -44,7 +44,7 @@ </return> <description> Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance3D]. - Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform]. + Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform]. See also [method get_aabb]. </description> </method> <method name="set_base"> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index b594f652b3..ed147f31cd 100755 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -1041,7 +1041,7 @@ def make_footer(): # type: () -> str return ( ".. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`\n" ".. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`\n" - ".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`" + ".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`\n" ) # fmt: on diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 20d29d47f4..d1661fd7b3 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -754,8 +754,9 @@ void ConnectionsDock::_open_connection_dialog(ConnectDialog::ConnectionData cToE Node *dst = static_cast<Node *>(cToEdit.target); if (src && dst) { + const String &signalname = cToEdit.signal; connect_dialog->set_title(TTR("Edit Connection:") + cToEdit.signal); - connect_dialog->popup_centered(); + connect_dialog->popup_dialog(signalname); connect_dialog->init(cToEdit, true); } } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4835b4beab..3a52657862 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6198,7 +6198,9 @@ EditorNode::EditorNode() { #else p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN); #endif -#ifdef WINDOWS_ENABLED +#if defined(WINDOWS_ENABLED) && defined(WINDOWS_SUBSYSTEM_CONSOLE) + // The console can only be toggled if the application was built for the console subsystem, + // not the GUI subsystem. p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE); #endif p->add_separator(); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 1b65987af0..5b241deab0 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -138,6 +138,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shape); + cshape->set_transform(node->get_transform()); Node *owner = node->get_owner(); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 62eb06874c..e34f0855b2 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -142,42 +142,8 @@ void VisualShaderGraphPlugin::update_property_editor(VisualShader::Type p_type, if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { return; } - Control *custom_editor = links[p_node_id].custom_editor; - if (custom_editor != nullptr) { - links[p_node_id].graph_node->remove_child(custom_editor); - memdelete(custom_editor); - custom_editor = nullptr; - } - - links[p_node_id].visual_node->set_meta("id", p_node_id); - links[p_node_id].visual_node->set_meta("shader_type", (int)p_type); - - for (int i = 0; i < VisualShaderEditor::get_singleton()->plugins.size(); i++) { - custom_editor = VisualShaderEditor::get_singleton()->plugins.write[i]->create_editor(visual_shader, links[p_node_id].visual_node); - if (custom_editor) { - break; - } - } - links[p_node_id].visual_node->remove_meta("id"); - links[p_node_id].visual_node->remove_meta("shader_type"); - links[p_node_id].custom_editor = custom_editor; - if (custom_editor) { - links[p_node_id].graph_node->add_child(custom_editor); - links[p_node_id].graph_node->move_child(custom_editor, links[p_node_id].editor_pos); - - Ref<VisualShaderNode> vsnode = Ref<VisualShaderNode>(links[p_node_id].visual_node); - Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode; - Ref<VisualShaderNodeIntUniform> int_uniform = vsnode; - Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode; - Ref<VisualShaderNodeColorUniform> color_uniform = vsnode; - Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode; - Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode; - - if (float_uniform.is_valid() || int_uniform.is_valid() || vec3_uniform.is_valid() || color_uniform.is_valid() || bool_uniform.is_valid() || transform_uniform.is_valid()) { - custom_editor->call_deferred("_show_prop_names", true); - } - } - links[p_node_id].graph_node->set_size(Vector2(-1, -1)); + remove_node(p_type, p_node_id); + add_node(p_type, p_node_id); } void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value) { @@ -247,21 +213,13 @@ void VisualShaderGraphPlugin::make_dirty(bool p_enabled) { } void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) { - links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, -1 }); + links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr }); } void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) { links[p_node_id].output_ports.insert(p_port, { p_button }); } -void VisualShaderGraphPlugin::register_custom_editor(int p_node_id, Control *p_custom_editor) { - links[p_node_id].custom_editor = p_custom_editor; -} - -void VisualShaderGraphPlugin::register_editor_pos(int p_node_id, int p_pos) { - links[p_node_id].editor_pos = p_pos; -} - void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (p_type != visual_shader->get_shader_type()) { return; @@ -379,10 +337,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (custom_editor && !float_uniform.is_valid() && !int_uniform.is_valid() && !vec3_uniform.is_valid() && !bool_uniform.is_valid() && !transform_uniform.is_valid() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { //will be embedded in first port } else if (custom_editor) { - register_editor_pos(p_id, port_offset); port_offset++; node->add_child(custom_editor); - register_custom_editor(p_id, custom_editor); if (color_uniform.is_valid()) { custom_editor->call_deferred("_show_prop_names", true); } @@ -454,12 +410,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { default_value = vsnode->get_input_port_default_value(i); } + Button *button = memnew(Button); + hb->add_child(button); + register_default_input_button(p_id, i, button); + button->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, i)); if (default_value.get_type() != Variant::NIL) { // only a label - Button *button = memnew(Button); - hb->add_child(button); - button->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, i)); - register_default_input_button(p_id, i, button); set_input_port_default_value(p_type, p_id, i, default_value); + } else { + button->hide(); } if (i == 0 && custom_editor) { @@ -654,12 +612,19 @@ void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id) { void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { if (visual_shader->get_shader_type() == p_type) { VisualShaderEditor::get_singleton()->graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) { + links[p_to_node].input_ports[p_to_port].default_input_button->hide(); + } } } void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { if (visual_shader->get_shader_type() == p_type) { VisualShaderEditor::get_singleton()->graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr && links[p_to_node].visual_node->get_input_port_default_value(p_to_port).get_type() != Variant::NIL) { + links[p_to_node].input_ports[p_to_port].default_input_button->show(); + set_input_port_default_value(p_type, p_to_node, p_to_port, links[p_to_node].visual_node->get_input_port_default_value(p_to_port)); + } } } diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index e5e4add6a2..056d4c6a11 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -71,8 +71,6 @@ private: Map<int, InputPort> input_ports; Map<int, Port> output_ports; VBoxContainer *preview_box; - Control *custom_editor; - int editor_pos; }; Ref<VisualShader> visual_shader; @@ -88,8 +86,6 @@ public: void set_connections(List<VisualShader::Connection> &p_connections); void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node); void register_output_port(int p_id, int p_port, TextureButton *p_button); - void register_custom_editor(int p_node_id, Control *p_custom_editor); - void register_editor_pos(int p_node_id, int p_pos); void clear_links(); void set_shader_type(VisualShader::Type p_type); bool is_preview_visible(int p_id) const; diff --git a/main/splash_editor.png b/main/splash_editor.png Binary files differindex 29931a71db..855646b346 100644 --- a/main/splash_editor.png +++ b/main/splash_editor.png diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 32c3240a35..f517eecf64 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -849,8 +849,8 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { } else { if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { // The position was found, just shift all elements - for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam[j + 1] = areasWhereIam[j]; + for (int j = areaWhereIamCount; j > i; j--) { + areasWhereIam[j] = areasWhereIam[j - 1]; } areasWhereIam[i] = p_area; break; diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index e528fc6623..918581bc9b 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -369,24 +369,19 @@ <description> Returns the floating-point modulus of [code]a/b[/code] that wraps equally in positive and negative. [codeblock] - var i = -6 - while i < 5: - prints(i, fposmod(i, 3)) - i += 1 + for i in 7: + var x = 0.5 * i - 1.5 + print("%4.1f %4.1f %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)]) [/codeblock] Produces: [codeblock] - -6 0 - -5 1 - -4 2 - -3 0 - -2 1 - -1 2 - 0 0 - 1 1 - 2 2 - 3 0 - 4 1 + -1.5 -0.0 0.0 + -1.0 -1.0 0.5 + -0.5 -0.5 1.0 + 0.0 0.0 0.0 + 0.5 0.5 0.5 + 1.0 1.0 1.0 + 1.5 0.0 0.0 [/codeblock] </description> </method> @@ -771,24 +766,18 @@ <description> Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative. [codeblock] - var i = -6 - while i < 5: - prints(i, posmod(i, 3)) - i += 1 + for i in range(-3, 4): + print("%2.0f %2.0f %2.0f" % [i, i % 3, posmod(i, 3)]) [/codeblock] Produces: [codeblock] - -6 0 - -5 1 - -4 2 - -3 0 - -2 1 - -1 2 - 0 0 - 1 1 - 2 2 - 3 0 - 4 1 + -3 0 0 + -2 -2 1 + -1 -1 2 + 0 0 0 + 1 1 1 + 2 2 2 + 3 0 0 [/codeblock] </description> </method> @@ -991,27 +980,15 @@ <description> Returns an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial, final-1, increment). [codeblock] - for i in range(4): - print(i) - for i in range(2, 5): - print(i) - for i in range(0, 6, 2): - print(i) + print(range(4)) + print(range(2, 5)) + print(range(0, 6, 2)) [/codeblock] Output: [codeblock] - 0 - 1 - 2 - 3 - - 2 - 3 - 4 - - 0 - 2 - 4 + [0, 1, 2, 3] + [2, 3, 4] + [0, 2, 4] [/codeblock] </description> </method> diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index 501bfff075..12a982df6e 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -43,8 +43,8 @@ #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" #define PEM_END_CRT "-----END CERTIFICATE-----\n" -#include "mbedtls/pem.h" #include <mbedtls/debug.h> +#include <mbedtls/pem.h> CryptoKey *CryptoKeyMbedTLS::create() { return memnew(CryptoKeyMbedTLS); @@ -294,20 +294,15 @@ Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoK unsigned char buf[4096]; memset(buf, 0, 4096); - Ref<X509CertificateMbedTLS> out; - out.instance(); - mbedtls_x509write_crt_pem(&crt, buf, 4096, mbedtls_ctr_drbg_random, &ctr_drbg); - - int err = mbedtls_x509_crt_parse(&(out->cert), buf, 4096); - if (err != 0) { - mbedtls_mpi_free(&serial); - mbedtls_x509write_crt_free(&crt); - ERR_PRINT("Generated invalid certificate: " + itos(err)); - return nullptr; - } - + int ret = mbedtls_x509write_crt_pem(&crt, buf, 4096, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_mpi_free(&serial); mbedtls_x509write_crt_free(&crt); + ERR_FAIL_COND_V_MSG(ret != 0, nullptr, "Failed to generate certificate: " + itos(ret)); + buf[4095] = '\0'; // Make sure strlen can't fail. + + Ref<X509CertificateMbedTLS> out; + out.instance(); + out->load_from_memory(buf, strlen((char *)buf) + 1); // Use strlen to find correct output size. return out; } diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs index 05e06babd4..b217ae4bf7 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; namespace GodotTools.Core { @@ -35,7 +36,17 @@ namespace GodotTools.Core path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim(); - return rooted ? Path.DirectorySeparatorChar + path : path; + if (!rooted) + return path; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string maybeDrive = parts[0]; + if (maybeDrive.Length == 2 && maybeDrive[1] == ':') + return path; // Already has drive letter + } + + return Path.DirectorySeparatorChar + path; } private static readonly string DriveRoot = Path.GetPathRoot(Environment.CurrentDirectory); @@ -49,7 +60,7 @@ namespace GodotTools.Core public static string ToSafeDirName(this string dirName, bool allowDirSeparator = false) { - var invalidChars = new List<string> { ":", "*", "?", "\"", "<", ">", "|" }; + var invalidChars = new List<string> {":", "*", "?", "\"", "<", ">", "|"}; if (allowDirSeparator) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index a963810d63..f77d3052f4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -44,6 +44,15 @@ namespace Godot.Collections Add(element); } + public Array(params object[] array) : this() + { + if (array == null) + { + throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); + } + safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array)); + } + internal Array(ArraySafeHandle handle) { safeHandle = handle; @@ -72,6 +81,11 @@ namespace Godot.Collections return godot_icall_Array_Resize(GetPtr(), newSize); } + public static Array operator +(Array left, Array right) + { + return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr())); + } + // IDisposable public void Dispose() @@ -155,6 +169,9 @@ namespace Godot.Collections internal extern static IntPtr godot_icall_Array_Ctor(); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Array_Dtor(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] @@ -176,6 +193,9 @@ namespace Godot.Collections internal extern static void godot_icall_Array_Clear(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] @@ -231,6 +251,15 @@ namespace Godot.Collections objectArray = new Array(collection); } + public Array(params T[] array) : this() + { + if (array == null) + { + throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); + } + objectArray = new Array(array); + } + public Array(Array array) { objectArray = array; @@ -266,6 +295,11 @@ namespace Godot.Collections return objectArray.Resize(newSize); } + public static Array<T> operator +(Array<T> left, Array<T> right) + { + return new Array<T>(left.objectArray + right.objectArray); + } + // IList<T> public T this[int index] diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 766b00d612..3313e8cb77 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -104,10 +104,31 @@ void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) { } } +Array *godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array) { + Array *godot_array = memnew(Array); + unsigned int count = mono_array_length(mono_array); + godot_array->resize(count); + for (unsigned int i = 0; i < count; i++) { + MonoObject *item = mono_array_get(mono_array, MonoObject *, i); + godot_icall_Array_SetAt(godot_array, i, item); + } + return godot_array; +} + Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) { return memnew(Array(ptr->duplicate(deep))); } +Array *godot_icall_Array_Concatenate(Array *left, Array *right) { + int count = left->size() + right->size(); + Array *new_array = memnew(Array(left->duplicate(false))); + new_array->resize(count); + for (unsigned int i = 0; i < (unsigned int)right->size(); i++) { + new_array->operator[](i + left->size()) = right->operator[](i); + } + return new_array; +} + int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) { return ptr->find(GDMonoMarshal::mono_object_to_variant(item)); } @@ -284,6 +305,7 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) { void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", (void *)godot_icall_Array_Ctor_MonoArray); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic); @@ -291,6 +313,7 @@ void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", (void *)godot_icall_Array_Concatenate); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", (void *)godot_icall_Array_Duplicate); diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index c5a988b8c3..b8ee0204c4 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -64,25 +64,32 @@ static int get_log_level_id(const char *p_log_level) { return -1; } +static String make_text(const char *log_domain, const char *log_level, const char *message) { + String text(message); + text += " (in domain "; + text += log_domain; + if (log_level) { + text += ", "; + text += log_level; + } + text += ")"; + return text; +} + void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { FileAccess *f = GDMonoLog::get_singleton()->log_file; if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { - String text(message); - text += " (in domain "; - text += log_domain; - if (log_level) { - text += ", "; - text += log_level; - } - text += ")\n"; + String text = make_text(log_domain, log_level, message); + text += "\n"; f->seek_end(); f->store_string(text); } if (fatal) { - ERR_PRINT("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); + String text = make_text(log_domain, log_level, message); + ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); // Make sure to flush before aborting f->flush(); f->close(); diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index 04b743f2c8..a7ca26c16c 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -65,12 +65,14 @@ def configure(env): env.Append(CCFLAGS=["/MD"]) env.Append(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) elif env["target"] == "debug": env.Append(CCFLAGS=["/Zi"]) env.Append(CCFLAGS=["/MDd"]) env.Append(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) env.Append(LINKFLAGS=["/DEBUG"]) ## Compiler configuration diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 4e1da22bb0..c380142c72 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -210,6 +210,7 @@ def configure_msvc(env, manual_msvc_config): env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) else: env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) ## Compile/link flags @@ -347,6 +348,7 @@ def configure_mingw(env): env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) else: env.Append(LINKFLAGS=["-Wl,--subsystem,console"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) ## Compiler configuration diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c7a809f6d8..c2951559a4 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -412,6 +412,9 @@ void TileMap::update_dirty_quadrants() { vs->canvas_item_set_light_mask(canvas_item, get_light_mask()); vs->canvas_item_set_z_index(canvas_item, z_index); + vs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(CanvasItem::get_texture_filter())); + vs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(CanvasItem::get_texture_repeat())); + q.canvas_items.push_back(canvas_item); if (debug_shapes) { @@ -1687,6 +1690,28 @@ bool TileMap::get_clip_uv() const { return clip_uv; } +void TileMap::set_texture_filter(TextureFilter p_texture_filter) { + CanvasItem::set_texture_filter(p_texture_filter); + for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) { + Quadrant &q = F->get(); + for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(E->get(), RS::CanvasItemTextureFilter(p_texture_filter)); + _make_quadrant_dirty(F); + } + } +} + +void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { + CanvasItem::set_texture_repeat(p_texture_repeat); + for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) { + Quadrant &q = F->get(); + for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(E->get(), RS::CanvasItemTextureRepeat(p_texture_repeat)); + _make_quadrant_dirty(F); + } + } +} + String TileMap::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 7a2a3e412c..b9dd8f5405 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -342,6 +342,10 @@ public: String get_configuration_warning() const override; + virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; + + virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override; + void fix_invalid_tiles(); void clear(); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 211082d610..2e77d20d4e 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -345,7 +345,7 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const { String tooltip = Control::get_tooltip(p_pos); if (shortcut_in_tooltip && shortcut.is_valid() && shortcut->is_valid()) { String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")"; - if (shortcut->get_name().nocasecmp_to(tooltip) != 0) { + if (tooltip != String() && shortcut->get_name().nocasecmp_to(tooltip) != 0) { text += "\n" + tooltip; } tooltip = text; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 5cd45ea408..796408a38d 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -1369,6 +1369,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) { } texture_filter = p_texture_filter; _update_texture_filter_changed(true); + _change_notify(); } CanvasItem::TextureFilter CanvasItem::get_texture_filter() const { @@ -1421,6 +1422,7 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) { } texture_repeat = p_texture_repeat; _update_texture_repeat_changed(true); + _change_notify(); } CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const { diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index d9ffe770ff..3f32df87a7 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -405,10 +405,10 @@ public: void force_update_transform(); - void set_texture_filter(TextureFilter p_texture_filter); + virtual void set_texture_filter(TextureFilter p_texture_filter); TextureFilter get_texture_filter() const; - void set_texture_repeat(TextureRepeat p_texture_repeat); + virtual void set_texture_repeat(TextureRepeat p_texture_repeat); TextureRepeat get_texture_repeat() const; // Used by control nodes to retrieve the parent's anchorable area diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d962171555..b29b40ea5f 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1509,7 +1509,7 @@ void Viewport::_gui_show_tooltip() { } Control *which = nullptr; - String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which); + String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.last_mouse_pos), &which); tooltip = tooltip.strip_edges(); if (tooltip.length() == 0) { return; // bye diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 9e3335b05b..a13e7d786b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3208,9 +3208,9 @@ Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); Vector<float> ret; - ret.resize(multimesh->instances); + ret.resize(multimesh->instances * multimesh->stride_cache); { - float *w = multimesh->data_cache.ptrw(); + float *w = ret.ptrw(); const uint8_t *r = buffer.ptr(); copymem(w, r, buffer.size()); } diff --git a/tests/test_expression.h b/tests/test_expression.h index 85d37d1460..8c026a35f5 100644 --- a/tests/test_expression.h +++ b/tests/test_expression.h @@ -148,6 +148,20 @@ TEST_CASE("[Expression] Scientific notation") { "The expression should return the expected result."); } +TEST_CASE("[Expression] Underscored numeric literals") { + Expression expression; + + CHECK_MESSAGE( + expression.parse("1_000_000") == OK, + "The expression should parse successfully."); + CHECK_MESSAGE( + expression.parse("1_000.000") == OK, + "The expression should parse successfully."); + CHECK_MESSAGE( + expression.parse("0xff_99_00") == OK, + "The expression should parse successfully."); +} + TEST_CASE("[Expression] Built-in functions") { Expression expression; |