diff --git a/core/image.cpp b/core/image.cpp index 812a967cc03..07a3673592a 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -2988,6 +2988,7 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL); + BIND_ENUM_CONSTANT(COMPRESS_SOURCE_LAYERED); } void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, CompressSource)) { diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml index f65c89ff2c3..b8a1250d536 100644 --- a/doc/classes/AnimationNodeOneShot.xml +++ b/doc/classes/AnimationNodeOneShot.xml @@ -11,17 +11,6 @@ https://godotengine.org/asset-library/asset/678 - - - - - - - - - - - @@ -37,6 +26,8 @@ + + diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml index 92d96d45da9..8b4257138f8 100644 --- a/doc/classes/BakedLightmap.xml +++ b/doc/classes/BakedLightmap.xml @@ -45,7 +45,7 @@ When enabled, an octree containing the scene's lighting information will be computed. This octree will then be used to light dynamic objects in the scene. - Bias value to reduce the amount of light proagation in the captured octree. + Bias value to reduce the amount of light propagation in the captured octree. Bake quality of the capture data. diff --git a/doc/classes/CollisionObject.xml b/doc/classes/CollisionObject.xml index eb2b9115da5..f5cf271f530 100644 --- a/doc/classes/CollisionObject.xml +++ b/doc/classes/CollisionObject.xml @@ -182,7 +182,7 @@ If [code]true[/code], the [CollisionObject] will continue to receive input events as the mouse is dragged across its shapes. - If [code]true[/code], the [CollisionObject]'s shapes will respond to [RayCast]s. + If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [member collision_layer] bit to be set. diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index 3b603d3fcb0..61b64242d1b 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -207,7 +207,7 @@ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. - If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set. + If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [member collision_layer] bit to be set. diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index cecee855de3..33f1487e3c2 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -9,7 +9,11 @@ - Glow - Tonemap (Auto Exposure) - Adjustments - These effects will only apply when the [Viewport]'s intended usage is "3D" or "3D Without Effects". This can be configured for the root Viewport with [member ProjectSettings.rendering/quality/intended_usage/framebuffer_allocation], or for specific Viewports via the [member Viewport.usage] property. + If the target [Viewport] is set to "2D Without Sampling", all post-processing effects will be unavailable. With "3D Without Effects", the following options will be unavailable: + - Ssao + - Ss Reflections + This can be configured for the root Viewport with [member ProjectSettings.rendering/quality/intended_usage/framebuffer_allocation], or for specific Viewports via the [member Viewport.usage] property. + Note that [member ProjectSettings.rendering/quality/intended_usage/framebuffer_allocation] has a mobile platform override to use "3D Without Effects" by default. It improves the performance on mobile devices, but at the same time affects the screen display on mobile devices. https://docs.godotengine.org/en/3.4/tutorials/3d/environment_and_post_processing.html diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 4a209c4f795..adfe49feb17 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -603,5 +603,8 @@ Source texture (before compression) is a normal texture (e.g. it can be compressed into two channels). + + Source texture (before compression) is a [TextureLayered]. + diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index f51dd5fb8f1..7642f1c4b46 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -24,7 +24,7 @@ Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network. [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types. - Use [code]indent[/code] parameter to pretty print the output. + The [code]indent[/code] parameter controls if and how something is indented, the string used for this parameter will be used where there should be an indent in the output, even spaces like [code]" "[/code] will work. [code]\t[/code] and [code]\n[/code] can also be used for a tab indent, or to make a newline for each indent respectively. [b]Example output:[/b] [codeblock] ## JSON.print(my_dictionary) @@ -32,18 +32,34 @@ ## JSON.print(my_dictionary, "\t") { - "name": "my_dictionary", - "version": "1.0.0", - "entities": [ - { - "name": "entity_0", - "value": "value_0" - }, - { - "name": "entity_1", - "value": "value_1" - } - ] + "name": "my_dictionary", + "version": "1.0.0", + "entities": [ + { + "name": "entity_0", + "value": "value_0" + }, + { + "name": "entity_1", + "value": "value_1" + } + ] + } + + ## JSON.print(my_dictionary, "...") + { + ..."name": "my_dictionary", + ..."version": "1.0.0", + ..."entities": [ + ......{ + ........."name": "entity_0", + ........."value": "value_0" + ......}, + ......{ + ........."name": "entity_1", + ........."value": "value_1" + ......} + ...] } [/codeblock] diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 9d7175def0e..1cdaa938e3d 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -106,6 +106,9 @@ OS.execute("CMD.exe", ["/C", "cd %TEMP% && dir"], true, output) [/codeblock] [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [code]path[/code], [code]/c[/code] as the first argument, and the desired command as the second argument. + [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [code]path[/code], [code]-Command[/code] as the first argument, and the desired command as the second argument. + [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [code]path[/code], [code]-c[/code] as the first argument, and the desired command as the second argument. diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 08adbbef296..a8e8f5f226f 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -243,7 +243,7 @@ The label's text in BBCode format. Is not representative of manual modifications to the internal tag stack. Erases changes made by other methods when edited. - [b]Note:[/b] It is unadvised to use the [code]+=[/code] operator with [code]bbcode_text[/code] (e.g. [code]bbcode_text += "some string"[/code]) as it replaces the whole text and can cause slowdowns. Use [method append_bbcode] for adding text instead, unless you absolutely need to close a tag that was opened in an earlier method call. + [b]Note:[/b] It is unadvised to use the [code]+=[/code] operator with [code]bbcode_text[/code] (e.g. [code]bbcode_text += "some string"[/code]) as it replaces the whole text and can cause slowdowns. It will also erase all BBCode that was added to stack using [code]push_*[/code] methods. Use [method append_bbcode] for adding text instead, unless you absolutely need to close a tag that was opened in an earlier method call. The currently installed custom effects. This is an array of [RichTextEffect]s. diff --git a/doc/classes/SoftBody.xml b/doc/classes/SoftBody.xml index 5479fb6240d..91daf173b7a 100644 --- a/doc/classes/SoftBody.xml +++ b/doc/classes/SoftBody.xml @@ -5,6 +5,7 @@ A deformable physics body. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials. + [b]Note:[/b] There are many known bugs in [SoftBody]. Therefore, it's not recommended to use them for things that can affect gameplay (such as a player character made entirely out of soft bodies). https://docs.godotengine.org/en/3.4/tutorials/physics/soft_body.html diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml index 65f5de3e441..dbed62812a5 100644 --- a/doc/classes/SpriteBase3D.xml +++ b/doc/classes/SpriteBase3D.xml @@ -57,13 +57,15 @@ If [code]true[/code], texture is flipped vertically. - A color value that gets multiplied on, could be used for mood-coloring or to simulate the color of light. + A color value used to [i]multiply[/i] the texture's colors. Can be used for mood-coloring or to simulate the color of light. + [b]Note:[/b] If a [member GeometryInstance.material_override] is defined on the [SpriteBase3D], the material override must be configured to take vertex colors into account for albedo. Otherwise, the color defined in [member modulate] will be ignored. For a [SpatialMaterial], [member SpatialMaterial.vertex_color_use_as_albedo] must be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/color] must be inserted in the shader's [code]fragment()[/code] function. The texture's drawing offset. - The objects' visibility on a scale from [code]0[/code] fully invisible to [code]1[/code] fully visible. + The texture's visibility on a scale from [code]0[/code] (fully invisible) to [code]1[/code] (fully visible). [member opacity] is a multiplier for the [member modulate] color's alpha channel. + [b]Note:[/b] If a [member GeometryInstance.material_override] is defined on the [SpriteBase3D], the material override must be configured to take vertex colors into account for albedo. Otherwise, the opacity defined in [member opacity] will be ignored. For a [SpatialMaterial], [member SpatialMaterial.vertex_color_use_as_albedo] must be [code]true[/code]. For a [ShaderMaterial], [code]ALPHA *= COLOR.a;[/color] must be inserted in the shader's [code]fragment()[/code] function. The size of one pixel's width on the sprite to scale it in 3D. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 96768c1e84a..1f5f3598a06 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -750,13 +750,24 @@ - Converts a string containing a decimal number into a [code]float[/code]. + Converts a string containing a decimal number into a [code]float[/code]. The method will stop on the first non-number character except the first [code].[/code] (decimal point), and [code]e[/code] which is used for exponential. + [codeblock] + print("12.3".to_float()) # 12.3 + print("1.2.3".to_float()) # 1.2 + print("12ab3".to_float()) # 12 + print("1e3".to_float()) # 1000 + [/codeblock] - Converts a string containing an integer number into an [code]int[/code]. + Converts a string containing an integer number into an [code]int[/code]. The method will remove any non-number character and stop if it encounters a [code].[/code]. + [codeblock] + print("123".to_int()) # 123 + print("a1b2c3".to_int()) # 123 + print("1.2.3".to_int()) # 1 + [/codeblock] diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 98fb1b1d17c..218cb459deb 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -427,6 +427,7 @@ Sets the tile's modulation color. + [b]Note:[/b] Modulation is performed by setting the tile's vertex color. To access this in a shader, use [code]COLOR[/code] rather than [code]MODULATE[/code] (which instead accesses the [TileMap]'s [member CanvasItem.modulate] property). diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index b57d3ef045c..657e0f08c4d 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -38,7 +38,7 @@ - Creates an item in the tree and adds it as a child of [code]parent[/code]. + Creates an item in the tree and adds it as a child of [code]parent[/code], which can be either a valid [TreeItem] or [code]null[/code]. If [code]parent[/code] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty. The new item will be the [code]idx[/code]th child of parent, or it will be the last child if there are not enough siblings. @@ -117,7 +117,7 @@ - Returns the rectangle area for the specified item. If [code]column[/code] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. + Returns the rectangle area for the specified [TreeItem]. If [code]column[/code] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. @@ -131,7 +131,7 @@ - Returns the next selected item after the given one, or [code]null[/code] if the end is reached. + Returns the next selected [TreeItem] after the given one, or [code]null[/code] if the end is reached. If [code]from[/code] is [code]null[/code], this returns the first selected item. @@ -173,7 +173,7 @@ - Causes the [Tree] to jump to the specified item. + Causes the [Tree] to jump to the specified [TreeItem]. diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index 746bfd199d4..6d08efb1f4d 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -321,7 +321,7 @@ def main(): # type: () -> None for path in args.path: # Cut off trailing slashes so os.path.basename doesn't choke. - if path.endswith(os.sep): + if path.endswith("/") or path.endswith("\\"): path = path[:-1] if os.path.basename(path) == "modules": diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp index d64d4e1dd81..6f47d06f050 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_dummy.cpp @@ -77,7 +77,6 @@ void ResourceFormatDummyTexture::get_recognized_extensions(List *p_exten p_extensions->push_back("png"); p_extensions->push_back("pvr"); p_extensions->push_back("svg"); - p_extensions->push_back("svgz"); p_extensions->push_back("tga"); p_extensions->push_back("webp"); } @@ -99,7 +98,6 @@ String ResourceFormatDummyTexture::get_resource_type(const String &p_path) const extension == "png" || extension == "pvr" || extension == "svg" || - extension == "svgz" || extension == "tga" || extension == "webp") { return "ImageTexture"; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index c8350b7575d..3ff45d2af91 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -204,7 +204,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, in float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse / (sigma2 + 0.13)); float B = 0.45 * sigma2 / (sigma2 + 0.09); diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index a5285dee329..7ac81a5aeb9 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -186,8 +186,7 @@ void main() { } vec2 final_pos; - float grad; - grad = steps_taken / float(num_steps); + float grad = (steps_taken + 1.0) / float(num_steps); float initial_fade = curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), curve_fade_in); float fade = pow(clamp(1.0 - grad, 0.0, 1.0), distance_fade) * initial_fade; final_pos = pos; diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 82201e748a0..c7952806e36 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -140,7 +140,6 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { extension_guess["jpeg"] = tree->get_icon("ImageTexture", "EditorIcons"); extension_guess["png"] = tree->get_icon("ImageTexture", "EditorIcons"); extension_guess["svg"] = tree->get_icon("ImageTexture", "EditorIcons"); - extension_guess["svgz"] = tree->get_icon("ImageTexture", "EditorIcons"); extension_guess["tga"] = tree->get_icon("ImageTexture", "EditorIcons"); extension_guess["webp"] = tree->get_icon("ImageTexture", "EditorIcons"); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 491c4a231ea..e6cc7efad70 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1498,6 +1498,10 @@ void EditorFileSystem::update_file(const String &p_file) { _queue_update_script_classes(); } +Set EditorFileSystem::get_valid_extensions() const { + return valid_extensions; +} + Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector &p_files) { String importer_name; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 5a8e0056d1f..660a1afee31 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -262,6 +262,7 @@ public: void scan_changes(); void get_changed_sources(List *r_changed); void update_file(const String &p_file); + Set get_valid_extensions() const; EditorFileSystemDirectory *get_filesystem_path(const String &p_path); String get_file_type(const String &p_file) const; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 41ddbab4d2a..75de7df5908 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1436,12 +1436,18 @@ void FileSystemDock::_folder_removed(String p_folder) { void FileSystemDock::_rename_operation_confirm() { String new_name = rename_dialog_text->get_text().strip_edges(); + String old_name = tree->get_selected()->get_text(0); if (new_name.length() == 0) { EditorNode::get_singleton()->show_warning(TTR("No name provided.")); return; } else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) { EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters.")); return; + } else if (to_rename.is_file && old_name.get_extension() != new_name.get_extension()) { + if (!EditorFileSystem::get_singleton()->get_valid_extensions().find(new_name.get_extension())) { + EditorNode::get_singleton()->show_warning(TTR("This file extension is not recognized by the editor.\nIf you want to rename it anyway, use your operating system's file manager.\nAfter renaming to an unknown extension, the file won't be shown in the editor anymore.")); + return; + } } String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1) : to_rename.path; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 0d20821c10e..2e61a6a8864 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -103,7 +103,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert } void AnimationNodeBlendTreeEditor::_update_graph() { - if (updating) { + if (updating || blend_tree.is_null()) { return; } @@ -915,6 +915,9 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref p_node) { + if (le == nullptr) { + return; // The text_submitted signal triggered the graph update and freed the LineEdit. + } _node_renamed(le->call("get_text"), p_node); } diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 0a53c97f622..8c4c4c93b20 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -136,9 +136,11 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref p_library, continue; } - //Transform shape_transform = sb->shape_owner_get_transform(E->get()); - - //shape_transform.set_origin(shape_transform.get_origin() - phys_offset); + Transform shape_transform; + if (p_apply_xforms) { + shape_transform = mi->get_transform(); + } + shape_transform *= sb->get_transform() * sb->shape_owner_get_transform(E->get()); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { Ref collision = sb->shape_owner_get_shape(E->get(), k); @@ -147,7 +149,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref p_library, } MeshLibrary::ShapeData shape_data; shape_data.shape = collision; - shape_data.local_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get()); + shape_data.local_transform = shape_transform; collisions.push_back(shape_data); } } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index e134e8fa294..6e2698553a3 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -258,7 +258,7 @@ void ProjectSettingsEditor::_device_input_add() { int idx = edit_idx; Dictionary old_val = ProjectSettings::get_singleton()->get(name); Dictionary action = old_val.duplicate(); - Array events = action["events"]; + Array events = action["events"].duplicate(); switch (add_type) { case INPUT_MOUSE_BUTTON: { @@ -383,7 +383,7 @@ void ProjectSettingsEditor::_press_a_key_confirm() { Dictionary old_val = ProjectSettings::get_singleton()->get(name); Dictionary action = old_val.duplicate(); - Array events = action["events"]; + Array events = action["events"].duplicate(); for (int i = 0; i < events.size(); i++) { Ref aie = events[i]; @@ -654,7 +654,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, Dictionary action = old_val.duplicate(); int idx = ti->get_metadata(0); - Array events = action["events"]; + Array events = action["events"].duplicate(); ERR_FAIL_INDEX(idx, events.size()); events.remove(idx); action["events"] = events; diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index fe180c46f4b..cadc9c4fcc7 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -284,6 +284,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und vbc->add_child(lbl_preview_title); lbl_preview = memnew(Label); + lbl_preview->set_autowrap(true); vbc->add_child(lbl_preview); // ---- Dialog related diff --git a/main/main.cpp b/main/main.cpp index ddd37c3d066..0fc950bf22c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1413,7 +1413,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { GLOBAL_DEF("application/config/icon", String()); ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", - PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz")); + PROPERTY_HINT_FILE, "*.png,*.webp,*.svg")); GLOBAL_DEF("application/config/macos_native_icon", String()); ProjectSettings::get_singleton()->set_custom_property_info("application/config/macos_native_icon", PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns")); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 68e1a1d3bd5..1527c280404 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1757,7 +1757,7 @@ CSGBrush *CSGPolygon::_build_brush() { } int shape_sides = shape_polygon.size(); Vector shape_faces = Geometry::triangulate_polygon(shape_polygon); - ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon"); + ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon. Make sure the polygon doesn't have any intersecting edges."); // Get polygon enclosing Rect2. Rect2 shape_rect(shape_polygon[0], Vector2()); diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml index 92d5b756cad..e9a05590295 100644 --- a/modules/csg/doc_classes/CSGMesh.xml +++ b/modules/csg/doc_classes/CSGMesh.xml @@ -4,7 +4,7 @@ A CSG Mesh shape that uses a mesh resource. - This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more then two faces. + This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces. See also [CSGPolygon] for drawing 2D extruded polygons to be used as CSG nodes. diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml index ab791ec1c04..6e76aced8c2 100644 --- a/modules/csg/doc_classes/CSGPolygon.xml +++ b/modules/csg/doc_classes/CSGPolygon.xml @@ -4,7 +4,7 @@ Extrudes a 2D polygon shape to create a 3D mesh. - An array of 2D points is extruded to quickly and easily create a variety of 3D meshes. + An array of 2D points is extruded to quickly and easily create a variety of 3D meshes. See also [CSGMesh] for using 3D meshes as CSG nodes. @@ -48,7 +48,8 @@ When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling. - The point array that defines the 2D polygon that is extruded. + The point array that defines the 2D polygon that is extruded. This can be a convex or concave polygon with 3 or more points. The polygon must [i]not[/i] have any intersecting edges. Otherwise, triangulation will fail and no mesh will be generated. + [b]Note:[/b] If only 1 or 2 points are defined in [member polygon], no mesh will be generated. If [code]true[/code], applies smooth shading to the extrusions. diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml index 1a6cf2e498e..ea880d03619 100644 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -7,8 +7,8 @@ A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [ARVRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on. - https://docs.godotengine.org/en/3.4/tutorials/scripting/gdnative/gdnative-c-example.html - https://docs.godotengine.org/en/3.4/tutorials/scripting/gdnative/gdnative-cpp-example.html + https://docs.godotengine.org/en/3.4/tutorials/scripting/gdnative/gdnative_c_example.html + https://docs.godotengine.org/en/3.4/tutorials/scripting/gdnative/gdnative_cpp_example.html diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 5189fd294db..850d75aa8eb 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -473,7 +473,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err_text = "Left operand of 'is' was already freed."; OPCODE_BREAK; } - if (b->is_invalid_object()) { + if (b->get_type() != Variant::OBJECT || b->is_invalid_object()) { err_text = "Right operand of 'is' is not a class."; OPCODE_BREAK; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 888b1e1209f..44611dcab34 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -318,6 +318,9 @@ namespace Godot.Collections [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass); + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); @@ -484,7 +487,7 @@ namespace Godot.Collections private KeyValuePair GetKeyValuePair(int index) { - Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value); + Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass); return new KeyValuePair((TKey)key, (TValue)value); } diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index a456c6581cc..95ac0b9d0cd 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -240,6 +240,12 @@ void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObjec *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index)); } +void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) { + ManagedType type(value_type_encoding, value_type_class); + *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); + *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type); +} + void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); Variant *ret = ptr->getptr(varKey); @@ -350,6 +356,7 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index d2150ffa1d8..5da936c961e 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -132,14 +132,31 @@ void gd_mono_debug_init() { CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8(); if (da_args.length()) { + // Clear to avoid passing it to child processes OS::get_singleton()->set_environment("GODOT_MONO_DEBUGGER_AGENT", String()); + } else { + // Try with command line arguments. This is useful on platforms where it's difficult to pass + // environment variables. The command line arguments can be specified in the export options. + + String da_cmdline_arg; + List cmdline_args = OS::get_singleton()->get_cmdline_args(); + + for (List::Element *E = cmdline_args.front(); E; E = E->next()) { + const String &arg = E->get(); + + if (arg.begins_with("--mono-debugger-agent=")) { + da_cmdline_arg = arg; + break; + } + } + + if (da_cmdline_arg.length()) { + da_cmdline_arg.replace_first("--mono-debugger-agent=", "--debugger-agent="); + da_args = da_cmdline_arg.utf8(); + } } #ifdef TOOLS_ENABLED - int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685); - bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); - int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); - if (Engine::get_singleton()->is_editor_hint() || ProjectSettings::get_singleton()->get_resource_path().empty() || Main::is_project_manager()) { @@ -148,6 +165,12 @@ void gd_mono_debug_init() { } if (da_args.length() == 0) { + // Use project settings defaults for the editor player + + int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685); + bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); + int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); + da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) + ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n")) .utf8(); diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 62555e7f3ad..6dd4fa73e73 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -246,6 +246,8 @@ Ref RegEx::search(const String &p_subject, int p_offset, int p_end) if (res < 0) { pcre2_match_data_free_16(match); + pcre2_match_context_free_16(mctx); + return nullptr; } diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index cb7bc9356f1..c421a7e55e2 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -152,7 +152,6 @@ Error ImageLoaderSVG::load_image(Ref p_image, FileAccess *f, bool p_force void ImageLoaderSVG::get_recognized_extensions(List *p_extensions) const { p_extensions->push_back("svg"); - p_extensions->push_back("svgz"); } ImageLoaderSVG::ImageLoaderSVG() { diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 8d01eb10e82..9837bdbab92 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "export.h" + #include "core/io/image_loader.h" #include "core/io/json.h" #include "core/io/stream_peer_ssl.h" @@ -658,9 +660,9 @@ void EditorExportPlatformJavaScript::get_export_options(List *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/display", PROPERTY_HINT_ENUM, "Fullscreen,Standalone,Minimal Ui,Browser"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/orientation", PROPERTY_HINT_ENUM, "Any,Landscape,Portrait"), 0)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color())); } diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 2dc65816660..ab4ec59a089 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "export.h" + #include "core/os/file_access.h" #include "core/os/os.h" #include "editor/editor_export.h" diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 73a3129beb5..87217274193 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -3822,7 +3822,7 @@ Error OS_X11::move_to_trash(const String &p_path) { // Create needed directories for decided trash can location. { - DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = dir_access->make_dir_recursive(trash_path); // Issue an error if trash can is not created proprely. @@ -3831,7 +3831,6 @@ Error OS_X11::move_to_trash(const String &p_path) { ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/files"); err = dir_access->make_dir_recursive(trash_path + "/info"); ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/info"); - memdelete(dir_access); } // The trash can is successfully created, now we check that we don't exceed our file name length limit. @@ -3871,16 +3870,15 @@ Error OS_X11::move_to_trash(const String &p_path) { String trash_info = "[Trash Info]\nPath=" + p_path.http_escape() + "\nDeletionDate=" + timestamp + "\n"; { Error err; - FileAccess *file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); + FileAccessRef file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file:" + trash_path + "/info/" + file_name + ".trashinfo"); file->store_string(trash_info); file->close(); // Rename our resource before moving it to the trash can. - DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); err = dir_access->rename(p_path, p_path.get_base_dir() + "/" + file_name); ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + p_path + "\""); - memdelete(dir_access); } // Move the given resource to the trash can. diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 7bf33b18218..250c6583fbc 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1278,7 +1278,7 @@ void CPUParticles2D::_bind_methods() { ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents"), "set_emission_rect_extents", "get_emission_rect_extents"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); @@ -1314,7 +1314,7 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 293a4043c43..a8cc211bb1f 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -389,7 +389,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector GeometryInstance *gi = Object::cast_to(p_at_node); if (gi) { - all_override = mi->get_material_override(); + all_override = gi->get_material_override(); } for (int i = 0; i < bmeshes.size(); i += 2) { @@ -414,8 +414,8 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector mf.mesh = mesh; if (gi) { - mf.cast_shadows = mi->get_cast_shadows_setting() != GeometryInstance::SHADOW_CASTING_SETTING_OFF; - mf.generate_lightmap = mi->get_generate_lightmap(); + mf.cast_shadows = gi->get_cast_shadows_setting() != GeometryInstance::SHADOW_CASTING_SETTING_OFF; + mf.generate_lightmap = gi->get_generate_lightmap(); } else { mf.cast_shadows = true; mf.generate_lightmap = true; diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 31d74509162..9f7dbfe1a85 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -1410,7 +1410,7 @@ void CPUParticles::_bind_methods() { ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points, Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); @@ -1454,7 +1454,7 @@ void CPUParticles::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index c697c9128fa..a73deeb0b07 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -319,6 +319,8 @@ void AnimationNodeOneShot::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync); ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadein_time", "get_fadein_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadeout_time", "get_fadeout_time"); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index b98d30c3930..f48da22a216 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -684,8 +684,8 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { void LineEdit::_notification(int p_what) { switch (p_what) { -#ifdef TOOLS_ENABLED case NOTIFICATION_ENTER_TREE: { +#ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) { cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false)); cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65)); @@ -694,8 +694,15 @@ void LineEdit::_notification(int p_what) { EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); } } - } break; #endif + update_cached_width(); + update_placeholder_width(); + } break; + case NOTIFICATION_THEME_CHANGED: { + update_cached_width(); + update_placeholder_width(); + update(); + } break; case NOTIFICATION_RESIZED: { scroll_offset = 0; set_cursor_position(get_cursor_position()); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 131536e559b..d286fc49179 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -387,7 +387,6 @@ void TextureProgress::draw_nine_patch_stretched(const Ref &p_texture, F } void TextureProgress::_notification(int p_what) { - const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 }; switch (p_what) { case NOTIFICATION_DRAW: { if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP || mode == FILL_BILINEAR_LEFT_AND_RIGHT || mode == FILL_BILINEAR_TOP_AND_BOTTOM)) { @@ -452,7 +451,7 @@ void TextureProgress::_notification(int p_what) { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(progress_offset, s); - Rect2 source = Rect2(Point2(), s); + Rect2 source = Rect2(Point2(), progress->get_size()); draw_texture_rect_region(progress, region, source, tint_progress); } else if (val != 0) { Array pts; @@ -466,16 +465,14 @@ void TextureProgress::_notification(int p_what) { } float end = start + direction * val; - pts.append(start); - pts.append(end); float from = MIN(start, end); float to = MAX(start, end); - for (int i = 0; i < 12; i++) { - if (corners[i] > from && corners[i] < to) { - pts.append(corners[i]); - } + pts.append(from); + for (float corner = Math::floor(from * 4 + 0.5) * 0.25 + 0.125; corner < to; corner += 0.25) { + pts.append(corner); } - pts.sort(); + pts.append(to); + Vector uvs; Vector points; uvs.push_back(get_relative_center()); @@ -492,6 +489,8 @@ void TextureProgress::_notification(int p_what) { colors.push_back(tint_progress); draw_polygon(points, colors, uvs, progress); } + + // Draw a reference cross. if (Engine::get_singleton()->is_editor_hint()) { Point2 p; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index c8b251ee8be..7b586a67b44 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1928,6 +1928,7 @@ Node *Node::_duplicate(int p_flags, Map *r_duplimap) const #endif node = res->instance(ges); ERR_FAIL_COND_V(!node, nullptr); + node->set_scene_instance_load_placeholder(get_scene_instance_load_placeholder()); instanced = true; diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index f766ee667a5..fa12c5b026b 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -30,6 +30,8 @@ #include "mesh_library.h" +#include "box_shape.h" + bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name.begins_with("item/")) { @@ -254,12 +256,35 @@ int MeshLibrary::get_last_unused_item_id() const { } void MeshLibrary::_set_item_shapes(int p_item, const Array &p_shapes) { - ERR_FAIL_COND(p_shapes.size() & 1); + Array arr_shapes = p_shapes; + int size = p_shapes.size(); + if (size & 1) { + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + int prev_size = item_map[p_item].shapes.size() * 2; + + if (prev_size < size) { + // Check if last element is a shape. + Ref shape = arr_shapes[size - 1]; + if (shape.is_null()) { + Ref box_shape; + box_shape.instance(); + arr_shapes[size - 1] = box_shape; + } + + // Make sure the added element is a Transform. + arr_shapes.push_back(Transform()); + size++; + } else { + size--; + arr_shapes.resize(size); + } + } + Vector shapes; - for (int i = 0; i < p_shapes.size(); i += 2) { + for (int i = 0; i < size; i += 2) { ShapeData sd; - sd.shape = p_shapes[i + 0]; - sd.local_transform = p_shapes[i + 1]; + sd.shape = arr_shapes[i + 0]; + sd.local_transform = arr_shapes[i + 1]; if (sd.shape.is_valid()) { shapes.push_back(sd); diff --git a/servers/visual/portals/portal_gameplay_monitor.cpp b/servers/visual/portals/portal_gameplay_monitor.cpp index 75073b78fbd..7a46cc4c85b 100644 --- a/servers/visual/portals/portal_gameplay_monitor.cpp +++ b/servers/visual/portals/portal_gameplay_monitor.cpp @@ -74,6 +74,95 @@ bool PortalGameplayMonitor::_source_rooms_changed(const int *p_source_room_ids, return source_rooms_changed; } +void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) { + // First : send gameplay exit signals for any objects still in gameplay + //////////////////////////////////////////////////////////////////// + // lock output + VisualServerCallbacks *callbacks = VSG::scene->get_callbacks(); + callbacks->lock(); + + // Remove any movings + for (int n = 0; n < _active_moving_pool_ids_prev->size(); n++) { + int pool_id = (*_active_moving_pool_ids_prev)[n]; + PortalRenderer::Moving &moving = p_portal_renderer.get_pool_moving(pool_id); + moving.last_gameplay_tick_hit = 0; + + VisualServerCallbacks::Message msg; + msg.object_id = VSG::scene->_instance_get_object_ID(moving.instance); + msg.type = _exit_callback_type; + callbacks->push_message(msg); + } + + // Remove any roaming ghosts + for (int n = 0; n < _active_rghost_pool_ids_prev->size(); n++) { + int pool_id = (*_active_rghost_pool_ids_prev)[n]; + PortalRenderer::RGhost &moving = p_portal_renderer.get_pool_rghost(pool_id); + moving.last_gameplay_tick_hit = 0; + + VisualServerCallbacks::Message msg; + msg.object_id = moving.object_id; + msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY; + callbacks->push_message(msg); + } + + // Rooms + for (int n = 0; n < _active_room_ids_prev->size(); n++) { + int room_id = (*_active_room_ids_prev)[n]; + VSRoom &room = p_portal_renderer.get_room(room_id); + room.last_gameplay_tick_hit = 0; + + VisualServerCallbacks::Message msg; + msg.object_id = room._godot_instance_ID; + msg.type = _exit_callback_type; + callbacks->push_message(msg); + } + + // RoomGroups + for (int n = 0; n < _active_roomgroup_ids_prev->size(); n++) { + int roomgroup_id = (*_active_roomgroup_ids_prev)[n]; + VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); + roomgroup.last_gameplay_tick_hit = 0; + + VisualServerCallbacks::Message msg; + msg.object_id = roomgroup._godot_instance_ID; + msg.type = _exit_callback_type; + callbacks->push_message(msg); + } + + // Static Ghosts + for (int n = 0; n < _active_sghost_ids_prev->size(); n++) { + int id = (*_active_sghost_ids_prev)[n]; + VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); + ghost.last_gameplay_tick_hit = 0; + + VisualServerCallbacks::Message msg; + msg.object_id = ghost.object_id; + msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY; + callbacks->push_message(msg); + } + + // unlock + callbacks->unlock(); + + // Clear all remaining data + for (int n = 0; n < 2; n++) { + _active_moving_pool_ids[n].clear(); + _active_rghost_pool_ids[n].clear(); + _active_room_ids[n].clear(); + _active_roomgroup_ids[n].clear(); + _active_sghost_ids[n].clear(); + } + + _source_rooms_prev.clear(); + + // Lets not reset this just in case because it may be possible to have a moving outside the room system + // which is preserved between levels, and has a stored gameplay tick. And with uint32_t this should take + // a *long* time to rollover... (828 days?). And I don't think a rollover would actually cause a problem in practice. + // But can revisit this in the case of e.g. servers running continuously. + // We could alternatively go through all movings (not just active) etc and reset the last_gameplay_tick_hit to 0. + // _gameplay_tick = 1; +} + void PortalGameplayMonitor::set_params(bool p_use_secondary_pvs, bool p_use_signals) { _use_secondary_pvs = p_use_secondary_pvs; _use_signals = p_use_signals; diff --git a/servers/visual/portals/portal_gameplay_monitor.h b/servers/visual/portals/portal_gameplay_monitor.h index d9e2811b67d..5f2833fdc9f 100644 --- a/servers/visual/portals/portal_gameplay_monitor.h +++ b/servers/visual/portals/portal_gameplay_monitor.h @@ -43,6 +43,8 @@ class PortalGameplayMonitor { public: PortalGameplayMonitor(); + void unload(PortalRenderer &p_portal_renderer); + // entering and exiting gameplay notifications (requires PVS) void update_gameplay(PortalRenderer &p_portal_renderer, const int *p_source_room_ids, int p_num_source_rooms); void set_params(bool p_use_secondary_pvs, bool p_use_signals); diff --git a/servers/visual/portals/portal_renderer.cpp b/servers/visual/portals/portal_renderer.cpp index 59c4989a2c8..06f3015cf70 100644 --- a/servers/visual/portals/portal_renderer.cpp +++ b/servers/visual/portals/portal_renderer.cpp @@ -996,6 +996,7 @@ void PortalRenderer::sprawl_roaming(uint32_t p_mover_pool_id, MovingBase &r_movi void PortalRenderer::_ensure_unloaded(String p_reason) { if (_loaded) { _loaded = false; + _gameplay_monitor.unload(*this); String str; if (p_reason != String()) { @@ -1014,6 +1015,17 @@ void PortalRenderer::_ensure_unloaded(String p_reason) { void PortalRenderer::rooms_and_portals_clear() { _loaded = false; + + // N.B. We want to make sure all the tick counters on movings rooms etc to zero, + // so that on loading the next level gameplay entered signals etc will be + // correctly sent and everything is fresh. + // This is mostly done by the gameplay_monitor, but rooms_and_portals_clear() + // will also clear tick counters where possible + // (there is no TrackedList for the RoomGroup pool for example). + // This could be made neater by moving everything to TrackedPooledLists, but this + // may be overkill. + _gameplay_monitor.unload(*this); + _statics.clear(); _static_ghosts.clear(); diff --git a/servers/visual/portals/portal_renderer.h b/servers/visual/portals/portal_renderer.h index 81d913ed1eb..e5df2952f89 100644 --- a/servers/visual/portals/portal_renderer.h +++ b/servers/visual/portals/portal_renderer.h @@ -87,6 +87,9 @@ public: void destroy() { _rooms.clear(); room_id = -1; + + last_tick_hit = 0; + last_gameplay_tick_hit = 0; } // the expanded aabb allows objects to move on most frames diff --git a/servers/visual/portals/portal_types.h b/servers/visual/portals/portal_types.h index 3332992fde0..14b5b0a9060 100644 --- a/servers/visual/portals/portal_types.h +++ b/servers/visual/portals/portal_types.h @@ -257,6 +257,7 @@ struct VSRoom { _secondary_pvs_size = 0; _priority = 0; _contains_internal_rooms = false; + last_gameplay_tick_hit = 0; } void cleanup_after_conversion() { diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 7e360f66753..15a8e815da6 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -1141,7 +1141,7 @@ void VisualServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p ERR_FAIL_COND(!occluder); if (occluder->polygon.is_valid()) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon); if (occluder_poly) { occluder_poly->owners.erase(occluder); }