summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/csg/csg_shape.cpp18
-rw-r--r--modules/csg/editor/csg_gizmos.cpp8
-rw-r--r--modules/freetype/SCsub3
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h8
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd11
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd7
-rw-r--r--modules/gdscript/gdscript.cpp34
-rw-r--r--modules/gdscript/gdscript.h13
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp43
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_cache.cpp6
-rw-r--r--modules/gdscript/gdscript_cache.h4
-rw-r--r--modules/gdscript/gdscript_compiler.cpp152
-rw-r--r--modules/gdscript/gdscript_compiler.h6
-rw-r--r--modules/gdscript/gdscript_editor.cpp11
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp195
-rw-r--r--modules/gdscript/gdscript_parser.h14
-rw-r--r--modules/gdscript/gdscript_tokenizer.h2
-rw-r--r--modules/gdscript/gdscript_vm.cpp21
-rw-r--r--modules/gdscript/gdscript_warning.cpp16
-rw-r--r--modules/gdscript/gdscript_warning.h10
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp8
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp6
-rw-r--r--modules/gdscript/language_server/lsp.hpp2
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd49
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out19
-rw-r--r--modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/if_after_lambda.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_bind_unused.gd13
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_bind_unused.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_dictionary.gd43
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_dictionary.out15
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd26
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.out9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd16
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out2
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp46
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml69
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml2
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp2
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp1
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.h3
-rw-r--r--modules/gltf/gltf_accessor.h1
-rw-r--r--modules/gltf/gltf_document.cpp116
-rw-r--r--modules/gltf/gltf_document.h17
-rw-r--r--modules/gltf/gltf_document_extension.cpp100
-rw-r--r--modules/gltf/gltf_document_extension.h38
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.cpp45
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.h8
-rw-r--r--modules/gltf/gltf_skeleton.h2
-rw-r--r--modules/gltf/gltf_state.cpp11
-rw-r--r--modules/gltf/gltf_state.h11
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp2
-rw-r--r--modules/gridmap/grid_map.cpp67
-rw-r--r--modules/gridmap/grid_map.h5
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp4
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.h1
-rw-r--r--modules/mono/csharp_script.cpp24
-rw-r--r--modules/mono/csharp_script.h12
-rw-r--r--modules/mono/editor/bindings_generator.cpp73
-rw-r--r--modules/mono/editor/bindings_generator.h6
-rw-r--r--modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs18
-rw-r--r--modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs5
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h1
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h1
-rw-r--r--modules/navigation/godot_navigation_server.cpp52
-rw-r--r--modules/navigation/godot_navigation_server.h12
-rw-r--r--modules/navigation/nav_map.cpp22
-rw-r--r--modules/navigation/nav_map.h12
-rw-r--r--modules/navigation/nav_region.cpp8
-rw-r--r--modules/navigation/nav_region.h14
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp43
-rw-r--r--modules/navigation/rvo_agent.cpp3
-rw-r--r--modules/noise/fastnoise_lite.cpp15
-rw-r--r--modules/noise/noise_texture.cpp4
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp1
-rw-r--r--modules/openxr/openxr_api.cpp8
-rw-r--r--modules/openxr/openxr_api.h6
-rw-r--r--modules/raycast/lightmap_raycaster.cpp10
-rw-r--r--modules/raycast/lightmap_raycaster.h4
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp6
-rw-r--r--modules/raycast/raycast_occlusion_cull.h16
-rw-r--r--modules/raycast/static_raycaster.cpp10
-rw-r--r--modules/raycast/static_raycaster.h4
-rw-r--r--modules/text_server_adv/SCsub2
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct12
-rw-r--r--modules/text_server_adv/text_server_adv.cpp94
-rw-r--r--modules/text_server_adv/text_server_adv.h14
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct10
-rw-r--r--modules/text_server_fb/text_server_fb.cpp81
-rw-r--r--modules/text_server_fb/text_server_fb.h10
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp129
-rw-r--r--modules/visual_script/editor/visual_script_editor.h4
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.cpp11
-rw-r--r--modules/visual_script/visual_script.cpp124
-rw-r--r--modules/visual_script/visual_script.h3
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp4
-rw-r--r--modules/visual_script/visual_script_nodes.cpp8
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnection.xml7
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml5
-rw-r--r--modules/webrtc/webrtc_data_channel.h2
-rw-r--r--modules/webrtc/webrtc_peer_connection.cpp7
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.cpp7
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.h2
135 files changed, 1745 insertions, 704 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index a5b3db89d9..0f09eb2020 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -638,7 +638,7 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape3D::get_meshes);
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001,suffix:m"), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents");
ADD_GROUP("Collision", "collision_");
@@ -1052,7 +1052,7 @@ void CSGSphere3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere3D::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere3D::get_material);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
@@ -1225,7 +1225,7 @@ void CSGBox3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
@@ -1405,8 +1405,8 @@ void CSGCylinder3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces);
ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
@@ -1630,8 +1630,8 @@ void CSGTorus3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces);
ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_inner_radius", "get_inner_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_outer_radius", "get_outer_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
@@ -2135,7 +2135,7 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.01,100.0,0.01,or_greater,exp"), "set_depth", "get_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.01,100.0,0.01,or_greater,exp,suffix:m"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
@@ -2145,7 +2145,7 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater"), "set_path_u_distance", "get_path_u_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater,suffix:m"), "set_path_u_distance", "get_path_u_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 4d972e46c6..6442ff71fc 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -349,9 +349,11 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (cs->is_root_shape()) {
Array csg_meshes = cs->get_meshes();
- Ref<Mesh> csg_mesh = csg_meshes[1];
- if (csg_mesh.is_valid()) {
- p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ if (csg_meshes.size() == 2) {
+ Ref<Mesh> csg_mesh = csg_meshes[1];
+ if (csg_mesh.is_valid()) {
+ p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ }
}
}
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index d23c4b637c..4b2ea6faa5 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -49,6 +49,7 @@ if env["builtin_freetype"]:
"src/psnames/psnames.c",
"src/raster/raster.c",
"src/sdf/sdf.c",
+ "src/svg/svg.c",
"src/smooth/smooth.c",
"src/truetype/truetype.c",
"src/type1/type1.c",
@@ -87,7 +88,7 @@ if env["builtin_freetype"]:
# Also needed in main env for scene/
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
- env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG"])
+ env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", "FT_CONFIG_OPTION_SYSTEM_ZLIB"])
if env["target"] == "debug":
env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 191568661d..b86e9b386d 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -387,9 +387,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
- if (!in_node_path && in_region == -1 && str[j] == '$') {
+ if (!in_node_path && in_region == -1 && (str[j] == '$' || str[j] == '%')) {
in_node_path = true;
- } else if (in_region != -1 || (is_a_symbol && str[j] != '/')) {
+ } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) {
in_node_path = false;
}
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index 4633a431d8..969a50f48c 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
-#include "core/templates/rb_set.h"
+#include "core/templates/hash_set.h"
#include "editor/editor_translation_parser.h"
#include "modules/gdscript/gdscript_parser.h"
@@ -44,9 +44,9 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug
// List of patterns used for extracting translation strings.
StringName tr_func = "tr";
StringName trn_func = "tr_n";
- RBSet<StringName> assignment_patterns;
- RBSet<StringName> first_arg_patterns;
- RBSet<StringName> second_arg_patterns;
+ HashSet<StringName> assignment_patterns;
+ HashSet<StringName> first_arg_patterns;
+ HashSet<StringName> second_arg_patterns;
// FileDialog patterns.
StringName fd_add_filter = "add_filter";
StringName fd_set_filter = "set_filters";
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
new file mode 100644
index 0000000000..b4b2305b8c
--- /dev/null
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
@@ -0,0 +1,11 @@
+# meta-description: Basic import script template
+@tool
+extends EditorScenePostImport
+
+
+# Called by the editor when a scene has this script set as the import script in the import tab.
+func _post_import(scene: Node) -> Object:
+ # Modify the contents of the scene upon import. For example, setting up LODs:
+# (scene.get_node(^"HighPolyMesh") as MeshInstance3D).draw_distance_end = 5.0
+# (scene.get_node(^"LowPolyMesh") as MeshInstance3D).draw_distance_begin = 5.0
+ return scene # Return the modified root node when you're done.
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
new file mode 100644
index 0000000000..875afb4fc0
--- /dev/null
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
@@ -0,0 +1,7 @@
+# meta-description: Basic import script template (no comments)
+@tool
+extends EditorScenePostImport
+
+
+func _post_import(scene: Node) -> Object:
+ return scene
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index e400d0bf94..64258ee8d3 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -128,6 +128,7 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance
return;
}
}
+ ERR_FAIL_NULL(p_script->implicit_initializer);
p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
}
@@ -764,8 +765,8 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
_update_exports_values(values, propnames);
if (changed) {
- for (RBSet<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->update(propnames, values);
+ for (PlaceHolderScriptInstance *E : placeholders) {
+ E->update(propnames, values);
}
} else {
p_instance_to_update->update(propnames, values);
@@ -788,10 +789,10 @@ void GDScript::update_exports() {
return;
}
- RBSet<ObjectID> copy = inheriters_cache; //might get modified
+ HashSet<ObjectID> copy = inheriters_cache; //might get modified
- for (RBSet<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
- Object *id = ObjectDB::get_instance(E->get());
+ for (const ObjectID &E : copy) {
+ Object *id = ObjectDB::get_instance(E);
GDScript *s = Object::cast_to<GDScript>(id);
if (!s) {
continue;
@@ -937,10 +938,10 @@ void GDScript::get_constants(HashMap<StringName, Variant> *p_constants) {
}
}
-void GDScript::get_members(RBSet<StringName> *p_members) {
+void GDScript::get_members(HashSet<StringName> *p_members) {
if (p_members) {
- for (RBSet<StringName>::Element *E = members.front(); E; E = E->next()) {
- p_members->insert(E->get());
+ for (const StringName &E : members) {
+ p_members->insert(E);
}
}
}
@@ -1475,6 +1476,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
if (d.has("usage")) {
pinfo.usage = d["usage"];
}
+ if (d.has("class_name")) {
+ pinfo.class_name = d["class_name"];
+ }
props.push_back(pinfo);
}
@@ -1916,7 +1920,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
#ifdef TOOLS_ENABLED
while (script->placeholders.size()) {
- Object *obj = script->placeholders.front()->get()->get_owner();
+ Object *obj = (*script->placeholders.begin())->get_owner();
//save instance info
if (obj->get_script_instance()) {
@@ -1926,7 +1930,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
obj->set_script(Variant());
} else {
// no instance found. Let's remove it so we don't loop forever
- script->placeholders.erase(script->placeholders.front()->get());
+ script->placeholders.erase(*script->placeholders.begin());
}
}
@@ -2232,9 +2236,13 @@ GDScriptLanguage::GDScriptLanguage() {
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
- String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
- bool default_enabled = !warning.begins_with("unsafe_");
- GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled);
+ GDScriptWarning::Code code = (GDScriptWarning::Code)i;
+ Variant default_enabled = GDScriptWarning::get_default_value(code);
+ String path = GDScriptWarning::get_settings_path_from_code(code);
+ GLOBAL_DEF(path, default_enabled);
+
+ PropertyInfo property_info = GDScriptWarning::get_property_info(code);
+ ProjectSettings::get_singleton()->set_custom_property_info(path, property_info);
}
#endif // DEBUG_ENABLED
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 5199d3215d..80f187a375 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -37,6 +37,7 @@
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
+#include "core/templates/rb_set.h"
#include "gdscript_function.h"
class GDScriptNativeClass : public RefCounted {
@@ -80,7 +81,7 @@ class GDScript : public Script {
GDScript *_base = nullptr; //fast pointer access
GDScript *_owner = nullptr; //for subclasses
- RBSet<StringName> members; //members are just indices to the instantiated script.
+ HashSet<StringName> members; //members are just indices to the instantiated script.
HashMap<StringName, Variant> constants;
HashMap<StringName, GDScriptFunction *> member_functions;
HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script.
@@ -95,7 +96,7 @@ class GDScript : public Script {
List<PropertyInfo> members_cache;
HashMap<StringName, Variant> member_default_values_cache;
Ref<GDScript> base_cache;
- RBSet<ObjectID> inheriters_cache;
+ HashSet<ObjectID> inheriters_cache;
bool source_changed_cache = false;
bool placeholder_fallback_enabled = false;
void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames);
@@ -139,7 +140,7 @@ class GDScript : public Script {
String _get_debug_path() const;
#ifdef TOOLS_ENABLED
- RBSet<PlaceHolderScriptInstance *> placeholders;
+ HashSet<PlaceHolderScriptInstance *> placeholders;
//void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
@@ -178,7 +179,7 @@ public:
const HashMap<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; }
const HashMap<StringName, Variant> &get_constants() const { return constants; }
- const RBSet<StringName> &get_members() const { return members; }
+ const HashSet<StringName> &get_members() const { return members; }
const GDScriptDataType &get_member_type(const StringName &p_member) const {
CRASH_COND(!member_indices.has(p_member));
return member_indices[p_member].data_type;
@@ -246,7 +247,7 @@ public:
}
virtual void get_constants(HashMap<StringName, Variant> *p_constants) override;
- virtual void get_members(RBSet<StringName> *p_members) override;
+ virtual void get_members(HashSet<StringName> *p_members) override;
virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override;
@@ -449,7 +450,7 @@ public:
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
virtual bool has_named_classes() const override;
virtual bool supports_builtin_mode() const override;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 32fa3b8c87..a070d319f3 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -898,7 +898,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
#ifdef DEBUG_ENABLED
- RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : member.function->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -947,7 +947,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
- RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : member.function->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -1160,8 +1160,16 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
}
}
} else {
- GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type);
- p_function->set_datatype(return_type);
+ if (p_function->return_type != nullptr) {
+ p_function->set_datatype(resolve_datatype(p_function->return_type));
+ } else {
+ // In case the function is not typed, we can safely assume it's a Variant, so it's okay to mark as "inferred" here.
+ // It's not "undetected" to not mix up with unknown functions.
+ GDScriptParser::DataType return_type;
+ return_type.type_source = GDScriptParser::DataType::INFERRED;
+ return_type.kind = GDScriptParser::DataType::VARIANT;
+ p_function->set_datatype(return_type);
+ }
#ifdef TOOLS_ENABLED
// Check if the function signature matches the parent. If not it's an error since it breaks polymorphism.
@@ -1231,7 +1239,7 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun
GDScriptParser::DataType return_type = p_function->body->get_datatype();
- if (p_function->get_datatype().has_no_type() && return_type.is_set()) {
+ if (!p_function->get_datatype().is_hard_type() && return_type.is_set()) {
// Use the suite inferred type if return isn't explicitly set.
return_type.type_source = GDScriptParser::DataType::INFERRED;
p_function->set_datatype(p_function->body->get_datatype());
@@ -1279,7 +1287,7 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
}
#ifdef DEBUG_ENABLED
- RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : stmt->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -1514,10 +1522,22 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant) {
GDScriptParser::DataType type;
+ GDScriptParser::DataType explicit_type;
+ if (p_constant->datatype_specifier != nullptr) {
+ explicit_type = resolve_datatype(p_constant->datatype_specifier);
+ explicit_type.is_meta_type = false;
+ }
+
if (p_constant->initializer != nullptr) {
reduce_expression(p_constant->initializer);
if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) {
- const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer));
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer);
+ const_fold_array(array);
+
+ // Can only infer typed array if it has elements.
+ if (array->elements.size() > 0 || (p_constant->datatype_specifier != nullptr && explicit_type.has_container_element_type())) {
+ update_array_literal_element_type(explicit_type, array);
+ }
} else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer));
}
@@ -1536,8 +1556,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
}
if (p_constant->datatype_specifier != nullptr) {
- GDScriptParser::DataType explicit_type = resolve_datatype(p_constant->datatype_specifier);
- explicit_type.is_meta_type = false;
if (!is_type_compatible(explicit_type, type)) {
push_error(vformat(R"(Assigned value for constant "%s" has type %s which is not compatible with defined type %s.)", p_constant->identifier->name, type.to_string(), explicit_type.to_string()), p_constant->initializer);
#ifdef DEBUG_ENABLED
@@ -1639,8 +1657,8 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
p_match_pattern->bind->set_datatype(result);
#ifdef DEBUG_ENABLED
is_shadowing(p_match_pattern->bind, "pattern bind");
- if (p_match_pattern->bind->usages == 0) {
- parser->push_warning(p_match_pattern->bind, GDScriptWarning::UNASSIGNED_VARIABLE, p_match_pattern->bind->name);
+ if (p_match_pattern->bind->usages == 0 && !String(p_match_pattern->bind->name).begins_with("_")) {
+ parser->push_warning(p_match_pattern->bind, GDScriptWarning::UNUSED_VARIABLE, p_match_pattern->bind->name);
}
#endif
break;
@@ -2057,7 +2075,8 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) {
p_await->set_datatype(awaiting_type);
#ifdef DEBUG_ENABLED
- if (!awaiting_type.is_coroutine && awaiting_type.builtin_type != Variant::SIGNAL) {
+ awaiting_type = p_await->to_await->get_datatype();
+ if (!(awaiting_type.has_no_type() || awaiting_type.is_coroutine || awaiting_type.builtin_type == Variant::SIGNAL)) {
parser->push_warning(p_await, GDScriptWarning::REDUNDANT_AWAIT);
}
#endif
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 5b03f6dbb4..3966b81b6e 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -33,7 +33,7 @@
#include "core/object/object.h"
#include "core/object/ref_counted.h"
-#include "core/templates/rb_set.h"
+#include "core/templates/hash_set.h"
#include "gdscript_cache.h"
#include "gdscript_parser.h"
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index bd98d66fcc..4c15fca91e 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -223,13 +223,13 @@ Error GDScriptCache::finish_compiling(const String &p_owner) {
singleton->full_gdscript_cache[p_owner] = script.ptr();
singleton->shallow_gdscript_cache.erase(p_owner);
- RBSet<String> depends = singleton->dependencies[p_owner];
+ HashSet<String> depends = singleton->dependencies[p_owner];
Error err = OK;
- for (const RBSet<String>::Element *E = depends.front(); E != nullptr; E = E->next()) {
+ for (const String &E : depends) {
Error this_err = OK;
// No need to save the script. We assume it's already referenced in the owner.
- get_full_script(E->get(), this_err);
+ get_full_script(E, this_err);
if (this_err != OK) {
err = this_err;
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 8abae7d4ad..b971bdd984 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -34,7 +34,7 @@
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/templates/hash_map.h"
-#include "core/templates/rb_set.h"
+#include "core/templates/hash_set.h"
#include "gdscript.h"
class GDScriptAnalyzer;
@@ -74,7 +74,7 @@ class GDScriptCache {
HashMap<String, GDScriptParserRef *> parser_map;
HashMap<String, GDScript *> shallow_gdscript_cache;
HashMap<String, GDScript *> full_gdscript_cache;
- HashMap<String, RBSet<String>> dependencies;
+ HashMap<String, HashSet<String>> dependencies;
friend class GDScript;
friend class GDScriptParserRef;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index cb389fd86a..b2cce9d8ee 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -108,11 +108,15 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.native_type = result.script_type->get_instance_base_type();
} break;
case GDScriptParser::DataType::CLASS: {
- // Locate class by constructing the path to it and following that path
+ // Locate class by constructing the path to it and following that path.
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->path);
- const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->name);
+ result.kind = GDScriptDataType::GDSCRIPT;
+ result.builtin_type = p_datatype.builtin_type;
+
+ String class_name = class_type->fqcn.split("::")[0];
+ const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_name == main_script->path);
+ const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_name == main_script->name);
if (is_inner_by_path || is_inner_by_name) {
// Local class.
List<StringName> names;
@@ -131,16 +135,41 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
script = script->subclasses[names.back()->get()];
names.pop_back();
}
- result.kind = GDScriptDataType::GDSCRIPT;
result.script_type = script.ptr();
result.native_type = script->get_instance_base_type();
- result.builtin_type = p_datatype.builtin_type;
} else {
- result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path);
+ // Inner class.
+ PackedStringArray classes = class_type->fqcn.split("::");
+ if (!classes.is_empty()) {
+ for (GDScript *script : parsed_classes) {
+ // Checking of inheritance structure of inner class to find a correct script link.
+ if (script->name == classes[classes.size() - 1]) {
+ PackedStringArray classes2 = script->fully_qualified_name.split("::");
+ bool valid = true;
+ if (classes.size() != classes2.size()) {
+ valid = false;
+ } else {
+ for (int i = 0; i < classes.size(); i++) {
+ if (classes[i] != classes2[i]) {
+ valid = false;
+ break;
+ }
+ }
+ }
+ if (!valid) {
+ continue;
+ }
+ result.script_type_ref = Ref<GDScript>(script);
+ break;
+ }
+ }
+ }
+ if (result.script_type_ref.is_null()) {
+ result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path);
+ }
+
result.script_type = result.script_type_ref.ptr();
result.native_type = p_datatype.native_type;
- result.builtin_type = p_datatype.builtin_type;
}
}
} break;
@@ -638,20 +667,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::GET_NODE: {
const GDScriptParser::GetNodeNode *get_node = static_cast<const GDScriptParser::GetNodeNode *>(p_expression);
- String node_name;
- if (get_node->string != nullptr) {
- node_name += String(get_node->string->value);
- } else {
- for (int i = 0; i < get_node->chain.size(); i++) {
- if (i > 0) {
- node_name += "/";
- }
- node_name += get_node->chain[i]->name;
- }
- }
-
Vector<GDScriptCodeGenerator::Address> args;
- args.push_back(codegen.add_constant(NodePath(node_name)));
+ args.push_back(codegen.add_constant(NodePath(get_node->full_path)));
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype()));
@@ -1372,25 +1389,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->pop_temporary();
codegen.generator->pop_temporary();
- // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
- if (p_is_nested) {
- // Use the previous value as target, since we only need one temporary variable.
- codegen.generator->write_and_right_operand(result_addr);
- codegen.generator->write_end_and(p_previous_test);
- } else if (!p_is_first) {
- // Use the previous value as target, since we only need one temporary variable.
- codegen.generator->write_or_right_operand(result_addr);
- codegen.generator->write_end_or(p_previous_test);
- } else {
- // Just assign this value to the accumulator temporary.
- codegen.generator->write_assign(p_previous_test, result_addr);
- }
- codegen.generator->pop_temporary(); // Remove temp result addr.
-
// Create temporaries outside the loop so they can be reused.
GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
- GDScriptCodeGenerator::Address test_addr = p_previous_test;
// Evaluate element by element.
for (int i = 0; i < p_pattern->array.size(); i++) {
@@ -1400,7 +1401,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
}
// Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
- codegen.generator->write_and_left_operand(test_addr);
+ codegen.generator->write_and_left_operand(result_addr);
// Add index to constant map.
GDScriptCodeGenerator::Address index_addr = codegen.add_constant(i);
@@ -1414,19 +1415,34 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->write_call_utility(element_type_addr, "typeof", typeof_args);
// Try the pattern inside the element.
- test_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, p_previous_test, false, true);
+ result_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, result_addr, false, true);
if (r_error != OK) {
return GDScriptCodeGenerator::Address();
}
- codegen.generator->write_and_right_operand(test_addr);
- codegen.generator->write_end_and(test_addr);
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(result_addr);
}
// Remove element temporaries.
codegen.generator->pop_temporary();
codegen.generator->pop_temporary();
- return test_addr;
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(result_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, result_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove temp result addr.
+
+ return p_previous_test;
} break;
case GDScriptParser::PatternNode::PT_DICTIONARY: {
if (p_is_nested) {
@@ -1471,27 +1487,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->pop_temporary();
codegen.generator->pop_temporary();
- // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
- if (p_is_nested) {
- // Use the previous value as target, since we only need one temporary variable.
- codegen.generator->write_and_right_operand(result_addr);
- codegen.generator->write_end_and(p_previous_test);
- } else if (!p_is_first) {
- // Use the previous value as target, since we only need one temporary variable.
- codegen.generator->write_or_right_operand(result_addr);
- codegen.generator->write_end_or(p_previous_test);
- } else {
- // Just assign this value to the accumulator temporary.
- codegen.generator->write_assign(p_previous_test, result_addr);
- }
- codegen.generator->pop_temporary(); // Remove temp result addr.
-
// Create temporaries outside the loop so they can be reused.
- temp_type.builtin_type = Variant::BOOL;
- GDScriptCodeGenerator::Address test_result = codegen.add_temporary(temp_type);
GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
- GDScriptCodeGenerator::Address test_addr = p_previous_test;
// Evaluate element by element.
for (int i = 0; i < p_pattern->dictionary.size(); i++) {
@@ -1502,7 +1500,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
}
// Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
- codegen.generator->write_and_left_operand(test_addr);
+ codegen.generator->write_and_left_operand(result_addr);
// Get the pattern key.
GDScriptCodeGenerator::Address pattern_key_addr = _parse_expression(codegen, r_error, element.key);
@@ -1513,11 +1511,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check if pattern key exists in user's dictionary. This will be AND-ed with next result.
func_args.clear();
func_args.push_back(pattern_key_addr);
- codegen.generator->write_call(test_result, p_value_addr, "has", func_args);
+ codegen.generator->write_call(result_addr, p_value_addr, "has", func_args);
if (element.value_pattern != nullptr) {
// Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
- codegen.generator->write_and_left_operand(test_result);
+ codegen.generator->write_and_left_operand(result_addr);
// Get actual value from user dictionary.
codegen.generator->write_get(element_addr, pattern_key_addr, p_value_addr);
@@ -1528,16 +1526,16 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->write_call_utility(element_type_addr, "typeof", func_args);
// Try the pattern inside the value.
- test_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, test_addr, false, true);
+ result_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, result_addr, false, true);
if (r_error != OK) {
return GDScriptCodeGenerator::Address();
}
- codegen.generator->write_and_right_operand(test_addr);
- codegen.generator->write_end_and(test_addr);
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(result_addr);
}
- codegen.generator->write_and_right_operand(test_addr);
- codegen.generator->write_end_and(test_addr);
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(result_addr);
// Remove pattern key temporary.
if (pattern_key_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1548,9 +1546,23 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Remove element temporaries.
codegen.generator->pop_temporary();
codegen.generator->pop_temporary();
- codegen.generator->pop_temporary();
- return test_addr;
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(result_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, result_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove temp result addr.
+
+ return p_previous_test;
} break;
case GDScriptParser::PatternNode::PT_REST:
// Do nothing.
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index c9ffb04fb8..4841884e2d 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_COMPILER_H
#define GDSCRIPT_COMPILER_H
-#include "core/templates/rb_set.h"
+#include "core/templates/hash_set.h"
#include "gdscript.h"
#include "gdscript_codegen.h"
#include "gdscript_function.h"
@@ -39,8 +39,8 @@
class GDScriptCompiler {
const GDScriptParser *parser = nullptr;
- RBSet<GDScript *> parsed_classes;
- RBSet<GDScript *> parsing_classes;
+ HashSet<GDScript *> parsed_classes;
+ HashSet<GDScript *> parsing_classes;
GDScript *main_script = nullptr;
struct CodeGen {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 72f54626e3..202d1dcdf4 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -110,7 +110,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl
}
}
-bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, RBSet<int> *r_safe_lines) const {
+bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const {
GDScriptParser parser;
GDScriptAnalyzer analyzer(&parser);
@@ -159,7 +159,7 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
#ifdef DEBUG_ENABLED
if (r_safe_lines) {
- const RBSet<int> &unsafe_lines = parser.get_unsafe_lines();
+ const HashSet<int> &unsafe_lines = parser.get_unsafe_lines();
for (int i = 1; i <= parser.get_last_line_number(); i++) {
if (!unsafe_lines.has(i)) {
r_safe_lines->insert(i);
@@ -3155,7 +3155,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
- // Before parsing, try the usual stuff
+ // Before parsing, try the usual stuff.
if (ClassDB::class_exists(p_symbol)) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
r_result.class_name = p_symbol;
@@ -3171,7 +3171,9 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
}
- if (GDScriptUtilityFunctions::function_exists(p_symbol)) {
+ // Need special checks for assert and preload as they are technically
+ // keywords, so are not registered in GDScriptUtilityFunctions.
+ if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
r_result.class_name = "@GDScript";
r_result.class_member = p_symbol;
@@ -3227,6 +3229,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
is_function = true;
[[fallthrough]];
}
+ case GDScriptParser::COMPLETION_ASSIGN:
case GDScriptParser::COMPLETION_CALL_ARGUMENTS:
case GDScriptParser::COMPLETION_IDENTIFIER: {
GDScriptParser::DataType base_type;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index deef593f34..cd3b7d69c5 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -270,6 +270,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->exit_function();
}
+
+ _clear_stack();
#endif
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 8563f2b432..bc225850c9 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -203,7 +203,8 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
if (ignored_warnings.has(warn_name)) {
return;
}
- if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) {
+ int warn_level = (int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code));
+ if (!warn_level) {
return;
}
@@ -215,6 +216,11 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
warning.leftmost_column = p_source->leftmost_column;
warning.rightmost_column = p_source->rightmost_column;
+ if (warn_level == GDScriptWarning::WarnLevel::ERROR) {
+ push_error(warning.get_message(), p_source);
+ return;
+ }
+
List<GDScriptWarning>::Element *before = nullptr;
for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
if (E->get().start_line > warning.start_line) {
@@ -1624,6 +1630,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
case Node::AWAIT:
// Fine.
break;
+ case Node::LAMBDA:
+ // Standalone lambdas can't be used, so make this an error.
+ push_error("Standalone lambdas cannot be accessed. Consider assigning it to a variable.", expression);
+ break;
default:
push_warning(expression, GDScriptWarning::STANDALONE_EXPRESSION);
}
@@ -1808,7 +1818,6 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
#ifdef DEBUG_ENABLED
bool all_have_return = true;
bool have_wildcard = false;
- bool wildcard_has_return = false;
bool have_wildcard_without_continue = false;
#endif
@@ -1826,9 +1835,6 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
if (branch->has_wildcard) {
have_wildcard = true;
- if (branch->block->has_return) {
- wildcard_has_return = true;
- }
if (!branch->block->has_continue) {
have_wildcard_without_continue = true;
}
@@ -1843,7 +1849,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
consume(GDScriptTokenizer::Token::DEDENT, R"(Expected an indented block after "match" statement.)");
#ifdef DEBUG_ENABLED
- if (wildcard_has_return || (all_have_return && have_wildcard)) {
+ if (all_have_return && have_wildcard) {
current_suite->has_return = true;
}
#endif
@@ -2103,7 +2109,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign);
while (p_precedence <= get_rule(current.type)->precedence) {
- if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL)) {
+ if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || (previous_operand->type == Node::LAMBDA && lambda_ended)) {
return previous_operand;
}
// Also switch multiline mode on here for infix operators.
@@ -2824,51 +2830,97 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
}
GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p_previous_operand, bool p_can_assign) {
- if (match(GDScriptTokenizer::Token::LITERAL)) {
- if (previous.literal.get_type() != Variant::STRING) {
- push_error(R"(Expect node path as string or identifier after "$".)");
+ if (!current.is_node_name() && !check(GDScriptTokenizer::Token::LITERAL) && !check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) {
+ push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous.get_name()));
+ return nullptr;
+ }
+
+ if (check(GDScriptTokenizer::Token::LITERAL)) {
+ if (current.literal.get_type() != Variant::STRING) {
+ push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous.get_name()));
return nullptr;
}
- GetNodeNode *get_node = alloc_node<GetNodeNode>();
- make_completion_context(COMPLETION_GET_NODE, get_node);
- get_node->string = parse_literal();
- return get_node;
- } else if (current.is_node_name()) {
- GetNodeNode *get_node = alloc_node<GetNodeNode>();
- int chain_position = 0;
- do {
- make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++);
- if (!current.is_node_name()) {
- push_error(R"(Expect node path after "/".)");
+ }
+
+ GetNodeNode *get_node = alloc_node<GetNodeNode>();
+
+ // Store the last item in the path so the parser knows what to expect.
+ // Allow allows more specific error messages.
+ enum PathState {
+ PATH_STATE_START,
+ PATH_STATE_SLASH,
+ PATH_STATE_PERCENT,
+ PATH_STATE_NODE_NAME,
+ } path_state = PATH_STATE_START;
+
+ if (previous.type == GDScriptTokenizer::Token::DOLLAR) {
+ // Detect initial slash, which will be handled in the loop if it matches.
+ match(GDScriptTokenizer::Token::SLASH);
+#ifdef DEBUG_ENABLED
+ } else {
+ get_node->use_dollar = false;
+#endif
+ }
+
+ int context_argument = 0;
+
+ do {
+ if (previous.type == GDScriptTokenizer::Token::PERCENT) {
+ if (path_state != PATH_STATE_START && path_state != PATH_STATE_SLASH) {
+ push_error(R"("%" is only valid in the beginning of a node name (either after "$" or after "/"))");
return nullptr;
}
- advance();
- IdentifierNode *identifier = alloc_node<IdentifierNode>();
- identifier->name = previous.get_identifier();
- get_node->chain.push_back(identifier);
- } while (match(GDScriptTokenizer::Token::SLASH));
- return get_node;
- } else if (match(GDScriptTokenizer::Token::SLASH)) {
- GetNodeNode *get_node = alloc_node<GetNodeNode>();
- IdentifierNode *identifier_root = alloc_node<IdentifierNode>();
- get_node->chain.push_back(identifier_root);
- int chain_position = 0;
- do {
- make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++);
- if (!current.is_node_name()) {
- push_error(R"(Expect node path after "/".)");
+ get_node->full_path += "%";
+
+ path_state = PATH_STATE_PERCENT;
+ } else if (previous.type == GDScriptTokenizer::Token::SLASH) {
+ if (path_state != PATH_STATE_START && path_state != PATH_STATE_NODE_NAME) {
+ push_error(R"("/" is only valid at the beginning of the path or after a node name.)");
+ return nullptr;
+ }
+
+ get_node->full_path += "/";
+
+ path_state = PATH_STATE_SLASH;
+ }
+
+ make_completion_context(COMPLETION_GET_NODE, get_node, context_argument++);
+
+ if (match(GDScriptTokenizer::Token::LITERAL)) {
+ if (previous.literal.get_type() != Variant::STRING) {
+ String previous_token;
+ switch (path_state) {
+ case PATH_STATE_START:
+ previous_token = "$";
+ break;
+ case PATH_STATE_PERCENT:
+ previous_token = "%";
+ break;
+ case PATH_STATE_SLASH:
+ previous_token = "/";
+ break;
+ default:
+ break;
+ }
+ push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous_token));
return nullptr;
}
+
+ get_node->full_path += previous.literal.operator String();
+
+ path_state = PATH_STATE_NODE_NAME;
+ } else if (current.is_node_name()) {
advance();
- IdentifierNode *identifier = alloc_node<IdentifierNode>();
- identifier->name = previous.get_identifier();
- get_node->chain.push_back(identifier);
- } while (match(GDScriptTokenizer::Token::SLASH));
- return get_node;
- } else {
- push_error(R"(Expect node path as string or identifier after "$".)");
- return nullptr;
- }
+ get_node->full_path += previous.get_identifier();
+
+ path_state = PATH_STATE_NODE_NAME;
+ } else if (!check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) {
+ push_error(vformat(R"(Unexpected "%s" in node path.)", current.get_name()));
+ return nullptr;
+ }
+ } while (match(GDScriptTokenizer::Token::SLASH) || match(GDScriptTokenizer::Token::PERCENT));
+
+ return get_node;
}
GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_previous_operand, bool p_can_assign) {
@@ -2926,6 +2978,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
current_function = function;
SuiteNode *body = alloc_node<SuiteNode>();
+ body->parent_function = current_function;
+ body->parent_block = current_suite;
+
SuiteNode *previous_suite = current_suite;
current_suite = body;
@@ -3138,24 +3193,23 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
String title, link; // For tutorials.
String doc_line = comments[line++].comment.trim_prefix("##");
- String striped_line = doc_line.strip_edges();
+ String stripped_line = doc_line.strip_edges();
// Set the read mode.
- if (striped_line.begins_with("@desc:") && p_desc.is_empty()) {
+ if (stripped_line.is_empty() && mode == BRIEF && !p_brief.is_empty()) {
mode = DESC;
- striped_line = striped_line.trim_prefix("@desc:");
- in_codeblock = _in_codeblock(doc_line, in_codeblock);
+ continue;
- } else if (striped_line.begins_with("@tutorial")) {
+ } else if (stripped_line.begins_with("@tutorial")) {
int begin_scan = String("@tutorial").length();
- if (begin_scan >= striped_line.length()) {
+ if (begin_scan >= stripped_line.length()) {
continue; // invalid syntax.
}
- if (striped_line[begin_scan] == ':') { // No title.
+ if (stripped_line[begin_scan] == ':') { // No title.
// Syntax: ## @tutorial: https://godotengine.org/ // The title argument is optional.
title = "";
- link = striped_line.trim_prefix("@tutorial:").strip_edges();
+ link = stripped_line.trim_prefix("@tutorial:").strip_edges();
} else {
/* Syntax:
@@ -3163,35 +3217,35 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
* ^ open ^ close ^ colon ^ url
*/
int open_bracket_pos = begin_scan, close_bracket_pos = 0;
- while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) {
+ while (open_bracket_pos < stripped_line.length() && (stripped_line[open_bracket_pos] == ' ' || stripped_line[open_bracket_pos] == '\t')) {
open_bracket_pos++;
}
- if (open_bracket_pos == striped_line.length() || striped_line[open_bracket_pos++] != '(') {
+ if (open_bracket_pos == stripped_line.length() || stripped_line[open_bracket_pos++] != '(') {
continue; // invalid syntax.
}
close_bracket_pos = open_bracket_pos;
- while (close_bracket_pos < striped_line.length() && striped_line[close_bracket_pos] != ')') {
+ while (close_bracket_pos < stripped_line.length() && stripped_line[close_bracket_pos] != ')') {
close_bracket_pos++;
}
- if (close_bracket_pos == striped_line.length()) {
+ if (close_bracket_pos == stripped_line.length()) {
continue; // invalid syntax.
}
int colon_pos = close_bracket_pos + 1;
- while (colon_pos < striped_line.length() && (striped_line[colon_pos] == ' ' || striped_line[colon_pos] == '\t')) {
+ while (colon_pos < stripped_line.length() && (stripped_line[colon_pos] == ' ' || stripped_line[colon_pos] == '\t')) {
colon_pos++;
}
- if (colon_pos == striped_line.length() || striped_line[colon_pos++] != ':') {
+ if (colon_pos == stripped_line.length() || stripped_line[colon_pos++] != ':') {
continue; // invalid syntax.
}
- title = striped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges();
- link = striped_line.substr(colon_pos).strip_edges();
+ title = stripped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges();
+ link = stripped_line.substr(colon_pos).strip_edges();
}
mode = TUTORIALS;
in_codeblock = false;
- } else if (striped_line.is_empty()) {
+ } else if (stripped_line.is_empty()) {
continue;
} else {
// Tutorial docs are single line, we need a @tag after it.
@@ -3211,7 +3265,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
}
doc_line = doc_line.substr(i);
} else {
- doc_line = striped_line;
+ doc_line = stripped_line;
}
String line_join = (in_codeblock) ? "\n" : " ";
@@ -3270,7 +3324,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_POWER }, // STAR_STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH,
- { nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
+ { &GDScriptParser::parse_get_node, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
// Assignment
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PLUS_EQUAL,
@@ -4250,17 +4304,10 @@ void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const
}
void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) {
- push_text("$");
- if (p_get_node->string != nullptr) {
- print_literal(p_get_node->string);
- } else {
- for (int i = 0; i < p_get_node->chain.size(); i++) {
- if (i > 0) {
- push_text("/");
- }
- print_identifier(p_get_node->chain[i]);
- }
+ if (p_get_node->use_dollar) {
+ push_text("$");
}
+ push_text(p_get_node->full_path);
}
void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 17f87edeeb..e3f8d4b8ba 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -749,8 +749,10 @@ public:
};
struct GetNodeNode : public ExpressionNode {
- LiteralNode *string = nullptr;
- Vector<IdentifierNode *> chain;
+ String full_path;
+#ifdef DEBUG_ENABLED
+ bool use_dollar = true;
+#endif
GetNodeNode() {
type = GET_NODE;
@@ -1205,9 +1207,9 @@ private:
List<ParserError> errors;
#ifdef DEBUG_ENABLED
List<GDScriptWarning> warnings;
- RBSet<String> ignored_warnings;
- RBSet<uint32_t> ignored_warning_codes;
- RBSet<int> unsafe_lines;
+ HashSet<String> ignored_warnings;
+ HashSet<uint32_t> ignored_warning_codes;
+ HashSet<int> unsafe_lines;
#endif
GDScriptTokenizer tokenizer;
@@ -1419,7 +1421,7 @@ public:
}
#ifdef DEBUG_ENABLED
const List<GDScriptWarning> &get_warnings() const { return warnings; }
- const RBSet<int> &get_unsafe_lines() const { return unsafe_lines; }
+ const HashSet<int> &get_unsafe_lines() const { return unsafe_lines; }
int get_last_line_number() const { return current.end_line; }
#endif
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index ad818cf812..7fb715f2c8 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -32,8 +32,8 @@
#define GDSCRIPT_TOKENIZER_H
#include "core/templates/hash_map.h"
+#include "core/templates/hash_set.h"
#include "core/templates/list.h"
-#include "core/templates/rb_set.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 8f85d8159b..55f4ebb1c5 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -3450,23 +3450,26 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
}
- // Check if this function has been interrupted by `await`.
- // If that is the case we want to keep it in the debugger until it actually exits.
+ // Check if this is not the last time it was interrupted by `await` or if it's the first time executing.
+ // If that is the case then we exit the function as normal. Otherwise we postpone it until the last `await` is completed.
// This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
- if (!awaited) {
+ if (!p_state || awaited) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->exit_function();
}
- }
#endif
- // Clear the stack even if there was an `await`.
- // The stack saved in the state is a copy, so this needs to be destructed to avoid leaks.
- if (_stack_size) {
- // Free stack.
- for (int i = 0; i < _stack_size; i++) {
+ // Free stack, except reserved addresses.
+ for (int i = 3; i < _stack_size; i++) {
stack[i].~Variant();
}
+#ifdef DEBUG_ENABLED
+ }
+#endif
+
+ // Always free reserved addresses, since they are never copied.
+ for (int i = 0; i < 3; i++) {
+ stack[i].~Variant();
}
return retvalue;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index ad96e36640..1cae7bdfac 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -163,6 +163,18 @@ String GDScriptWarning::get_message() const {
#undef CHECK_SYMBOLS
}
+int GDScriptWarning::get_default_value(Code p_code) {
+ if (get_name_from_code(p_code).to_lower().begins_with("unsafe_")) {
+ return WarnLevel::IGNORE;
+ }
+ return WarnLevel::WARN;
+}
+
+PropertyInfo GDScriptWarning::get_property_info(Code p_code) {
+ // Making this a separate function in case a warning needs different PropertyInfo in the future.
+ return PropertyInfo(Variant::INT, get_settings_path_from_code(p_code), PROPERTY_HINT_ENUM, "Ignore,Warn,Error");
+}
+
String GDScriptWarning::get_name() const {
return get_name_from_code(code);
}
@@ -210,6 +222,10 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
return names[(int)p_code];
}
+String GDScriptWarning::get_settings_path_from_code(Code p_code) {
+ return "debug/gdscript/warnings/" + get_name_from_code(p_code).to_lower();
+}
+
GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) {
for (int i = 0; i < WARNING_MAX; i++) {
if (get_name_from_code((Code)i) == p_name) {
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 82efe3568f..f47f31aedf 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -33,11 +33,18 @@
#ifdef DEBUG_ENABLED
+#include "core/object/object.h"
#include "core/string/ustring.h"
#include "core/templates/vector.h"
class GDScriptWarning {
public:
+ enum WarnLevel {
+ IGNORE,
+ WARN,
+ ERROR
+ };
+
enum Code {
UNASSIGNED_VARIABLE, // Variable used but never assigned.
UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc).
@@ -81,7 +88,10 @@ public:
String get_name() const;
String get_message() const;
+ static int get_default_value(Code p_code);
+ static PropertyInfo get_property_info(Code p_code);
static String get_name_from_code(Code p_code);
+ static String get_settings_path_from_code(Code p_code);
static Code get_code_from_name(const String &p_name);
};
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index d763701911..5ad9680ea0 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -169,6 +169,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
lsp::CompletionItem item;
item.label = option.display;
item.data = request_data;
+ item.insertText = option.insert_text;
switch (option.kind) {
case ScriptLanguage::CODE_COMPLETION_KIND_ENUM:
@@ -278,12 +279,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
item.documentation = symbol->render();
}
- if ((item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function) && !item.label.ends_with("):")) {
- item.insertText = item.label + "(";
- if (symbol && symbol->children.is_empty()) {
- item.insertText += ")";
- }
- } else if (item.kind == lsp::CompletionItemKind::Event) {
+ if (item.kind == lsp::CompletionItemKind::Event) {
if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(")) {
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
item.insertText = item.label.quote(quote_style);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index d9de112bb0..8d484a43b3 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -784,7 +784,7 @@ GDScriptWorkspace::GDScriptWorkspace() {
}
GDScriptWorkspace::~GDScriptWorkspace() {
- RBSet<String> cached_parsers;
+ HashSet<String> cached_parsers;
for (const KeyValue<String, ExtendGDScriptParser *> &E : parse_results) {
cached_parsers.insert(E.key);
@@ -794,7 +794,7 @@ GDScriptWorkspace::~GDScriptWorkspace() {
cached_parsers.insert(E.key);
}
- for (RBSet<String>::Element *E = cached_parsers.front(); E; E = E->next()) {
- remove_cache_parser(E->get());
+ for (const String &E : cached_parsers) {
+ remove_cache_parser(E);
}
}
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index d4aa207972..1c9349097f 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -1004,8 +1004,8 @@ struct CompletionItem {
dict["label"] = label;
dict["kind"] = kind;
dict["data"] = data;
+ dict["insertText"] = insertText;
if (resolved) {
- dict["insertText"] = insertText;
dict["detail"] = detail;
dict["documentation"] = documentation.to_json();
dict["deprecated"] = deprecated;
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 7cedbda804..b230c6ba36 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -70,7 +70,7 @@ class EditorExportGDScript : public EditorExportPlugin {
GDCLASS(EditorExportGDScript, EditorExportPlugin);
public:
- virtual void _export_file(const String &p_path, const String &p_type, const RBSet<String> &p_features) override {
+ virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override {
int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED;
String script_key;
diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd
new file mode 100644
index 0000000000..9a7c6a8250
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd
@@ -0,0 +1,12 @@
+# https://github.com/godotengine/godot/issues/54589
+# https://github.com/godotengine/godot/issues/56265
+
+extends Resource
+
+func test():
+ print("okay")
+ await self.changed
+ await unknown(self)
+
+func unknown(arg):
+ await arg.changed
diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out
new file mode 100644
index 0000000000..2dc04a363e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+okay
diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd
new file mode 100644
index 0000000000..9f86d0531c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd
@@ -0,0 +1,2 @@
+func test():
+ const arr: Array[int] = ["Hello", "World"]
diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out
new file mode 100644
index 0000000000..26b6e13d4f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Assigned value for constant "arr" has type Array[String] which is not compatible with defined type Array[int].
diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out
index b3dc181a22..9fafcb5a64 100644
--- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out
+++ b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Expect node path as string or identifier after "$".
+Expected node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd
new file mode 100644
index 0000000000..fa0a43094e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd
@@ -0,0 +1,3 @@
+func test():
+ func standalone():
+ print("can't be accessed")
diff --git a/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out
new file mode 100644
index 0000000000..c6830c8258
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Standalone lambdas cannot be accessed. Consider assigning it to a variable.
diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
index b3dc181a22..9fafcb5a64 100644
--- a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Expect node path as string or identifier after "$".
+Expected node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
index b3dc181a22..9fafcb5a64 100644
--- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Expect node path as string or identifier after "$".
+Expected node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
index dcb4ccecb0..3062f0be70 100644
--- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Expect node path after "/".
+Expected node path as string or identifier after "/".
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd
new file mode 100644
index 0000000000..f04f4de08d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd
@@ -0,0 +1,49 @@
+extends Node
+
+func test():
+ var child = Node.new()
+ child.name = "Child"
+ add_child(child)
+ child.owner = self
+
+ var hey = Node.new()
+ hey.name = "Hey"
+ child.add_child(hey)
+ hey.owner = self
+ hey.unique_name_in_owner = true
+
+ var fake_hey = Node.new()
+ fake_hey.name = "Hey"
+ add_child(fake_hey)
+ fake_hey.owner = self
+
+ var sub_child = Node.new()
+ sub_child.name = "SubChild"
+ hey.add_child(sub_child)
+ sub_child.owner = self
+
+ var howdy = Node.new()
+ howdy.name = "Howdy"
+ sub_child.add_child(howdy)
+ howdy.owner = self
+ howdy.unique_name_in_owner = true
+
+ print(hey == $Child/Hey)
+ print(howdy == $Child/Hey/SubChild/Howdy)
+
+ print(%Hey == hey)
+ print($%Hey == hey)
+ print(%"Hey" == hey)
+ print($"%Hey" == hey)
+ print($%"Hey" == hey)
+ print(%Hey/%Howdy == howdy)
+ print($%Hey/%Howdy == howdy)
+ print($"%Hey/%Howdy" == howdy)
+ print($"%Hey"/"%Howdy" == howdy)
+ print(%"Hey"/"%Howdy" == howdy)
+ print($%"Hey"/"%Howdy" == howdy)
+ print($"%Hey"/%"Howdy" == howdy)
+ print(%"Hey"/%"Howdy" == howdy)
+ print($%"Hey"/%"Howdy" == howdy)
+ print(%"Hey/%Howdy" == howdy)
+ print($%"Hey/%Howdy" == howdy)
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out
new file mode 100644
index 0000000000..041c4439b0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out
@@ -0,0 +1,19 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd
new file mode 100644
index 0000000000..f5e26ab1ab
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd
@@ -0,0 +1,7 @@
+# https://github.com/godotengine/godot/issues/61231
+
+func test():
+ var my_lambda = func():
+ print("hello")
+ if 0 == 0:
+ my_lambda.call()
diff --git a/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out
new file mode 100644
index 0000000000..58774d2d3f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+hello
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd
new file mode 100644
index 0000000000..2140b6923e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd
@@ -0,0 +1,7 @@
+# https://github.com/godotengine/godot/issues/56751
+
+func test():
+ var x = "local"
+ var lambda = func(param = x):
+ print(param)
+ lambda.call()
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out
new file mode 100644
index 0000000000..ce3241b94d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+local
diff --git a/modules/gdscript/tests/scripts/parser/features/match_bind_unused.gd b/modules/gdscript/tests/scripts/parser/features/match_bind_unused.gd
new file mode 100644
index 0000000000..707e4532cc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_bind_unused.gd
@@ -0,0 +1,13 @@
+# https://github.com/godotengine/godot/pull/61666
+
+func test():
+ var dict := {"key": "value"}
+ match dict:
+ {"key": var value}:
+ print(value) # used, no warning
+ match dict:
+ {"key": var value}:
+ pass # unused, warning
+ match dict:
+ {"key": var _value}:
+ pass # unused, suppressed warning from underscore
diff --git a/modules/gdscript/tests/scripts/parser/features/match_bind_unused.out b/modules/gdscript/tests/scripts/parser/features/match_bind_unused.out
new file mode 100644
index 0000000000..057c1b11e5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_bind_unused.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+>> WARNING
+>> Line: 9
+>> UNUSED_VARIABLE
+>> The local variable 'value' is declared but never used in the block. If this is intended, prefix it with an underscore: '_value'
+value
diff --git a/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd b/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd
new file mode 100644
index 0000000000..377dd25e9e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd
@@ -0,0 +1,43 @@
+func foo(x):
+ match x:
+ {"key1": "value1", "key2": "value2"}:
+ print('{"key1": "value1", "key2": "value2"}')
+ {"key1": "value1", "key2"}:
+ print('{"key1": "value1", "key2"}')
+ {"key1", "key2": "value2"}:
+ print('{"key1", "key2": "value2"}')
+ {"key1", "key2"}:
+ print('{"key1", "key2"}')
+ {"key1": "value1"}:
+ print('{"key1": "value1"}')
+ {"key1"}:
+ print('{"key1"}')
+ _:
+ print("wildcard")
+
+func bar(x):
+ match x:
+ {0}:
+ print("0")
+ {1}:
+ print("1")
+ {2}:
+ print("2")
+ _:
+ print("wildcard")
+
+func test():
+ foo({"key1": "value1", "key2": "value2"})
+ foo({"key1": "value1", "key2": ""})
+ foo({"key1": "", "key2": "value2"})
+ foo({"key1": "", "key2": ""})
+ foo({"key1": "value1"})
+ foo({"key1": ""})
+ foo({"key1": "value1", "key2": "value2", "key3": "value3"})
+ foo({"key1": "value1", "key3": ""})
+ foo({"key2": "value2"})
+ foo({"key3": ""})
+ bar({0: "0"})
+ bar({1: "1"})
+ bar({2: "2"})
+ bar({3: "3"})
diff --git a/modules/gdscript/tests/scripts/parser/features/match_dictionary.out b/modules/gdscript/tests/scripts/parser/features/match_dictionary.out
new file mode 100644
index 0000000000..4dee886927
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_dictionary.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+{"key1": "value1", "key2": "value2"}
+{"key1": "value1", "key2"}
+{"key1", "key2": "value2"}
+{"key1", "key2"}
+{"key1": "value1"}
+{"key1"}
+wildcard
+wildcard
+wildcard
+wildcard
+0
+1
+2
+wildcard
diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd
new file mode 100644
index 0000000000..dbe223f5f5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd
@@ -0,0 +1,26 @@
+func foo(x):
+ match x:
+ 1, [2]:
+ print('1, [2]')
+ _:
+ print('wildcard')
+
+func bar(x):
+ match x:
+ [1], [2], [3]:
+ print('[1], [2], [3]')
+ [4]:
+ print('[4]')
+ _:
+ print('wildcard')
+
+func test():
+ foo(1)
+ foo([2])
+ foo(2)
+ bar([1])
+ bar([2])
+ bar([3])
+ bar([4])
+ bar([5])
+
diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.out b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.out
new file mode 100644
index 0000000000..a12b934d67
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+1, [2]
+1, [2]
+wildcard
+[1], [2], [3]
+[1], [2], [3]
+[1], [2], [3]
+[4]
+wildcard
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd
new file mode 100644
index 0000000000..d00d483a73
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd
@@ -0,0 +1,16 @@
+func test():
+ var foo := "bar"
+ match foo:
+ "baz":
+ return
+ _:
+ pass
+ match foo:
+ "baz":
+ return
+ match foo:
+ "bar":
+ pass
+ _:
+ return
+ print("reached")
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out
new file mode 100644
index 0000000000..47db6b631b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+reached
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index d8f60d5e9b..cbcd7b2955 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -134,6 +134,34 @@ static void test_parser(const String &p_code, const String &p_script_path, const
#endif
}
+static void recursively_disassemble_functions(const Ref<GDScript> script, const Vector<String> &p_lines) {
+ for (const KeyValue<StringName, GDScriptFunction *> &E : script->get_member_functions()) {
+ const GDScriptFunction *func = E.value;
+
+ String signature = "Disassembling " + func->get_name().operator String() + "(";
+ for (int i = 0; i < func->get_argument_count(); i++) {
+ if (i > 0) {
+ signature += ", ";
+ }
+ signature += func->get_argument_name(i);
+ }
+ print_line(signature + ")");
+#ifdef TOOLS_ENABLED
+ func->disassemble(p_lines);
+#endif
+ print_line("");
+ print_line("");
+ }
+
+ for (const KeyValue<StringName, Ref<GDScript>> &F : script->get_subclasses()) {
+ const Ref<GDScript> inner_script = F.value;
+ print_line("");
+ print_line(vformat("Inner Class: %s", inner_script->get_script_class_name()));
+ print_line("");
+ recursively_disassemble_functions(inner_script, p_lines);
+ }
+}
+
static void test_compiler(const String &p_code, const String &p_script_path, const Vector<String> &p_lines) {
GDScriptParser parser;
Error err = parser.parse(p_code, p_script_path, false);
@@ -172,23 +200,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
return;
}
- for (const KeyValue<StringName, GDScriptFunction *> &E : script->get_member_functions()) {
- const GDScriptFunction *func = E.value;
-
- String signature = "Disassembling " + func->get_name().operator String() + "(";
- for (int i = 0; i < func->get_argument_count(); i++) {
- if (i > 0) {
- signature += ", ";
- }
- signature += func->get_argument_name(i);
- }
- print_line(signature + ")");
-#ifdef TOOLS_ENABLED
- func->disassemble(p_lines);
-#endif
- print_line("");
- print_line("");
- }
+ recursively_disassemble_functions(script, p_lines);
}
void test(TestType p_type) {
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index 03b4380ff4..3c28546ad7 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -7,65 +7,52 @@
<tutorials>
</tutorials>
<methods>
- <method name="export_post">
- <return type="int" enum="Error" />
- <argument index="0" name="document" type="GLTFDocument" />
+ <method name="_export_node" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
+ <argument index="1" name="gltf_node" type="GLTFNode" />
+ <argument index="2" name="json" type="Dictionary" />
+ <argument index="3" name="node" type="Node" />
<description>
</description>
</method>
- <method name="export_preflight">
- <return type="int" enum="Error" />
- <argument index="0" name="document" type="GLTFDocument" />
- <argument index="1" name="node" type="Node" />
+ <method name="_export_post" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
- <method name="get_export_setting" qualifiers="const">
- <return type="Variant" />
- <argument index="0" name="key" type="StringName" />
+ <method name="_export_preflight" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="root" type="Node" />
<description>
</description>
</method>
- <method name="get_export_setting_keys" qualifiers="const">
- <return type="Array" />
+ <method name="_import_node" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
+ <argument index="1" name="gltf_node" type="GLTFNode" />
+ <argument index="2" name="json" type="Dictionary" />
+ <argument index="3" name="node" type="Node" />
<description>
</description>
</method>
- <method name="get_import_setting" qualifiers="const">
- <return type="Variant" />
- <argument index="0" name="key" type="StringName" />
+ <method name="_import_post" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
+ <argument index="1" name="root" type="Node" />
<description>
</description>
</method>
- <method name="get_import_setting_keys" qualifiers="const">
- <return type="Array" />
+ <method name="_import_post_parse" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
- <method name="import_post">
- <return type="int" enum="Error" />
- <argument index="0" name="document" type="GLTFDocument" />
- <argument index="1" name="node" type="Node" />
- <description>
- </description>
- </method>
- <method name="import_preflight">
- <return type="int" enum="Error" />
- <argument index="0" name="document" type="GLTFDocument" />
- <description>
- </description>
- </method>
- <method name="set_export_setting">
- <return type="void" />
- <argument index="0" name="key" type="StringName" />
- <argument index="1" name="value" type="Variant" />
- <description>
- </description>
- </method>
- <method name="set_import_setting">
- <return type="void" />
- <argument index="0" name="key" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <method name="_import_preflight" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index a59fa900bc..44a1723563 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -192,6 +192,8 @@
</method>
</methods>
<members>
+ <member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default="&quot;&quot;">
+ </member>
<member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]">
</member>
<member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()">
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 63f446561a..676862ea5a 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -310,7 +310,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
Error err = OS::get_singleton()->execute(path, args, &pipe);
if (err != OK) {
if (r_err) {
- *r_err = TTR("Can't excecute Blender binary.");
+ *r_err = TTR("Can't execute Blender binary.");
}
return false;
}
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index d5b247fc6e..3fadec5167 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -35,7 +35,6 @@
#include "../gltf_document.h"
#include "../gltf_state.h"
-#include "scene/main/node.h"
#include "scene/resources/animation.h"
uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const {
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h
index edca038532..b17a1e4eaa 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor/editor_scene_importer_gltf.h
@@ -33,6 +33,9 @@
#ifdef TOOLS_ENABLED
+#include "../gltf_document_extension.h"
+#include "../gltf_state.h"
+
#include "editor/import/resource_importer_scene.h"
class Animation;
diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h
index 6bf1bf543a..f412dc2c7f 100644
--- a/modules/gltf/gltf_accessor.h
+++ b/modules/gltf/gltf_accessor.h
@@ -34,7 +34,6 @@
#include "core/io/resource.h"
#include "gltf_document.h"
-#include "gltf_document_extension.h"
struct GLTFAccessor : public Resource {
GDCLASS(GLTFAccessor, Resource);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index f440a29f28..2017355717 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -128,10 +128,10 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
state->buffers.push_back(Vector<uint8_t>());
}
- /* STEP 1 CONVERT MESH INSTANCES */
+ /* STEP CONVERT MESH INSTANCES */
_convert_mesh_instances(state);
- /* STEP 2 SERIALIZE CAMERAS */
+ /* STEP SERIALIZE CAMERAS */
Error err = _serialize_cameras(state);
if (err != OK) {
return Error::FAILED;
@@ -143,37 +143,37 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return Error::FAILED;
}
- /* STEP 5 SERIALIZE MESHES (we have enough info now) */
+ /* STEP SERIALIZE MESHES (we have enough info now) */
err = _serialize_meshes(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 6 SERIALIZE TEXTURES */
+ /* STEP SERIALIZE TEXTURES */
err = _serialize_materials(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 7 SERIALIZE ANIMATIONS */
+ /* STEP SERIALIZE ANIMATIONS */
err = _serialize_animations(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 8 SERIALIZE ACCESSORS */
+ /* STEP SERIALIZE ACCESSORS */
err = _encode_accessors(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 9 SERIALIZE IMAGES */
+ /* STEP SERIALIZE IMAGES */
err = _serialize_images(state, p_path);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 10 SERIALIZE TEXTURES */
+ /* STEP SERIALIZE TEXTURES */
err = _serialize_textures(state);
if (err != OK) {
return Error::FAILED;
@@ -183,42 +183,49 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
state->buffer_views.write[i]->buffer = 0;
}
- /* STEP 11 SERIALIZE BUFFER VIEWS */
+ /* STEP SERIALIZE BUFFER VIEWS */
err = _encode_buffer_views(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 12 SERIALIZE NODES */
+ /* STEP SERIALIZE NODES */
err = _serialize_nodes(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 13 SERIALIZE SCENE */
+ /* STEP SERIALIZE SCENE */
err = _serialize_scenes(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 14 SERIALIZE SCENE */
+ /* STEP SERIALIZE SCENE */
err = _serialize_lights(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 15 SERIALIZE EXTENSIONS */
+ /* STEP SERIALIZE EXTENSIONS */
err = _serialize_extensions(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 16 SERIALIZE VERSION */
+ /* STEP SERIALIZE VERSION */
err = _serialize_version(state);
if (err != OK) {
return Error::FAILED;
}
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->export_post(state);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+
return OK;
}
@@ -442,6 +449,15 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
}
node["children"] = children;
}
+
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ ERR_CONTINUE(!state->scene_nodes.find(i));
+ Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]);
+ ERR_CONTINUE(err != OK);
+ }
+
nodes.push_back(node);
}
state->json["nodes"] = nodes;
@@ -5658,7 +5674,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
if (!current_node) {
current_node = _generate_spatial(state, node_index);
}
- scene_parent->add_child(current_node);
+ scene_parent->add_child(current_node, true);
if (current_node != scene_root) {
current_node->set_owner(scene_root);
}
@@ -6642,8 +6658,8 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess>
for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
ERR_CONTINUE(ext.is_null());
- err = ext->import_preflight(this);
- ERR_FAIL_COND_V(err != OK, FAILED);
+ err = ext->import_preflight(state);
+ ERR_FAIL_COND_V(err != OK, err);
}
err = _parse_gltf_state(state, p_path, p_bake_fps);
ERR_FAIL_COND_V(err != OK, err);
@@ -6870,12 +6886,10 @@ PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) {
Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) {
ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
-
Error err = _serialize(state, p_path);
if (err != OK) {
return err;
}
-
err = _serialize_file(state, p_path);
if (err != OK) {
return Error::FAILED;
@@ -6886,6 +6900,7 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_pa
Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) {
ERR_FAIL_NULL_V(state, nullptr);
ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr);
+ Error err = OK;
GLTFNodeIndex gltf_root = state->root_nodes.write[0];
Node *gltf_root_node = state->get_scene_node(gltf_root);
Node *root = gltf_root_node->get_parent();
@@ -6899,12 +6914,26 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) {
_import_animation(state, ap, i, p_bake_fps);
}
}
-
+ for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) {
+ ERR_CONTINUE(!E.value);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ ERR_CONTINUE(!state->json.has("nodes"));
+ Array nodes = state->json["nodes"];
+ ERR_CONTINUE(E.key >= nodes.size());
+ ERR_CONTINUE(E.key < 0);
+ Dictionary node_json = nodes[E.key];
+ Ref<GLTFNode> gltf_node = state->nodes[E.key];
+ err = ext->import_node(state, gltf_node, node_json, E.value);
+ ERR_CONTINUE(err != OK);
+ }
+ }
for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
ERR_CONTINUE(ext.is_null());
- Error err = ext->import_post(this, root);
- ERR_FAIL_COND_V(err != OK, nullptr);
+ err = ext->import_post(state, root);
+ ERR_CONTINUE(err != OK);
}
ERR_FAIL_NULL_V(root, nullptr);
return root;
@@ -6919,13 +6948,23 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32
if (!state->buffers.size()) {
state->buffers.push_back(Vector<uint8_t>());
}
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ }
- /* STEP 1 CONVERT MESH INSTANCES */
- _convert_mesh_instances(state);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Error err = ext->export_preflight(p_node);
+ ERR_FAIL_COND_V(err != OK, FAILED);
+ }
+ _convert_scene_node(state, p_node, -1, -1);
+ if (!state->buffers.size()) {
+ state->buffers.push_back(Vector<uint8_t>());
+ }
- /* STEP 2 CREATE SKINS */
- Error err = _serialize_skins(state);
- return err;
+ return OK;
}
Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) {
@@ -6938,8 +6977,15 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa
Ref<FileAccessMemory> file_access;
file_access.instantiate();
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
- err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps);
- ERR_FAIL_COND_V(err != OK, FAILED);
+ state->base_path = p_base_path.get_base_dir();
+ err = _parse(state, state->base_path, file_access, p_bake_fps);
+ ERR_FAIL_COND_V(err != OK, err);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->import_post_parse(state);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
return OK;
}
@@ -7030,6 +7076,7 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear
for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) {
_generate_scene_node(state, root, root, state->root_nodes[root_i]);
}
+
return OK;
}
@@ -7049,9 +7096,16 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
if (base_path.is_empty()) {
base_path = p_path.get_base_dir();
}
+ r_state->base_path = base_path;
err = _parse(r_state, base_path, f, p_bake_fps);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- return err;
+ ERR_FAIL_COND_V(err != OK, err);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->import_post_parse(r_state);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+ return OK;
}
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 9db824a0d4..2f61210ff9 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -33,19 +33,12 @@
#include "gltf_animation.h"
-#include "core/error/error_list.h"
-#include "core/variant/dictionary.h"
-#include "core/variant/variant.h"
-#include "gltf_document_extension_convert_importer_mesh.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/material.h"
-#include "scene/resources/texture.h"
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
@@ -135,12 +128,12 @@ private:
}
template <class T>
- static Array to_array(const RBSet<T> &p_inp) {
+ static Array to_array(const HashSet<T> &p_inp) {
Array ret;
- typename RBSet<T>::Element *elem = p_inp.front();
+ typename HashSet<T>::Iterator elem = p_inp.begin();
while (elem) {
- ret.push_back(elem->get());
- elem = elem->next();
+ ret.push_back(*elem);
+ ++elem;
}
return ret;
}
@@ -154,7 +147,7 @@ private:
}
template <class T>
- static void set_from_array(RBSet<T> &r_out, const Array &p_inp) {
+ static void set_from_array(HashSet<T> &r_out, const Array &p_inp) {
r_out.clear();
for (int i = 0; i < p_inp.size(); i++) {
r_out.insert(p_inp[i]);
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
index 192a1d347c..d0bd7651e0 100644
--- a/modules/gltf/gltf_document_extension.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -30,59 +30,79 @@
#include "gltf_document_extension.h"
-#include "gltf_document.h"
-
void GLTFDocumentExtension::_bind_methods() {
- // Import
- ClassDB::bind_method(D_METHOD("get_import_setting_keys"),
- &GLTFDocumentExtension::get_import_setting_keys);
- ClassDB::bind_method(D_METHOD("import_preflight", "document"),
- &GLTFDocumentExtension::import_preflight);
- ClassDB::bind_method(D_METHOD("get_import_setting", "key"),
- &GLTFDocumentExtension::get_import_setting);
- ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"),
- &GLTFDocumentExtension::set_import_setting);
- ClassDB::bind_method(D_METHOD("import_post", "document", "node"),
- &GLTFDocumentExtension::import_post);
- // Export
- ClassDB::bind_method(D_METHOD("get_export_setting_keys"),
- &GLTFDocumentExtension::get_export_setting_keys);
- ClassDB::bind_method(D_METHOD("get_export_setting", "key"),
- &GLTFDocumentExtension::get_export_setting);
- ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"),
- &GLTFDocumentExtension::set_export_setting);
- ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"),
- &GLTFDocumentExtension::export_preflight);
- ClassDB::bind_method(D_METHOD("export_post", "document"),
- &GLTFDocumentExtension::export_post);
+ GDVIRTUAL_BIND(_import_preflight, "state");
+ GDVIRTUAL_BIND(_import_post_parse, "state");
+ GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
+ GDVIRTUAL_BIND(_import_post, "state", "root");
+ GDVIRTUAL_BIND(_export_preflight, "root");
+ GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node");
+ GDVIRTUAL_BIND(_export_post, "state");
}
-Array GLTFDocumentExtension::get_import_setting_keys() const {
- return import_settings.keys();
+Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
+ ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_import_post, p_state, p_root, err)) {
+ return Error(err);
+ }
+ return OK;
}
-Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const {
- if (!import_settings.has(p_key)) {
- return Variant();
+Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_import_preflight, p_state, err)) {
+ return Error(err);
}
- return import_settings[p_key];
+ return OK;
}
-void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) {
- import_settings[p_key] = p_var;
+Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_import_post_parse, p_state, err)) {
+ return Error(err);
+ }
+ return OK;
}
-Array GLTFDocumentExtension::get_export_setting_keys() const {
- return import_settings.keys();
+Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_export_post, p_state, err)) {
+ return Error(err);
+ }
+ return OK;
+}
+Error GLTFDocumentExtension::export_preflight(Node *p_root) {
+ ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_export_preflight, p_root, err)) {
+ return Error(err);
+ }
+ return OK;
}
-Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const {
- if (!import_settings.has(p_key)) {
- return Variant();
+Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err)) {
+ return Error(err);
}
- return import_settings[p_key];
+ return OK;
}
-void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) {
- import_settings[p_key] = p_var;
+Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
+ int err = OK;
+ if (GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err)) {
+ return Error(err);
+ }
+ return OK;
}
diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h
index f7a3531282..556f79e887 100644
--- a/modules/gltf/gltf_document_extension.h
+++ b/modules/gltf/gltf_document_extension.h
@@ -31,33 +31,31 @@
#ifndef GLTF_DOCUMENT_EXTENSION_H
#define GLTF_DOCUMENT_EXTENSION_H
-#include "core/io/resource.h"
-#include "core/variant/dictionary.h"
-#include "core/variant/typed_array.h"
-#include "core/variant/variant.h"
-class GLTFDocument;
+#include "gltf_accessor.h"
+#include "gltf_node.h"
+#include "gltf_state.h"
+
class GLTFDocumentExtension : public Resource {
GDCLASS(GLTFDocumentExtension, Resource);
- Dictionary import_settings;
- Dictionary export_settings;
-
protected:
static void _bind_methods();
public:
- virtual Array get_import_setting_keys() const;
- virtual Variant get_import_setting(const StringName &p_key) const;
- virtual void set_import_setting(const StringName &p_key, Variant p_var);
- virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; }
- virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
-
-public:
- virtual Array get_export_setting_keys() const;
- virtual Variant get_export_setting(const StringName &p_key) const;
- virtual void set_export_setting(const StringName &p_key, Variant p_var);
- virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
- virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; }
+ virtual Error import_preflight(Ref<GLTFState> p_state);
+ virtual Error import_post_parse(Ref<GLTFState> p_state);
+ virtual Error export_post(Ref<GLTFState> p_state);
+ virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
+ virtual Error export_preflight(Node *p_state);
+ virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
+ virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
+ GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>);
+ GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>);
+ GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
+ GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *);
+ GDVIRTUAL1R(int, _export_preflight, Node *);
+ GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
+ GDVIRTUAL1R(int, _export_post, Ref<GLTFState>);
};
#endif // GLTF_DOCUMENT_EXTENSION_H
diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
index 47a3e5598f..1620900a04 100644
--- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
@@ -29,41 +29,40 @@
/*************************************************************************/
#include "gltf_document_extension_convert_importer_mesh.h"
+
+#include "gltf_state.h"
+
#include "core/error/error_macros.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/importer_mesh.h"
-#include <cstddef>
-
void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
}
-Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) {
- ERR_FAIL_NULL_V(p_document, ERR_INVALID_PARAMETER);
- ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
+Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_state, Node *p_root) {
+ ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
List<Node *> queue;
- queue.push_back(p_node);
+ queue.push_back(p_root);
List<Node *> delete_queue;
while (!queue.is_empty()) {
List<Node *>::Element *E = queue.front();
Node *node = E->get();
- {
- ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
- if (mesh_3d) {
- MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
- Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
- if (mesh.is_valid()) {
- Ref<ArrayMesh> array_mesh = mesh->get_mesh();
- mesh_instance_node_3d->set_name(node->get_name());
- mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
- mesh_instance_node_3d->set_mesh(array_mesh);
- mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
- mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
- node->replace_by(mesh_instance_node_3d);
- delete_queue.push_back(node);
- } else {
- memdelete(mesh_instance_node_3d);
- }
+ ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
+ if (mesh_3d) {
+ MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
+ Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
+ if (mesh.is_valid()) {
+ Ref<ArrayMesh> array_mesh = mesh->get_mesh();
+ mesh_instance_node_3d->set_name(node->get_name());
+ mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
+ mesh_instance_node_3d->set_mesh(array_mesh);
+ mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
+ mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
+ node->replace_by(mesh_instance_node_3d);
+ delete_queue.push_back(node);
+ } else {
+ memdelete(mesh_instance_node_3d);
}
}
int child_count = node->get_child_count();
diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
index 2d51143140..4c9e42a00f 100644
--- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
@@ -31,14 +31,10 @@
#ifndef GLTF_EXTENSION_EDITOR_H
#define GLTF_EXTENSION_EDITOR_H
-#include "core/io/resource.h"
-#include "core/variant/dictionary.h"
-
-#include "gltf_document.h"
#include "gltf_document_extension.h"
+
#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
-#include "scene/main/node.h"
#include "scene/resources/importer_mesh.h"
class GLTFDocumentExtension;
@@ -50,6 +46,6 @@ protected:
static void _bind_methods();
public:
- Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override;
+ Error import_post(Ref<GLTFState> p_state, Node *p_root) override;
};
#endif // GLTF_EXTENSION_EDITOR_H
diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h
index 4dcee41465..92ee6e6234 100644
--- a/modules/gltf/gltf_skeleton.h
+++ b/modules/gltf/gltf_skeleton.h
@@ -50,7 +50,7 @@ private:
Skeleton3D *godot_skeleton = nullptr;
// Set of unique bone names for the skeleton
- RBSet<String> unique_names;
+ HashSet<String> unique_names;
HashMap<int32_t, GLTFNodeIndex> godot_bone_node;
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index e959a640b4..989fa476c2 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -57,6 +57,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_materials", "materials"), &GLTFState::set_materials);
ClassDB::bind_method(D_METHOD("get_scene_name"), &GLTFState::get_scene_name);
ClassDB::bind_method(D_METHOD("set_scene_name", "scene_name"), &GLTFState::set_scene_name);
+ ClassDB::bind_method(D_METHOD("get_base_path"), &GLTFState::get_base_path);
+ ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &GLTFState::set_base_path);
ClassDB::bind_method(D_METHOD("get_root_nodes"), &GLTFState::get_root_nodes);
ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes);
ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures);
@@ -93,6 +95,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "meshes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_meshes", "get_meshes"); // Vector<Ref<GLTFMesh>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "materials", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_materials", "get_materials"); // Vector<Ref<Material>
ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_name"), "set_scene_name", "get_scene_name"); // String
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_path"), "set_base_path", "get_base_path"); // String
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture>
@@ -313,3 +316,11 @@ void GLTFState::set_discard_meshes_and_materials(bool p_discard_meshes_and_mater
bool GLTFState::get_discard_meshes_and_materials() {
return discard_meshes_and_materials;
}
+
+String GLTFState::get_base_path() {
+ return base_path;
+}
+
+void GLTFState::set_base_path(String p_base_path) {
+ base_path = p_base_path;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index f695b20b49..2fdef19038 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -44,10 +44,7 @@
#include "gltf_skin.h"
#include "gltf_texture.h"
-#include "core/io/resource.h"
-#include "core/templates/pair.h"
#include "core/templates/rb_map.h"
-#include "core/templates/vector.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/texture.h"
@@ -56,6 +53,7 @@ class GLTFState : public Resource {
friend class GLTFDocument;
String filename;
+ String base_path;
Dictionary json;
int major_version = 0;
int minor_version = 0;
@@ -83,8 +81,8 @@ class GLTFState : public Resource {
Vector<Ref<GLTFSkin>> skins;
Vector<Ref<GLTFCamera>> cameras;
Vector<Ref<GLTFLight>> lights;
- RBSet<String> unique_names;
- RBSet<String> unique_animation_names;
+ HashSet<String> unique_names;
+ HashSet<String> unique_animation_names;
Vector<Ref<GLTFSkeleton>> skeletons;
HashMap<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node;
@@ -137,6 +135,9 @@ public:
String get_scene_name();
void set_scene_name(String p_scene_name);
+ String get_base_path();
+ void set_base_path(String p_base_path);
+
Array get_root_nodes();
void set_root_nodes(Array p_root_nodes);
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 4902adb827..cfff5c61de 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -1221,7 +1221,7 @@ GridMapEditor::GridMapEditor() {
search_box = memnew(LineEdit);
search_box->set_h_size_flags(SIZE_EXPAND_FILL);
- search_box->set_placeholder(TTR("Filter meshes"));
+ search_box->set_placeholder(TTR("Filter Meshes"));
hb->add_child(search_box);
search_box->connect("text_changed", callable_mp(this, &GridMapEditor::_text_changed));
search_box->connect("gui_input", callable_mp(this, &GridMapEditor::_sbox_input));
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 9da137f9d5..0e34b5907e 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -226,8 +226,8 @@ bool GridMap::is_baking_navigation() {
return bake_navigation;
}
-void GridMap::set_navigation_layers(uint32_t p_layers) {
- navigation_layers = p_layers;
+void GridMap::set_navigation_layers(uint32_t p_navigation_layers) {
+ navigation_layers = p_navigation_layers;
_recreate_octant_data();
}
@@ -433,6 +433,18 @@ void GridMap::_octant_transform(const OctantKey &p_key) {
RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
}
+ // update transform for NavigationServer regions and navigation debugmesh instances
+ for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ if (bake_navigation) {
+ if (E.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->region_set_transform(E.value.region, get_global_transform() * E.value.xform);
+ }
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(E.value.navmesh_debug_instance, get_global_transform() * E.value.xform);
+ }
+ }
+ }
+
for (int i = 0; i < g.multimesh_instances.size(); i++) {
RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
@@ -456,6 +468,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//erase navigation
for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
NavigationServer3D::get_singleton()->free(E.value.region);
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ }
}
g.navmesh_ids.clear();
@@ -483,15 +498,15 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
HashMap<int, List<Pair<Transform3D, IndexKey>>> multimesh_items;
- for (RBSet<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {
- ERR_CONTINUE(!cell_map.has(E->get()));
- const Cell &c = cell_map[E->get()];
+ for (const IndexKey &E : g.cells) {
+ ERR_CONTINUE(!cell_map.has(E));
+ const Cell &c = cell_map[E];
if (!mesh_library.is_valid() || !mesh_library->has_item(c.item)) {
continue;
}
- Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
+ Vector3 cellpos = Vector3(E.x, E.y, E.z);
Vector3 ofs = _get_offset();
Transform3D xform;
@@ -507,7 +522,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
Pair<Transform3D, IndexKey> p;
p.first = xform * mesh_library->get_item_mesh_transform(c.item);
- p.second = E->get();
+ p.second = E;
multimesh_items[c.item].push_back(p);
}
}
@@ -533,14 +548,29 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
if (bake_navigation) {
RID region = NavigationServer3D::get_singleton()->region_create();
- NavigationServer3D::get_singleton()->region_set_layers(region, navigation_layers);
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh);
- NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * mesh_library->get_item_navmesh_transform(c.item));
+ NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
nm.region = region;
+
+ // add navigation debugmesh visual instances if debug is enabled
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_navigation_hint()) {
+ if (!nm.navmesh_debug_instance.is_valid()) {
+ RID navmesh_debug_rid = navmesh->get_debug_mesh()->get_rid();
+ nm.navmesh_debug_instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(nm.navmesh_debug_instance, navmesh_debug_rid);
+ RS::get_singleton()->mesh_surface_set_material(navmesh_debug_rid, 0, st->get_debug_navigation_material()->get_rid());
+ }
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(nm.navmesh_debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_transform(nm.navmesh_debug_instance, get_global_transform() * nm.xform);
+ }
+ }
}
- g.navmesh_ids[E->get()] = nm;
+ g.navmesh_ids[E] = nm;
}
}
@@ -629,7 +659,7 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F.key].item);
if (nm.is_valid()) {
RID region = NavigationServer3D::get_singleton()->region_create();
- NavigationServer3D::get_singleton()->region_set_layers(region, navigation_layers);
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, nm);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform);
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
@@ -660,6 +690,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
NavigationServer3D::get_singleton()->free(F.value.region);
F.value.region = RID();
}
+ if (F.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(F.value.navmesh_debug_instance);
+ F.value.navmesh_debug_instance = RID();
+ }
}
}
@@ -678,7 +712,12 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
// Erase navigation
for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
- NavigationServer3D::get_singleton()->free(E.value.region);
+ if (E.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->free(E.value.region);
+ }
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ }
}
g.navmesh_ids.clear();
@@ -890,7 +929,7 @@ void GridMap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material");
ADD_GROUP("Cell", "cell_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size", PROPERTY_HINT_NONE, "suffix:m"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_center_x"), "set_center_x", "get_center_x");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_center_y"), "set_center_y", "get_center_y");
@@ -970,7 +1009,7 @@ Array GridMap::get_meshes() const {
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
- meshes.push_back(xform);
+ meshes.push_back(xform * mesh_library->get_item_mesh_transform(id));
meshes.push_back(mesh);
}
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 88e16bce82..08ed4d3d12 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -98,6 +98,7 @@ class GridMap : public Node3D {
struct NavMesh {
RID region;
Transform3D xform;
+ RID navmesh_debug_instance;
};
struct MultimeshInstance {
@@ -113,7 +114,7 @@ class GridMap : public Node3D {
};
Vector<MultimeshInstance> multimesh_instances;
- RBSet<IndexKey> cells;
+ HashSet<IndexKey> cells;
RID collision_debug;
RID collision_debug_instance;
@@ -237,7 +238,7 @@ public:
void set_bake_navigation(bool p_bake_navigation);
bool is_baking_navigation();
- void set_navigation_layers(uint32_t p_layers);
+ void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers();
void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 1818048877..92590fbcf6 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -298,6 +298,10 @@ StreamPeerMbedTLS::Status StreamPeerMbedTLS::get_status() const {
return status;
}
+Ref<StreamPeer> StreamPeerMbedTLS::get_stream() const {
+ return base;
+}
+
StreamPeerSSL *StreamPeerMbedTLS::_create_func() {
return memnew(StreamPeerMbedTLS);
}
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index 98b91e65ab..7660410e04 100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -57,6 +57,7 @@ public:
virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>());
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>());
virtual Status get_status() const;
+ virtual Ref<StreamPeer> get_stream() const;
virtual void disconnect_from_stream();
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index d0140f117c..622838b308 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -875,7 +875,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Script::instances are deleted during managed object disposal, which happens on domain finalize.
// Only placeholders are kept. Therefore we need to keep a copy before that happens.
- for (Object *&obj : script->instances) {
+ for (Object *obj : script->instances) {
script->pending_reload_instances.insert(obj->get_instance_id());
RefCounted *rc = Object::cast_to<RefCounted>(obj);
@@ -885,7 +885,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#ifdef TOOLS_ENABLED
- for (PlaceHolderScriptInstance *&script_instance : script->placeholders) {
+ for (PlaceHolderScriptInstance *script_instance : script->placeholders) {
Object *obj = script_instance->get_owner();
script->pending_reload_instances.insert(obj->get_instance_id());
@@ -899,7 +899,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Save state and remove script from instances
RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
- for (Object *&obj : script->instances) {
+ for (Object *obj : script->instances) {
ERR_CONTINUE(!obj->get_script_instance());
CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance());
@@ -922,8 +922,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// After the state of all instances is saved, clear scripts and script instances
for (Ref<CSharpScript> &script : scripts) {
- while (script->instances.front()) {
- Object *obj = script->instances.front()->get();
+ while (script->instances.begin()) {
+ Object *obj = *script->instances.begin();
obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
@@ -2315,9 +2315,9 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// CSharpInstance must not be created unless it's going to be added to the list for sure
- RBSet<Object *>::Element *match = script->instances.find(owner);
+ HashSet<Object *>::Iterator match = script->instances.find(owner);
CRASH_COND(!match);
- script->instances.erase(match);
+ script->instances.remove(match);
#else
script->instances.erase(owner);
#endif
@@ -2572,7 +2572,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
_update_exports_values(values, propnames);
if (changed) {
- for (PlaceHolderScriptInstance *&script_instance : placeholders) {
+ for (PlaceHolderScriptInstance *script_instance : placeholders) {
script_instance->update(propnames, values);
}
} else {
@@ -2807,7 +2807,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
GD_MONO_ASSERT_THREAD_ATTACHED;
if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
- r_hint = PROPERTY_HINT_ENUM;
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
+ r_hint = GDMonoUtils::Marshal::type_has_flags_attribute(reftype) ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
@@ -2844,7 +2845,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value.");
- if (val != (unsigned int)i) {
+ unsigned int expected_val = r_hint == PROPERTY_HINT_FLAGS ? 1 << i : i;
+ if (val != expected_val) {
uses_default_values = false;
}
@@ -3574,7 +3576,7 @@ CSharpScript::~CSharpScript() {
#endif
}
-void CSharpScript::get_members(RBSet<StringName> *p_members) {
+void CSharpScript::get_members(HashSet<StringName> *p_members) {
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
if (p_members) {
for (const StringName &member_name : exported_members_names) {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 6e600bb47a..69bd8703aa 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -110,7 +110,7 @@ private:
Ref<CSharpScript> base_cache; // TODO what's this for?
- RBSet<Object *> instances;
+ HashSet<Object *> instances;
#ifdef GD_MONO_HOT_RELOAD
struct StateBackup {
@@ -121,7 +121,7 @@ private:
List<Pair<StringName, Array>> event_signals;
};
- RBSet<ObjectID> pending_reload_instances;
+ HashSet<ObjectID> pending_reload_instances;
RBMap<ObjectID, StateBackup> pending_reload_state;
StringName tied_class_name_for_reload;
StringName tied_class_namespace_for_reload;
@@ -141,7 +141,7 @@ private:
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
- RBSet<PlaceHolderScriptInstance *> placeholders;
+ HashSet<PlaceHolderScriptInstance *> placeholders;
bool source_changed_cache = false;
bool placeholder_fallback_enabled = false;
bool exports_invalidated = true;
@@ -151,7 +151,7 @@ private:
#endif
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
- RBSet<StringName> exported_members_names;
+ HashSet<StringName> exported_members_names;
#endif
HashMap<StringName, PropertyInfo> member_info;
@@ -218,7 +218,7 @@ public:
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
- void get_members(RBSet<StringName> *p_members) override;
+ void get_members(HashSet<StringName> *p_members) override;
bool is_tool() const override { return tool; }
bool is_valid() const override { return valid; }
@@ -467,7 +467,7 @@ public:
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
/* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions,
- List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override {
+ List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override {
return true;
}
String validate_path(const String &p_path) const override;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index e602396ede..960d2fe27c 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1652,7 +1652,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append("static ");
}
- p_output.append(prop_itype->cs_type);
+ String prop_cs_type = prop_itype->cs_type + _get_generic_type_parameters(*prop_itype, proptype_name.generic_type_parameters);
+
+ p_output.append(prop_cs_type);
p_output.append(" ");
p_output.append(p_iprop.proxy_name);
p_output.append("\n" INDENT2 OPEN_BLOCK);
@@ -1762,6 +1764,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
"Invalid default value for parameter '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
}
+ String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
+
// Add the current arguments to the signature
// If the argument has a default value which is not a constant, we will make it Nullable
{
@@ -1773,7 +1777,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
arguments_sig += "Nullable<";
}
- arguments_sig += arg_type->cs_type;
+ arguments_sig += arg_cs_type;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
arguments_sig += "> ";
@@ -1800,7 +1804,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arg_in = iarg.name;
arg_in += "_in";
- cs_in_statements += arg_type->cs_type;
+ cs_in_statements += arg_cs_type;
cs_in_statements += " ";
cs_in_statements += arg_in;
cs_in_statements += " = ";
@@ -1820,7 +1824,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_in_statements += " : ";
}
- String cs_type = arg_type->cs_type;
+ String cs_type = arg_cs_type;
if (cs_type.ends_with("[]")) {
cs_type = cs_type.substr(0, cs_type.length() - 2);
}
@@ -1837,7 +1841,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Escape < and > in the attribute default value
String param_def_arg = def_arg.replacen("<", "&lt;").replacen(">", "&gt;");
- default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + param_def_arg + "</param>");
+ default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is <c>" + param_def_arg + "</c>.</param>");
} else {
icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
}
@@ -1903,7 +1907,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("virtual ");
}
- p_output.append(return_type->cs_type + " ");
+ String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters);
+
+ p_output.append(return_cs_type + " ");
p_output.append(p_imethod.proxy_name + "(");
p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L2);
@@ -1914,7 +1920,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("return;\n" CLOSE_BLOCK_L2);
} else {
p_output.append("return default(");
- p_output.append(return_type->cs_type);
+ p_output.append(return_cs_type);
p_output.append(");\n" CLOSE_BLOCK_L2);
}
@@ -1956,7 +1962,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
} else if (return_type->cs_out.is_empty()) {
p_output.append("return " + im_call + "(" + icall_params + ");\n");
} else {
- p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_type->cs_type, return_type->im_type_out));
+ p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_cs_type, return_type->im_type_out));
p_output.append("\n");
}
@@ -2517,6 +2523,42 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
return &placeholder_types.insert(placeholder.cname, placeholder)->value;
}
+const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters) {
+ if (p_generic_type_parameters.is_empty()) {
+ return "";
+ }
+
+ ERR_FAIL_COND_V_MSG(p_itype.type_parameter_count != p_generic_type_parameters.size(), "",
+ "Generic type parameter count mismatch for type '" + p_itype.name + "'." +
+ " Found " + itos(p_generic_type_parameters.size()) + ", but requires " +
+ itos(p_itype.type_parameter_count) + ".");
+
+ int i = 0;
+ String params = "<";
+ for (const TypeReference &param_type : p_generic_type_parameters) {
+ const TypeInterface *param_itype = _get_type_or_placeholder(param_type);
+
+ ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "",
+ "Generic type parameter is a singleton: '" + param_itype->name + "'.");
+
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(param_itype->api_type == ClassDB::API_EDITOR, "",
+ "Generic type parameter '" + param_itype->name + "' has type from the editor API." +
+ " Core API cannot have dependencies on the editor API.");
+ }
+
+ params += param_itype->cs_type;
+ if (i < p_generic_type_parameters.size() - 1) {
+ params += ", ";
+ }
+
+ i++;
+ }
+ params += ">";
+
+ return params;
+}
+
StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
switch (p_meta) {
case GodotTypeInfo::METADATA_INT_IS_INT8:
@@ -2832,6 +2874,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ERR_FAIL_COND_V_MSG(bad_reference_hint, false,
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
+ } else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string));
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type.cname = return_info.hint_string;
} else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
@@ -2861,6 +2906,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
iarg.type.is_enum = true;
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
+ } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
@@ -2966,6 +3014,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
iarg.type.is_enum = true;
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
+ } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
@@ -3549,13 +3600,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Array";
itype.cname = itype.name;
itype.proxy_name = itype.name;
+ itype.type_parameter_count = 1;
itype.c_out = "\treturn memnew(Array(%1));\n";
itype.c_type = itype.name;
itype.c_type_in = itype.c_type + "*";
itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new " + itype.cs_type + "(%0(%1));";
+ itype.cs_out = "return new %2(%0(%1));";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
builtin_types.insert(itype.cname, itype);
@@ -3565,13 +3617,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Dictionary";
itype.cname = itype.name;
itype.proxy_name = itype.name;
+ itype.type_parameter_count = 2;
itype.c_out = "\treturn memnew(Dictionary(%1));\n";
itype.c_type = itype.name;
itype.c_type_in = itype.c_type + "*";
itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new " + itype.cs_type + "(%0(%1));";
+ itype.cs_out = "return new %2(%0(%1));";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
builtin_types.insert(itype.cname, itype);
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index fb7e0e5a81..f0ba2b18e4 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -87,6 +87,8 @@ class BindingsGenerator {
StringName cname;
bool is_enum = false;
+ List<TypeReference> generic_type_parameters;
+
TypeReference() {}
TypeReference(const StringName &p_cname) :
@@ -206,6 +208,8 @@ class BindingsGenerator {
String name;
StringName cname;
+ int type_parameter_count;
+
/**
* Identifier name of the base class.
*/
@@ -679,6 +683,8 @@ class BindingsGenerator {
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
+ const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters);
+
StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
diff --git a/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs b/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs
new file mode 100644
index 0000000000..0690205d01
--- /dev/null
+++ b/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs
@@ -0,0 +1,18 @@
+// meta-description: Basic import script template
+
+#if TOOLS
+using _BINDINGS_NAMESPACE_;
+using System;
+
+[Tool]
+public partial class _CLASS_ : _BASE_
+{
+ public override Object _PostImport(Node scene)
+ {
+ // Modify the contents of the scene upon import. For example, setting up LODs:
+// scene.GetNode<MeshInstance3D>("HighPolyMesh").DrawDistanceEnd = 5.0
+// scene.GetNode<MeshInstance3D>("LowPolyMesh").DrawDistanceBegin = 5.0
+ return scene // Return the modified root node when you're done.
+ }
+}
+#endif
diff --git a/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs b/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs
new file mode 100644
index 0000000000..4e2d9b7088
--- /dev/null
+++ b/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs
@@ -0,0 +1,15 @@
+// meta-description: Basic import script template (no comments)
+
+#if TOOLS
+using _BINDINGS_NAMESPACE_;
+using System;
+
+[Tool]
+public partial class _CLASS_ : _BASE_
+{
+ public override Object _PostImport(Node scene)
+ {
+ return scene
+ }
+}
+#endif
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index ef135da51a..2febf37f05 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -2,17 +2,27 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that determines if an assembly has scripts. If so, what types of scripts the assembly has.
+ /// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyHasScriptsAttribute : Attribute
{
private readonly bool requiresLookup;
private readonly System.Type[] scriptTypes;
+ /// <summary>
+ /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// </summary>
public AssemblyHasScriptsAttribute()
{
requiresLookup = true;
}
+ /// <summary>
+ /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// </summary>
+ /// <param name="scriptTypes">The specified type(s) of scripts.</param>
public AssemblyHasScriptsAttribute(System.Type[] scriptTypes)
{
requiresLookup = false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
index e93bc89811..0b00878e8c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
@@ -2,6 +2,9 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that disables Godot Generators.
+ /// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class DisableGodotGeneratorsAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 6adf044886..46eb128d37 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -2,12 +2,20 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute used to export objects.
+ /// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ExportAttribute : Attribute
{
private PropertyHint hint;
private string hintString;
+ /// <summary>
+ /// Constructs a new ExportAttribute Instance.
+ /// </summary>
+ /// <param name="hint">A hint to the exported object.</param>
+ /// <param name="hintString">A string representing the exported object.</param>
public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
{
this.hint = hint;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
index 55848769d5..8d4ff0fdb7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
@@ -2,6 +2,9 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute for a method.
+ /// </summary>
[AttributeUsage(AttributeTargets.Method)]
internal class GodotMethodAttribute : Attribute
{
@@ -9,6 +12,10 @@ namespace Godot
public string MethodName { get { return methodName; } }
+ /// <summary>
+ /// Constructs a new GodotMethodAttribute instance.
+ /// </summary>
+ /// <param name="methodName">The name of the method.</param>
public GodotMethodAttribute(string methodName)
{
this.methodName = methodName;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
index b8b9bc660c..f0d37c344d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
@@ -2,9 +2,15 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// Constructs a new AnyPeerAttribute instance. Members with the AnyPeerAttribute are given authority over their own player.
+ /// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AnyPeerAttribute : Attribute { }
+ /// <summary>
+ /// Constructs a new AuthorityAttribute instance. Members with the AuthorityAttribute are given authority over the game.
+ /// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AuthorityAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 12eb1035c3..3ebb6612de 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -2,11 +2,18 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that contains the path to the object's script.
+ /// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ScriptPathAttribute : Attribute
{
private string path;
+ /// <summary>
+ /// Constructs a new ScriptPathAttribute instance.
+ /// </summary>
+ /// <param name="path">The file path to the script</param>
public ScriptPathAttribute(string path)
{
this.path = path;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
index 072e0f20ff..6475237002 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -4,9 +4,16 @@ namespace Godot
{
public static class Dispatcher
{
+ /// <summary>
+ /// Implements an external instance of GodotTaskScheduler.
+ /// </summary>
+ /// <returns>A GodotTaskScheduler instance.</returns>
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler();
+ /// <summary>
+ /// Initializes the synchronization context as the context of the GodotTaskScheduler.
+ /// </summary>
public static GodotSynchronizationContext SynchronizationContext =>
godot_icall_DefaultGodotTaskScheduler().Context;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
index c01c926e82..1b599beab5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
@@ -14,6 +14,9 @@ namespace Godot
_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
}
+ /// <summary>
+ /// Calls the Key method on each workItem object in the _queue to activate their callbacks.
+ /// </summary>
public void ExecutePendingContinuations()
{
while (_queue.TryTake(out var workItem))
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
index 8eaeea50dc..408bed71b2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
@@ -6,11 +6,25 @@ using System.Threading.Tasks;
namespace Godot
{
+ /// <summary>
+ /// GodotTaskScheduler contains a linked list of tasks to perform as a queue. Methods
+ /// within the class are used to control the queue and perform the contained tasks.
+ /// </summary>
public class GodotTaskScheduler : TaskScheduler
{
+ /// <summary>
+ /// The current synchronization context.
+ /// </summary>
internal GodotSynchronizationContext Context { get; }
+
+ /// <summary>
+ /// The queue of tasks for the task scheduler.
+ /// </summary>
private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+ /// <summary>
+ /// Constructs a new GodotTaskScheduler instance.
+ /// </summary>
public GodotTaskScheduler()
{
Context = new GodotSynchronizationContext();
@@ -53,12 +67,19 @@ namespace Godot
}
}
+ /// <summary>
+ /// Executes all queued tasks and pending tasks from the current context.
+ /// </summary>
public void Activate()
{
ExecuteQueuedTasks();
Context.ExecutePendingContinuations();
}
+ /// <summary>
+ /// Loops through and attempts to execute each task in _tasks.
+ /// </summary>
+ /// <exception cref="InvalidOperationException"></exception>
private void ExecuteQueuedTasks()
{
while (true)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
index 0397957d00..e747e03c1e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
@@ -1,10 +1,17 @@
namespace Godot
{
+ /// <summary>
+ /// An interface that requires a GetAwaiter() method to get a reference to the Awaiter.
+ /// </summary>
public interface IAwaitable
{
IAwaiter GetAwaiter();
}
+ /// <summary>
+ /// A templated interface that requires a GetAwaiter() method to get a reference to the Awaiter.
+ /// </summary>
+ /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam>
public interface IAwaitable<out TResult>
{
IAwaiter<TResult> GetAwaiter();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
index d3be9d781c..dec225eb29 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
@@ -2,6 +2,9 @@ using System.Runtime.CompilerServices;
namespace Godot
{
+ /// <summary>
+ /// An interface that requires a boolean for completion status and a method that gets the result of completion.
+ /// </summary>
public interface IAwaiter : INotifyCompletion
{
bool IsCompleted { get; }
@@ -9,6 +12,10 @@ namespace Godot
void GetResult();
}
+ /// <summary>
+ /// A templated interface that requires a boolean for completion status and a method that gets the result of completion and returns it.
+ /// </summary>
+ /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam>
public interface IAwaiter<out TResult> : INotifyCompletion
{
bool IsCompleted { get; }
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
index c3fa2f3e82..90b4d1b8d3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
@@ -1,5 +1,8 @@
namespace Godot
{
+ /// <summary>
+ /// An interface that requires methods for before and after serialization.
+ /// </summary>
public interface ISerializationListener
{
void OnBeforeSerialize();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
index ee4d0eed08..50ae2eb112 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
@@ -80,6 +80,11 @@ namespace Godot
private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
/// <summary>
+ /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
+ /// </summary>
+ private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
+
+ /// <summary>
/// Returns the generic type definition of <paramref name="type"/>.
/// </summary>
/// <exception cref="InvalidOperationException">
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index d8fd244067..44a8e26b8f 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -176,6 +176,7 @@ void CachedData::clear_godot_api_cache() {
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
+ methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
@@ -300,6 +301,7 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 4000342c94..92136e1f41 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -147,6 +147,7 @@ struct CachedData {
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
+ GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 25678be624..1983d6ebe2 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -614,6 +614,14 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
return (bool)res;
}
+bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
+ MonoException *exc = nullptr;
+ MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
+}
+
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 4c2c2c93c2..246a1cd31e 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -61,6 +61,7 @@ bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
+bool type_has_flags_attribute(MonoReflectionType *p_reftype);
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 42aad77979..2f8cb6c230 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -198,11 +198,11 @@ real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const {
return map->get_edge_connection_margin();
}
-Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
+Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
- return map->get_path(p_origin, p_destination, p_optimize, p_layers);
+ return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers);
}
Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -256,13 +256,19 @@ Array GodotNavigationServer::map_get_agents(RID p_map) const {
RID GodotNavigationServer::region_get_map(RID p_region) const {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(region == nullptr, RID());
- return region->get_map()->get_self();
+ if (region->get_map()) {
+ return region->get_map()->get_self();
+ }
+ return RID();
}
RID GodotNavigationServer::agent_get_map(RID p_agent) const {
RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND_V(agent == nullptr, RID());
- return agent->get_map()->get_self();
+ if (agent->get_map()) {
+ return agent->get_map()->get_self();
+ }
+ return RID();
}
RID GodotNavigationServer::region_create() const {
@@ -303,18 +309,48 @@ COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {
region->set_transform(p_transform);
}
-COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) {
+COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_enter_cost < 0.0);
+
+ region->set_enter_cost(p_enter_cost);
+}
+
+real_t GodotNavigationServer::region_get_enter_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_enter_cost();
+}
+
+COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_travel_cost < 0.0);
+
+ region->set_travel_cost(p_travel_cost);
+}
+
+real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_travel_cost();
+}
+
+COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
- region->set_layers(p_layers);
+ region->set_navigation_layers(p_navigation_layers);
}
-uint32_t GodotNavigationServer::region_get_layers(RID p_region) const {
+uint32_t GodotNavigationServer::region_get_navigation_layers(RID p_region) const {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(region == nullptr, 0);
- return region->get_layers();
+ return region->get_navigation_layers();
}
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) {
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 89e7311e51..d931dbaee0 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -98,7 +98,7 @@ public:
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
virtual real_t map_get_edge_connection_margin(RID p_map) const override;
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const override;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override;
@@ -109,10 +109,16 @@ public:
virtual Array map_get_agents(RID p_map) const override;
virtual RID region_create() const override;
+
+ COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost);
+ virtual real_t region_get_enter_cost(RID p_region) const override;
+ COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost);
+ virtual real_t region_get_travel_cost(RID p_region) const override;
+
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
virtual RID region_get_map(RID p_region) const override;
- COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
- virtual uint32_t region_get_layers(RID p_region) const override;
+ COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers);
+ virtual uint32_t region_get_navigation_layers(RID p_region) const override;
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override;
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 344475fb37..49c12813b3 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -65,7 +65,7 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
return p;
}
-Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
+Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
// Find the start poly and the end poly on this map.
const gd::Polygon *begin_poly = nullptr;
const gd::Polygon *end_poly = nullptr;
@@ -78,7 +78,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
const gd::Polygon &p = polygons[i];
// Only consider the polygon if it in a region with compatible layers.
- if ((p_layers & p.owner->get_layers()) == 0) {
+ if ((p_navigation_layers & p.owner->get_navigation_layers()) == 0) {
continue;
}
@@ -140,6 +140,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
float reachable_d = 1e30;
bool is_reachable = true;
+ gd::NavigationPoly *prev_least_cost_poly = nullptr;
+
while (true) {
// Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
@@ -152,13 +154,21 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
const gd::Edge::Connection &connection = edge.connections[connection_index];
// Only consider the connection to another polygon if this polygon is in a region with compatible layers.
- if ((p_layers & connection.polygon->owner->get_layers()) == 0) {
+ if ((p_navigation_layers & connection.polygon->owner->get_navigation_layers()) == 0) {
continue;
}
+ float region_enter_cost = 0.0;
+ float region_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
+
+ if (prev_least_cost_poly != nullptr && !(prev_least_cost_poly->poly->owner->get_self() == least_cost_poly->poly->owner->get_self())) {
+ region_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
+ }
+ prev_least_cost_poly = least_cost_poly;
+
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
- const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
+ const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * region_travel_cost) + region_enter_cost + least_cost_poly->traveled_distance;
const std::vector<gd::NavigationPoly>::iterator it = std::find(
navigation_polys.begin(),
@@ -238,7 +248,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
for (List<uint32_t>::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
- cost += np->entry.distance_to(end_point);
+ cost += (np->entry.distance_to(end_point) * np->poly->owner->get_travel_cost());
if (cost < least_cost) {
least_cost_id = np->self_id;
least_cost = cost;
@@ -249,7 +259,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
- float d = navigation_polys[least_cost_id].entry.distance_to(p_destination);
+ float d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost();
if (reachable_d > d) {
reachable_d = d;
reachable_end = navigation_polys[least_cost_id].poly;
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index 0ebdea30e1..2036dbecd7 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RVO_SPACE_H
-#define RVO_SPACE_H
+#ifndef NAV_MAP_H
+#define NAV_MAP_H
#include "nav_rid.h"
@@ -50,10 +50,10 @@ class NavMap : public NavRid {
/// To find the polygons edges the vertices are displaced in a grid where
/// each cell has the following cell_size.
- real_t cell_size = 0.3;
+ real_t cell_size = 0.25;
/// This value is used to detect the near edges to connect.
- real_t edge_connection_margin = 5.0;
+ real_t edge_connection_margin = 0.25;
bool regenerate_polygons = true;
bool regenerate_links = true;
@@ -105,7 +105,7 @@ public:
gd::PointKey get_point_key(const Vector3 &p_pos) const;
- Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
+ Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const;
Vector3 get_closest_point(const Vector3 &p_point) const;
Vector3 get_closest_point_normal(const Vector3 &p_point) const;
@@ -141,4 +141,4 @@ private:
void clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const;
};
-#endif // RVO_SPACE_H
+#endif // NAV_MAP_H
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index fea0ad519a..88740807eb 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -40,12 +40,12 @@ void NavRegion::set_map(NavMap *p_map) {
}
}
-void NavRegion::set_layers(uint32_t p_layers) {
- layers = p_layers;
+void NavRegion::set_navigation_layers(uint32_t p_navigation_layers) {
+ navigation_layers = p_navigation_layers;
}
-uint32_t NavRegion::get_layers() const {
- return layers;
+uint32_t NavRegion::get_navigation_layers() const {
+ return navigation_layers;
}
void NavRegion::set_transform(Transform3D p_transform) {
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 7a6da281c0..484856ae36 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -45,7 +45,9 @@ class NavRegion : public NavRid {
NavMap *map = nullptr;
Transform3D transform;
Ref<NavigationMesh> mesh;
- uint32_t layers = 1;
+ uint32_t navigation_layers = 1;
+ float enter_cost = 0.0;
+ float travel_cost = 1.0;
Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@@ -65,8 +67,14 @@ public:
return map;
}
- void set_layers(uint32_t p_layers);
- uint32_t get_layers() const;
+ void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
+ float get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
+ float get_travel_cost() const { return travel_cost; }
+
+ void set_navigation_layers(uint32_t p_navigation_layers);
+ uint32_t get_navigation_layers() const;
void set_transform(Transform3D transform);
const Transform3D &get_transform() const {
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 5cbaded6c1..e430f5fd59 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -172,14 +172,16 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
if (Object::cast_to<MultiMeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MultiMeshInstance3D *multimesh_instance = Object::cast_to<MultiMeshInstance3D>(p_node);
Ref<MultiMesh> multimesh = multimesh_instance->get_multimesh();
- Ref<Mesh> mesh = multimesh->get_mesh();
- if (mesh.is_valid()) {
- int n = multimesh->get_visible_instance_count();
- if (n == -1) {
- n = multimesh->get_instance_count();
- }
- for (int i = 0; i < n; i++) {
- _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices);
+ if (multimesh.is_valid()) {
+ Ref<Mesh> mesh = multimesh->get_mesh();
+ if (mesh.is_valid()) {
+ int n = multimesh->get_visible_instance_count();
+ if (n == -1) {
+ n = multimesh->get_instance_count();
+ }
+ for (int i = 0; i < n; i++) {
+ _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices);
+ }
}
}
}
@@ -448,6 +450,31 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
+ if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_nav_mesh->get_agent_height())) {
+ WARN_PRINT("Property agent_height is ceiled to cell_height voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_nav_mesh->get_agent_max_climb())) {
+ WARN_PRINT("Property agent_max_climb is floored to cell_height voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_nav_mesh->get_agent_radius())) {
+ WARN_PRINT("Property agent_radius is ceiled to cell_size voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_nav_mesh->get_edge_max_length())) {
+ WARN_PRINT("Property edge_max_length is rounded to cell_size voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.minRegionArea, p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size())) {
+ WARN_PRINT("Property region_min_size is converted to int and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size())) {
+ WARN_PRINT("Property region_merge_size is converted to int and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_nav_mesh->get_verts_per_poly())) {
+ WARN_PRINT("Property verts_per_poly is converted to int and loses precision.");
+ }
+ if (p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance() < 0.1f) {
+ WARN_PRINT("Property detail_sample_distance is clamped to 0.1 world units as the resulting value from multiplying with cell_size is too low.");
+ }
+
cfg.bmin[0] = bmin[0];
cfg.bmin[1] = bmin[1];
cfg.bmin[2] = bmin[2];
diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp
index a6a5660c0c..4ec72ad43f 100644
--- a/modules/navigation/rvo_agent.cpp
+++ b/modules/navigation/rvo_agent.cpp
@@ -65,8 +65,9 @@ void RvoAgent::dispatch_callback() {
return;
}
Object *obj = ObjectDB::get_instance(callback.id);
- if (obj == nullptr) {
+ if (!obj) {
callback.id = ObjectID();
+ return;
}
Callable::CallError responseCallError;
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
index 914cdec24c..b21e3247d7 100644
--- a/modules/noise/fastnoise_lite.cpp
+++ b/modules/noise/fastnoise_lite.cpp
@@ -300,6 +300,12 @@ real_t FastNoiseLite::get_domain_warp_fractal_gain() const {
// Noise interface functions.
real_t FastNoiseLite::get_noise_1d(real_t p_x) const {
+ p_x += offset.x;
+ if (domain_warp_enabled) {
+ // Needed since DomainWarp expects a reference.
+ real_t y_dummy = 0;
+ _domain_warp_noise.DomainWarp(p_x, y_dummy);
+ }
return get_noise_2d(p_x, 0.0);
}
@@ -308,10 +314,12 @@ real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const {
}
real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const {
+ p_x += offset.x;
+ p_y += offset.y;
if (domain_warp_enabled) {
_domain_warp_noise.DomainWarp(p_x, p_y);
}
- return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
+ return _noise.GetNoise(p_x, p_y);
}
real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const {
@@ -319,10 +327,13 @@ real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const {
}
real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const {
+ p_x += offset.x;
+ p_y += offset.y;
+ p_z += offset.z;
if (domain_warp_enabled) {
_domain_warp_noise.DomainWarp(p_x, p_y, p_z);
}
- return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
+ return _noise.GetNoise(p_x, p_y, p_z);
}
void FastNoiseLite::_changed() {
diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture.cpp
index e9d16e548c..ca55d3b96d 100644
--- a/modules/noise/noise_texture.cpp
+++ b/modules/noise/noise_texture.cpp
@@ -81,8 +81,8 @@ void NoiseTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater,suffix:px"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps");
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
index e2a4f67f16..41c6465f43 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -63,8 +63,7 @@ void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_te
}
void OpenXRActionEditor::_on_item_selected(int p_idx) {
- ERR_FAIL_COND(p_idx < 0);
- ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX);
+ ERR_FAIL_INDEX(p_idx, OpenXRAction::OPENXR_ACTION_MAX);
action->set_action_type(OpenXRAction::ActionType(p_idx));
}
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 6e9a2e1b61..87b7f50224 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -344,6 +344,7 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() {
tabs = memnew(TabContainer);
tabs->set_h_size_flags(SIZE_EXPAND_FILL);
tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ tabs->set_theme_type_variation("TabContainerOdd");
tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed));
tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed));
add_child(tabs);
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 6e94e3b444..d8d3bacb19 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -172,7 +172,7 @@ bool OpenXRAPI::load_supported_extensions() {
bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
for (uint32_t i = 0; i < num_supported_extensions; i++) {
- if ((supported_extensions[i].extensionName == p_extension) == 0) {
+ if (supported_extensions[i].extensionName == p_extension) {
#ifdef DEBUG
print_line("OpenXR: requested extension", p_extension, "is supported");
#endif
@@ -1102,7 +1102,7 @@ Size2 OpenXRAPI::get_recommended_target_size() {
return target_size;
}
-XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
XrResult result;
ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE);
@@ -1730,7 +1730,7 @@ XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointL
return _transform_from_location(p_location, r_transform);
}
-void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity) {
+void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
XrVector3f linear_velocity = p_velocity.linearVelocity;
r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z);
@@ -2303,7 +2303,7 @@ Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
}
-XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
Action *action = action_owner.get_or_null(p_action);
ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index bd71f0e1c2..fe9e2937b2 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -225,7 +225,7 @@ protected:
// helper method to get a valid Transform3D from an openxr space location
XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform);
XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform);
- void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity);
+ void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
public:
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
@@ -247,7 +247,7 @@ public:
bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; };
Size2 get_recommended_target_size();
- XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool get_view_transform(uint32_t p_view, Transform3D &r_transform);
bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix);
bool process();
@@ -285,7 +285,7 @@ public:
bool get_action_bool(RID p_action, RID p_tracker);
float get_action_float(RID p_action, RID p_tracker);
Vector2 get_action_vector2(RID p_action, RID p_tracker);
- XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns);
OpenXRAPI();
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
index 7e7c3f9067..9b35b5616e 100644
--- a/modules/raycast/lightmap_raycaster.cpp
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -152,17 +152,17 @@ void LightmapRaycasterEmbree::commit() {
rtcCommitScene(embree_scene);
}
-void LightmapRaycasterEmbree::set_mesh_filter(const RBSet<int> &p_mesh_ids) {
- for (RBSet<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
- rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
+void LightmapRaycasterEmbree::set_mesh_filter(const HashSet<int> &p_mesh_ids) {
+ for (const int &E : p_mesh_ids) {
+ rtcDisableGeometry(rtcGetGeometry(embree_scene, E));
}
rtcCommitScene(embree_scene);
filter_meshes = p_mesh_ids;
}
void LightmapRaycasterEmbree::clear_mesh_filter() {
- for (RBSet<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
- rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ for (const int &E : filter_meshes) {
+ rtcEnableGeometry(rtcGetGeometry(embree_scene, E));
}
rtcCommitScene(embree_scene);
filter_meshes.clear();
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h
index 4c52758fd8..4266b46ea8 100644
--- a/modules/raycast/lightmap_raycaster.h
+++ b/modules/raycast/lightmap_raycaster.h
@@ -53,7 +53,7 @@ private:
static void filter_function(const struct RTCFilterFunctionNArguments *p_args);
HashMap<unsigned int, AlphaTextureData> alpha_textures;
- RBSet<int> filter_meshes;
+ HashSet<int> filter_meshes;
public:
virtual bool intersect(Ray &p_ray) override;
@@ -64,7 +64,7 @@ public:
virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override;
virtual void commit() override;
- virtual void set_mesh_filter(const RBSet<int> &p_mesh_ids) override;
+ virtual void set_mesh_filter(const HashSet<int> &p_mesh_ids) override;
virtual void clear_mesh_filter() override;
static LightmapRaycaster *create_embree_raycaster();
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index c165354c7b..89e75f774e 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -223,9 +223,9 @@ void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3
occluder->vertices = p_vertices;
occluder->indices = p_indices;
- for (RBSet<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) {
- RID scenario_rid = E->get().scenario;
- RID instance_rid = E->get().instance;
+ for (const InstanceID &E : occluder->users) {
+ RID scenario_rid = E.scenario;
+ RID instance_rid = E.instance;
ERR_CONTINUE(!scenarios.has(scenario_rid));
Scenario &scenario = scenarios[scenario_rid];
ERR_CONTINUE(!scenario.instances.has(instance_rid));
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
index 779f6fb3c4..4474031991 100644
--- a/modules/raycast/raycast_occlusion_cull.h
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -86,11 +86,13 @@ private:
RID scenario;
RID instance;
- bool operator<(const InstanceID &rhs) const {
- if (instance == rhs.instance) {
- return rhs.scenario < scenario;
- }
- return instance < rhs.instance;
+ static uint32_t hash(const InstanceID &p_ins) {
+ uint32_t h = hash_djb2_one_64(p_ins.scenario.get_id());
+ return hash_djb2_one_64(p_ins.instance.get_id(), h);
+ }
+ bool operator==(const InstanceID &rhs) const {
+ return instance == rhs.instance && rhs.scenario == scenario;
+ ;
}
InstanceID() {}
@@ -101,7 +103,7 @@ private:
struct Occluder {
PackedVector3Array vertices;
PackedInt32Array indices;
- RBSet<InstanceID> users;
+ HashSet<InstanceID, InstanceID> users;
};
struct OccluderInstance {
@@ -136,7 +138,7 @@ private:
int current_scene_idx = 0;
HashMap<RID, OccluderInstance> instances;
- RBSet<RID> dirty_instances; // To avoid duplicates
+ HashSet<RID> dirty_instances; // To avoid duplicates
LocalVector<RID> dirty_instances_array; // To iterate and split into threads
LocalVector<RID> removed_instances;
diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster.cpp
index f2e944a82d..7659eea27f 100644
--- a/modules/raycast/static_raycaster.cpp
+++ b/modules/raycast/static_raycaster.cpp
@@ -94,17 +94,17 @@ void StaticRaycasterEmbree::commit() {
rtcCommitScene(embree_scene);
}
-void StaticRaycasterEmbree::set_mesh_filter(const RBSet<int> &p_mesh_ids) {
- for (RBSet<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
- rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
+void StaticRaycasterEmbree::set_mesh_filter(const HashSet<int> &p_mesh_ids) {
+ for (const int &E : p_mesh_ids) {
+ rtcDisableGeometry(rtcGetGeometry(embree_scene, E));
}
rtcCommitScene(embree_scene);
filter_meshes = p_mesh_ids;
}
void StaticRaycasterEmbree::clear_mesh_filter() {
- for (RBSet<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
- rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ for (const int &E : filter_meshes) {
+ rtcEnableGeometry(rtcGetGeometry(embree_scene, E));
}
rtcCommitScene(embree_scene);
filter_meshes.clear();
diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster.h
index b52b5bccfc..e2909f9b56 100644
--- a/modules/raycast/static_raycaster.h
+++ b/modules/raycast/static_raycaster.h
@@ -41,7 +41,7 @@ private:
static RTCDevice embree_device;
RTCScene embree_scene;
- RBSet<int> filter_meshes;
+ HashSet<int> filter_meshes;
public:
virtual bool intersect(Ray &p_ray) override;
@@ -50,7 +50,7 @@ public:
virtual void add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) override;
virtual void commit() override;
- virtual void set_mesh_filter(const RBSet<int> &p_mesh_ids) override;
+ virtual void set_mesh_filter(const HashSet<int> &p_mesh_ids) override;
virtual void clear_mesh_filter() override;
static StaticRaycaster *create_embree_raycaster();
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 525d4d3efb..a46f17311a 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -442,7 +442,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt70l.dat"
+ icu_data_name = "icudt71l.dat"
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 1c38398c88..0e36ef6805 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -116,6 +116,7 @@ if env["freetype_enabled"]:
"src/psnames/psnames.c",
"src/raster/raster.c",
"src/sdf/sdf.c",
+ "src/svg/svg.c",
"src/smooth/smooth.c",
"src/truetype/truetype.c",
"src/type1/type1.c",
@@ -164,7 +165,14 @@ if env["freetype_enabled"]:
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
- env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)])
+ env_freetype.Append(
+ CPPDEFINES=[
+ "FT2_BUILD_LIBRARY",
+ "FT_CONFIG_OPTION_USE_PNG",
+ ("PNG_ARM_NEON_OPT", 0),
+ "FT_CONFIG_OPTION_SYSTEM_ZLIB",
+ ]
+ )
if env["target"] == "debug":
env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
@@ -564,7 +572,7 @@ thirdparty_icu_sources = [
]
thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
-icu_data_name = "icudt70l.dat"
+icu_data_name = "icudt71l.dat"
if env["static_icu_data"]:
env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index bd14b15561..86687357d6 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -1288,7 +1288,16 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fargs.memory_size = p_font_data->data_size;
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &fd->stream;
- error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
+
+ int max_index = 0;
+ FT_Face tmp_face;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (error == 0) {
+ max_index = tmp_face->num_faces - 1;
+ }
+ FT_Done_Face(tmp_face);
+
+ error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
@@ -1329,7 +1338,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
- hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.columns[0][1]);
+ hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);
if (!p_font_data->face_init) {
// Get style flags and name.
@@ -1691,6 +1700,8 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_
}
RID TextServerAdvanced::create_font() {
+ _THREAD_SAFE_METHOD_
+
FontDataAdvanced *fd = memnew(FontDataAdvanced);
return font_owner.make_rid(fd);
@@ -1718,6 +1729,69 @@ void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t
fd->data_size = p_data_size;
}
+void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
+ ERR_FAIL_COND(p_face_index < 0);
+ ERR_FAIL_COND(p_face_index >= 0x7FFF);
+
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->face_index != p_face_index) {
+ fd->face_index = p_face_index;
+ _font_clear_cache(fd);
+ }
+}
+
+int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ return fd->face_index;
+}
+
+int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ int face_count = 0;
+
+ if (fd->data_ptr && (fd->data_size > 0)) {
+ // Init dynamic font.
+#ifdef MODULE_FREETYPE_ENABLED
+ int error = 0;
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
+ ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
+
+ FT_StreamRec stream;
+ memset(&stream, 0, sizeof(FT_StreamRec));
+ stream.base = (unsigned char *)fd->data_ptr;
+ stream.size = fd->data_size;
+ stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)fd->data_ptr;
+ fargs.memory_size = fd->data_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &stream;
+
+ FT_Face tmp_face;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (error == 0) {
+ face_count = tmp_face->num_faces;
+ }
+ FT_Done_Face(tmp_face);
+#endif
+ }
+
+ return face_count;
+}
+
void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2778,7 +2852,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -3270,7 +3344,7 @@ void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) {
int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {
int64_t limit = p_pos;
if (p_utf32.length() != p_utf16.length()) {
- const UChar *data = p_utf16.ptr();
+ const UChar *data = p_utf16.get_data();
for (int i = 0; i < p_pos; i++) {
if (U16_IS_LEAD(data[i])) {
limit--;
@@ -3359,6 +3433,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
sd->hb_buffer = hb_buffer_create();
sd->direction = p_direction;
@@ -3748,6 +3823,8 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
}
RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
+ _THREAD_SAFE_METHOD_
+
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -4775,6 +4852,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
RID f = p_fonts[p_fb_index];
FontDataAdvanced *fd = font_owner.get_or_null(f);
+ ERR_FAIL_COND(!fd);
+ MutexLock lock(fd->mutex);
+
Vector2i fss = _get_size(fd, fs);
hb_font_t *hb_font = _font_get_hb_handle(f, fs);
double scale = font_get_scale(f, fs);
@@ -5584,9 +5664,9 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri
// Convert to UTF-16.
Char16String utf16 = p_string.utf16();
- RBSet<int> breaks;
+ HashSet<int> breaks;
UErrorCode err = U_ZERO_ERROR;
- UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err);
+ UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
if (U_FAILURE(err)) {
// No data loaded - use fallback.
for (int i = 0; i < p_string.length(); i++) {
@@ -5635,8 +5715,10 @@ TextServerAdvanced::TextServerAdvanced() {
TextServerAdvanced::~TextServerAdvanced() {
_bmp_free_font_funcs();
+#ifdef MODULE_FREETYPE_ENABLED
if (ft_library != nullptr) {
FT_Done_FreeType(ft_library);
}
+#endif
u_cleanup();
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 897c27b6fa..e7690cb70d 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -67,8 +67,8 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
@@ -126,7 +126,7 @@ class TextServerAdvanced : public TextServerExtension {
_THREAD_SAFE_CLASS_
struct NumSystemData {
- RBSet<StringName> lang;
+ HashSet<StringName> lang;
String digits;
String percent_sign;
String exp;
@@ -191,7 +191,7 @@ class TextServerAdvanced : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
+ HashMap<Vector2i, Vector2> kerning_map;
hb_font_t *hb_handle = nullptr;
#ifdef MODULE_FREETYPE_ENABLED
@@ -235,7 +235,7 @@ class TextServerAdvanced : public TextServerExtension {
HashMap<Vector2i, FontDataForSizeAdvanced *, VariantHasher, VariantComparator> cache;
bool face_init = false;
- RBSet<uint32_t> supported_scripts;
+ HashSet<uint32_t> supported_scripts;
Dictionary supported_features;
Dictionary supported_varaitions;
Dictionary feature_overrides;
@@ -247,6 +247,7 @@ class TextServerAdvanced : public TextServerExtension {
PackedByteArray data;
const uint8_t *data_ptr;
size_t data_size;
+ int face_index = 0;
mutable ThreadWorkPool work_pool;
~FontDataAdvanced() {
@@ -473,6 +474,11 @@ public:
virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
+ virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override;
+ virtual int64_t font_get_face_index(const RID &p_font_rid) const override;
+
+ virtual int64_t font_get_face_count(const RID &p_font_rid) const override;
+
virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 1753bc8b86..6c9e10db18 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -111,6 +111,7 @@ if env["freetype_enabled"]:
"src/psnames/psnames.c",
"src/raster/raster.c",
"src/sdf/sdf.c",
+ "src/svg/svg.c",
"src/smooth/smooth.c",
"src/truetype/truetype.c",
"src/type1/type1.c",
@@ -159,7 +160,14 @@ if env["freetype_enabled"]:
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
- env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)])
+ env_freetype.Append(
+ CPPDEFINES=[
+ "FT2_BUILD_LIBRARY",
+ "FT_CONFIG_OPTION_USE_PNG",
+ ("PNG_ARM_NEON_OPT", 0),
+ "FT_CONFIG_OPTION_SYSTEM_ZLIB",
+ ]
+ )
if env["target"] == "debug":
env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index c53ca7766a..0bece4e7a7 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -733,7 +733,16 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
fargs.memory_size = p_font_data->data_size;
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &fd->stream;
- error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
+
+ int max_index = 0;
+ FT_Face tmp_face;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (error == 0) {
+ max_index = tmp_face->num_faces - 1;
+ }
+ FT_Done_Face(tmp_face);
+
+ error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
@@ -853,6 +862,8 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontDataFallback *p_fo
}
RID TextServerFallback::create_font() {
+ _THREAD_SAFE_METHOD_
+
FontDataFallback *fd = memnew(FontDataFallback);
return font_owner.make_rid(fd);
@@ -890,6 +901,69 @@ void TextServerFallback::font_set_style(const RID &p_font_rid, int64_t /*FontSty
fd->style_flags = p_style;
}
+void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
+ ERR_FAIL_COND(p_face_index < 0);
+ ERR_FAIL_COND(p_face_index >= 0x7FFF);
+
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->face_index != p_face_index) {
+ fd->face_index = p_face_index;
+ _font_clear_cache(fd);
+ }
+}
+
+int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ return fd->face_index;
+}
+
+int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ int face_count = 0;
+
+ if (fd->data_ptr && (fd->data_size > 0)) {
+ // Init dynamic font.
+#ifdef MODULE_FREETYPE_ENABLED
+ int error = 0;
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
+ ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
+
+ FT_StreamRec stream;
+ memset(&stream, 0, sizeof(FT_StreamRec));
+ stream.base = (unsigned char *)fd->data_ptr;
+ stream.size = fd->data_size;
+ stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)fd->data_ptr;
+ fargs.memory_size = fd->data_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &stream;
+
+ FT_Face tmp_face;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (error == 0) {
+ face_count = tmp_face->num_faces;
+ }
+ FT_Done_Face(tmp_face);
+#endif
+ }
+
+ return face_count;
+}
+
int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -1926,7 +2000,7 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -2429,6 +2503,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
sd->direction = p_direction;
sd->orientation = p_orientation;
@@ -2807,6 +2882,8 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
}
RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
+ _THREAD_SAFE_METHOD_
+
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 0d2fc2628d..e4c81aed5b 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,8 +67,8 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
@@ -159,7 +159,7 @@ class TextServerFallback : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
+ HashMap<Vector2i, Vector2> kerning_map;
#ifdef MODULE_FREETYPE_ENABLED
FT_Face face = nullptr;
@@ -209,6 +209,7 @@ class TextServerFallback : public TextServerExtension {
PackedByteArray data;
const uint8_t *data_ptr;
size_t data_size;
+ int face_index = 0;
mutable ThreadWorkPool work_pool;
@@ -364,6 +365,11 @@ public:
virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
+ virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override;
+ virtual int64_t font_get_face_index(const RID &p_font_rid) const override;
+
+ virtual int64_t font_get_face_count(const RID &p_font_rid) const override;
+
virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index 4847b24f61..ceea0eaf1d 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -889,7 +889,49 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
- button->set_text(pi.hint_string.get_slice(",", value));
+ bool found = false;
+ const Vector<String> options = pi.hint_string.split(",");
+ int64_t current_val = 0;
+ for (const String &option : options) {
+ Vector<String> text_split = option.split(":");
+ if (text_split.size() != 1) {
+ current_val = text_split[1].to_int();
+ }
+ if (value.operator int() == current_val) {
+ button->set_text(text_split[0]);
+ found = true;
+ break;
+ }
+ current_val += 1;
+ }
+ if (!found) {
+ button->set_text(value);
+ }
+ } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_FLAGS) {
+ Vector<String> value_texts;
+ const Vector<String> options = pi.hint_string.split(",");
+ uint32_t v = value;
+ for (const String &option : options) {
+ uint32_t current_val;
+ Vector<String> text_split = option.split(":");
+ if (text_split.size() != -1) {
+ current_val = text_split[1].to_int();
+ } else {
+ current_val = 1 << i;
+ }
+ if ((v & current_val) == current_val) {
+ value_texts.push_back(text_split[0]);
+ }
+ }
+ if (value_texts.size() != 0) {
+ String value_text = value_texts[0];
+ for (const String &text : value_texts) {
+ value_text += " | " + text;
+ }
+ button->set_text(value_text);
+ } else {
+ button->set_text(value);
+ }
} else {
button->set_text(value);
}
@@ -980,6 +1022,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
+ float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ graph->set_connection_lines_curvature(graph_lines_curvature);
+
// Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything.
graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE);
updating_graph = false;
@@ -1440,7 +1485,11 @@ void VisualScriptEditor::_deselect_input_names() {
}
}
-void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) {
+void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button) {
+ if (p_mouse_button != MouseButton::LEFT) {
+ return;
+ }
+
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
TreeItem *root = members->get_root();
@@ -1625,8 +1674,8 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
undo_redo->add_do_method(this, "_update_graph", p_id);
for (const KeyValue<int, RBSet<int>> &E : conn_map) {
- for (const RBSet<int>::Element *F = E.value.front(); F; F = F->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F->get());
+ for (const int &F : E.value) {
+ undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F);
}
}
@@ -1813,14 +1862,14 @@ void VisualScriptEditor::_on_nodes_paste() {
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
}
- for (RBSet<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
+ for (const VisualScript::SequenceConnection &E : clipboard->sequence_connections) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E.from_node], E.from_output, remap[E.to_node]);
}
- for (RBSet<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
+ for (const VisualScript::DataConnection &E : clipboard->data_connections) {
+ undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);
}
undo_redo->add_do_method(this, "_update_graph");
@@ -1910,17 +1959,17 @@ void VisualScriptEditor::_on_nodes_duplicate() {
RBSet<int> to_select;
HashMap<int, int> remap;
- for (RBSet<int>::Element *F = to_duplicate.front(); F; F = F->next()) {
+ for (const int &F : to_duplicate) {
// Duplicate from the specific function but place it into the default func as it would lack the connections.
- Ref<VisualScriptNode> node = script->get_node(F->get());
+ Ref<VisualScriptNode> node = script->get_node(F);
Ref<VisualScriptNode> dupe = node->duplicate(true);
int new_id = idc++;
- remap.insert(F->get(), new_id);
+ remap.insert(F, new_id);
to_select.insert(new_id);
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20));
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F) + Vector2(20, 20));
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
}
@@ -1966,15 +2015,6 @@ void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) {
}
new_connect_node_select->select_from_visual_script(script, false); // do not reset text
-
- // Ensure that the dialog fits inside the graph.
- Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
- pos.x = pos.x > bounds.x ? bounds.x : pos.x;
- pos.y = pos.y > bounds.y ? bounds.y : pos.y;
-
- if (pos != Vector2()) {
- new_connect_node_select->set_position(pos);
- }
}
void VisualScriptEditor::input(const Ref<InputEvent> &p_event) {
@@ -3935,6 +3975,9 @@ void VisualScriptEditor::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+ graph->set_minimap_opacity(EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"));
+ graph->set_connection_lines_curvature(EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"));
+ _update_graph();
} break;
case NOTIFICATION_READY: {
@@ -4201,9 +4244,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
// If we still don't have a start node then,
// run through the nodes and select the first tree node,
// i.e. node without any input sequence but output sequence.
- for (RBSet<int>::Element *E = nodes_from.front(); E; E = E->next()) {
- if (!nodes_to.has(E->get())) {
- start_node = E->get();
+ for (const int &E : nodes_from) {
+ if (!nodes_to.has(E)) {
+ start_node = E;
}
}
}
@@ -4272,13 +4315,13 @@ void VisualScriptEditor::_menu_option(int p_what) {
// Move the nodes.
// Handles reconnection of sequence connections on undo, start here in case of issues.
- for (RBSet<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E->get().from_node, E->get().from_output, E->get().to_node);
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);
+ for (const VisualScript::SequenceConnection &E : seqext) {
+ undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E.from_node, E.from_output, E.to_node);
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);
}
- for (RBSet<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "data_disconnect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ for (const VisualScript::DataConnection &E : dataext) {
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);
}
// I don't really think we need support for non sequenced functions at this moment.
@@ -4286,24 +4329,24 @@ void VisualScriptEditor::_menu_option(int p_what) {
// Could fail with the new changes, start here when searching for bugs in create function shortcut.
int m = 1;
- for (RBSet<int>::Element *G = end_nodes.front(); G; G = G->next()) {
+ for (const int &G : end_nodes) {
Ref<VisualScriptReturn> ret_node;
ret_node.instantiate();
int ret_id = fn_id + (m++);
selections.insert(ret_id);
- Vector2 posi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100));
+ Vector2 posi = _get_available_pos(false, script->get_node_position(G) + Vector2(80, -100));
undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi);
undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id);
- undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id);
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", G, 0, ret_id);
// Add data outputs from each of the end_nodes.
- Ref<VisualScriptNode> vsn = script->get_node(G->get());
+ Ref<VisualScriptNode> vsn = script->get_node(G);
if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) {
ret_node->set_enable_return_value(true);
// Use the zeroth data port cause that's the likely one that is planned to be used.
ret_node->set_return_type(vsn->get_output_value_port_info(0).type);
- undo_redo->add_do_method(script.ptr(), "data_connect", G->get(), 0, ret_id, 0);
+ undo_redo->add_do_method(script.ptr(), "data_connect", G, 0, ret_id, 0);
}
}
@@ -4352,7 +4395,11 @@ void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::Sequence
}
}
-void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
+void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos, MouseButton p_button) {
+ if (p_button != MouseButton::RIGHT) {
+ return;
+ }
+
TreeItem *ti = members->get_selected();
ERR_FAIL_COND(!ti);
@@ -4553,11 +4600,11 @@ VisualScriptEditor::VisualScriptEditor() {
members_section->add_margin_child(TTR("Members:"), members, true);
members->set_custom_minimum_size(Size2(0, 50 * EDSCALE));
members->set_hide_root(true);
- members->connect("button_pressed", callable_mp(this, &VisualScriptEditor::_member_button));
+ members->connect("button_clicked", callable_mp(this, &VisualScriptEditor::_member_button));
members->connect("item_edited", callable_mp(this, &VisualScriptEditor::_member_edited));
members->connect("cell_selected", callable_mp(this, &VisualScriptEditor::_member_selected), varray(), CONNECT_DEFERRED);
members->connect("gui_input", callable_mp(this, &VisualScriptEditor::_members_gui_input));
- members->connect("item_rmb_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected));
+ members->connect("item_mouse_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected));
members->set_allow_rmb_select(true);
members->set_allow_reselect(true);
members->set_hide_folding(true);
@@ -4594,6 +4641,8 @@ VisualScriptEditor::VisualScriptEditor() {
graph->set_drag_forwarding(this);
float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
+ float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ graph->set_connection_lines_curvature(graph_lines_curvature);
graph->hide();
graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));
diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h
index c7fd8c4a78..fd59d22cbe 100644
--- a/modules/visual_script/editor/visual_script_editor.h
+++ b/modules/visual_script/editor/visual_script_editor.h
@@ -226,7 +226,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _update_available_nodes();
- void _member_button(Object *p_item, int p_column, int p_button);
+ void _member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button);
void _expression_text_changed(const String &p_text, int p_id);
void _add_input_port(int p_id);
@@ -289,7 +289,7 @@ class VisualScriptEditor : public ScriptEditorBase {
VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &p_visited_nodes);
- void _member_rmb_selected(const Vector2 &p_pos);
+ void _member_rmb_selected(const Vector2 &p_pos, MouseButton p_button);
void _member_option(int p_option);
void _toggle_scripts_pressed();
diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp
index 7557d12526..ae30655301 100644
--- a/modules/visual_script/editor/visual_script_property_selector.cpp
+++ b/modules/visual_script/editor/visual_script_property_selector.cpp
@@ -521,8 +521,17 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
results_tree->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected));
vbox->add_child(results_tree);
+ ScrollContainer *scroller = memnew(ScrollContainer);
+ scroller->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ scroller->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ scroller->set_custom_minimum_size(Size2(600, 400) * EDSCALE);
+ vbox->add_child(scroller);
+
help_bit = memnew(EditorHelpBit);
- vbox->add_child(help_bit);
+ help_bit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ help_bit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ scroller->add_child(help_bit);
+
help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested));
get_ok_button()->set_text(TTR("Open"));
get_ok_button()->set_disabled(true);
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index a287b8e69f..30b64d0a7b 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -230,12 +230,12 @@ void VisualScript::_node_ports_changed(int p_id) {
{
List<SequenceConnection> to_remove;
- for (RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
- if (E->get().from_node == p_id && E->get().from_output >= vsn->get_output_sequence_port_count()) {
- to_remove.push_back(E->get());
+ for (const SequenceConnection &E : sequence_connections) {
+ if (E.from_node == p_id && E.from_output >= vsn->get_output_sequence_port_count()) {
+ to_remove.push_back(E);
}
- if (E->get().to_node == p_id && !vsn->has_input_sequence_port()) {
- to_remove.push_back(E->get());
+ if (E.to_node == p_id && !vsn->has_input_sequence_port()) {
+ to_remove.push_back(E);
}
}
@@ -248,12 +248,12 @@ void VisualScript::_node_ports_changed(int p_id) {
{
List<DataConnection> to_remove;
- for (RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (E->get().from_node == p_id && E->get().from_port >= vsn->get_output_value_port_count()) {
- to_remove.push_back(E->get());
+ for (const DataConnection &E : data_connections) {
+ if (E.from_node == p_id && E.from_port >= vsn->get_output_value_port_count()) {
+ to_remove.push_back(E);
}
- if (E->get().to_node == p_id && E->get().to_port >= vsn->get_input_value_port_count()) {
- to_remove.push_back(E->get());
+ if (E.to_node == p_id && E.to_port >= vsn->get_input_value_port_count()) {
+ to_remove.push_back(E);
}
}
@@ -292,9 +292,9 @@ void VisualScript::remove_node(int p_id) {
{
List<SequenceConnection> to_remove;
- for (RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
- if (E->get().from_node == p_id || E->get().to_node == p_id) {
- to_remove.push_back(E->get());
+ for (const SequenceConnection &E : sequence_connections) {
+ if (E.from_node == p_id || E.to_node == p_id) {
+ to_remove.push_back(E);
}
}
@@ -307,9 +307,9 @@ void VisualScript::remove_node(int p_id) {
{
List<DataConnection> to_remove;
- for (RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (E->get().from_node == p_id || E->get().to_node == p_id) {
- to_remove.push_back(E->get());
+ for (const DataConnection &E : data_connections) {
+ if (E.from_node == p_id || E.to_node == p_id) {
+ to_remove.push_back(E);
}
}
@@ -384,8 +384,8 @@ bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, i
}
void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const {
- for (const RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
- r_connection->push_back(E->get());
+ for (const SequenceConnection &E : sequence_connections) {
+ r_connection->push_back(E);
}
}
@@ -426,8 +426,8 @@ bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_t
}
bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
- for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (E->get().to_node == p_node && E->get().to_port == p_port) {
+ for (const DataConnection &E : data_connections) {
+ if (E.to_node == p_node && E.to_port == p_port) {
return true;
}
}
@@ -435,10 +435,10 @@ bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
}
bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const {
- for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (E->get().to_node == p_node && E->get().to_port == p_port) {
- *r_node = E->get().from_node;
- *r_port = E->get().from_port;
+ for (const DataConnection &E : data_connections) {
+ if (E.to_node == p_node && E.to_port == p_port) {
+ *r_node = E.from_node;
+ *r_port = E.from_port;
return true;
}
}
@@ -446,8 +446,8 @@ bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port
}
void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const {
- for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- r_connection->push_back(E->get());
+ for (const DataConnection &E : data_connections) {
+ r_connection->push_back(E);
}
}
@@ -764,8 +764,8 @@ void VisualScript::_update_placeholders() {
values[p.name] = variables[E.key].default_value;
}
- for (RBSet<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->update(pinfo, values);
+ for (PlaceHolderScriptInstance *E : placeholders) {
+ E->update(pinfo, values);
}
}
@@ -1078,19 +1078,19 @@ Dictionary VisualScript::_get_data() const {
d["nodes"] = nds;
Array seqconns;
- for (const RBSet<SequenceConnection>::Element *F = sequence_connections.front(); F; F = F->next()) {
- seqconns.push_back(F->get().from_node);
- seqconns.push_back(F->get().from_output);
- seqconns.push_back(F->get().to_node);
+ for (const SequenceConnection &F : sequence_connections) {
+ seqconns.push_back(F.from_node);
+ seqconns.push_back(F.from_output);
+ seqconns.push_back(F.to_node);
}
d["sequence_connections"] = seqconns;
Array dataconns;
- for (const RBSet<DataConnection>::Element *F = data_connections.front(); F; F = F->next()) {
- dataconns.push_back(F->get().from_node);
- dataconns.push_back(F->get().from_port);
- dataconns.push_back(F->get().to_node);
- dataconns.push_back(F->get().to_port);
+ for (const DataConnection &F : data_connections) {
+ dataconns.push_back(F.from_node);
+ dataconns.push_back(F.from_port);
+ dataconns.push_back(F.to_node);
+ dataconns.push_back(F.to_port);
}
d["data_connections"] = dataconns;
@@ -1528,7 +1528,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
// If no exit bit was set, and has sequence outputs, guess next node.
if (output >= node->sequence_output_count) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Node returned an invalid sequence output: ") + itos(output);
+ error_str = RTR("Node returned an invalid sequence output:") + " " + itos(output);
error = true;
break;
}
@@ -1594,7 +1594,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
// Check for stack overflow.
if (flow_stack_pos + 1 >= flow_max) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Stack overflow with stack depth: ") + itos(output);
+ error_str = RTR("Stack overflow with stack depth:") + " " + itos(output);
error = true;
break;
}
@@ -1869,23 +1869,23 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
List<int> nd_queue;
nd_queue.push_back(function.node);
while (!nd_queue.is_empty()) {
- for (const RBSet<VisualScript::SequenceConnection>::Element *F = script->sequence_connections.front(); F; F = F->next()) {
- if (nd_queue.front()->get() == F->get().from_node && !node_ids.has(F->get().to_node)) {
- nd_queue.push_back(F->get().to_node);
- node_ids.insert(F->get().to_node);
+ for (const VisualScript::SequenceConnection &F : script->sequence_connections) {
+ if (nd_queue.front()->get() == F.from_node && !node_ids.has(F.to_node)) {
+ nd_queue.push_back(F.to_node);
+ node_ids.insert(F.to_node);
}
- if (nd_queue.front()->get() == F->get().from_node && !seqconns.has(F->get())) {
- seqconns.insert(F->get());
+ if (nd_queue.front()->get() == F.from_node && !seqconns.has(F)) {
+ seqconns.insert(F);
}
}
nd_queue.pop_front();
}
HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port)
- for (const RBSet<VisualScript::DataConnection>::Element *F = script->data_connections.front(); F; F = F->next()) {
- dc_lut[F->get().to_node][F->get().to_port] = Pair<int, int>(F->get().from_node, F->get().from_port);
+ for (const VisualScript::DataConnection &F : script->data_connections) {
+ dc_lut[F.to_node][F.to_port] = Pair<int, int>(F.from_node, F.from_port);
}
- for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
- nd_queue.push_back(F->get());
+ for (const int &F : node_ids) {
+ nd_queue.push_back(F);
}
List<int> dc_keys;
while (!nd_queue.is_empty()) {
@@ -1907,15 +1907,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
//Multiple passes are required to set up this complex thing..
//First create the nodes.
- for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
- Ref<VisualScriptNode> node = script->nodes[F->get()].node;
+ for (const int &F : node_ids) {
+ Ref<VisualScriptNode> node = script->nodes[F].node;
VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance.
ERR_FAIL_COND(!instance);
instance->base = node.ptr();
- instance->id = F->get();
+ instance->id = F;
instance->input_port_count = node->get_input_value_port_count();
instance->input_ports = nullptr;
instance->output_port_count = node->get_output_value_port_count();
@@ -1975,14 +1975,14 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
max_input_args = MAX(max_input_args, instance->input_port_count);
max_output_args = MAX(max_output_args, instance->output_port_count);
- instances[F->get()] = instance;
+ instances[F] = instance;
}
function.trash_pos = function.max_stack++; // create pos for trash
// Second pass, do data connections.
- for (const RBSet<VisualScript::DataConnection>::Element *F = dataconns.front(); F; F = F->next()) {
- VisualScript::DataConnection dc = F->get();
+ for (const VisualScript::DataConnection &F : dataconns) {
+ VisualScript::DataConnection dc = F;
ERR_CONTINUE(!instances.has(dc.from_node));
VisualScriptNodeInstance *from = instances[dc.from_node];
ERR_CONTINUE(!instances.has(dc.to_node));
@@ -2008,8 +2008,8 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
}
// Third pass, do sequence connections.
- for (const RBSet<VisualScript::SequenceConnection>::Element *F = seqconns.front(); F; F = F->next()) {
- VisualScript::SequenceConnection sc = F->get();
+ for (const VisualScript::SequenceConnection &F : seqconns) {
+ VisualScript::SequenceConnection sc = F;
ERR_CONTINUE(!instances.has(sc.from_node));
VisualScriptNodeInstance *from = instances[sc.from_node];
ERR_CONTINUE(!instances.has(sc.to_node));
@@ -2022,11 +2022,11 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
//fourth pass:
// 1) unassigned input ports to default values
// 2) connect unassigned output ports to trash
- for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
- ERR_CONTINUE(!instances.has(F->get()));
+ for (const int &F : node_ids) {
+ ERR_CONTINUE(!instances.has(F));
- Ref<VisualScriptNode> node = script->nodes[F->get()].node;
- VisualScriptNodeInstance *instance = instances[F->get()];
+ Ref<VisualScriptNode> node = script->nodes[F].node;
+ VisualScriptNodeInstance *instance = instances[F];
// Connect to default values.
for (int i = 0; i < instance->input_port_count; i++) {
@@ -2223,7 +2223,7 @@ Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const
return script;
}
-bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, RBSet<int> *r_safe_lines) const {
+bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const {
return false;
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index c28ec2268b..0f3b8de3fc 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -36,6 +36,7 @@
#include "core/doc_data.h"
#include "core/object/script_language.h"
#include "core/os/thread.h"
+#include "core/templates/rb_set.h"
class VisualScriptInstance;
class VisualScriptNodeInstance;
@@ -570,7 +571,7 @@ public:
virtual void get_string_delimiters(List<String> *p_delimiters) const override;
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
virtual bool has_named_classes() const override;
virtual bool supports_builtin_mode() const override;
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index 0e63753720..bbbb995635 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -391,7 +391,7 @@ public:
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Input type not iterable: ") + Variant::get_type_name(p_inputs[0]->get_type());
+ r_error_str = RTR("Input type not iterable:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
return 0;
}
@@ -414,7 +414,7 @@ public:
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Iterator became invalid: ") + Variant::get_type_name(p_inputs[0]->get_type());
+ r_error_str = RTR("Iterator became invalid:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
return 0;
}
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index ac33526ddc..2dfc6da181 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -1116,9 +1116,9 @@ public:
r_error_str = *p_outputs[0];
} else {
if (unary) {
- r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid argument of type: ") + Variant::get_type_name(p_inputs[0]->get_type());
+ r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid argument of type:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
} else {
- r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid arguments: ") + "A: " + Variant::get_type_name(p_inputs[0]->get_type()) + " B: " + Variant::get_type_name(p_inputs[1]->get_type());
+ r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid arguments:") + " A: " + Variant::get_type_name(p_inputs[0]->get_type()) + ", B: " + Variant::get_type_name(p_inputs[1]->get_type());
}
}
}
@@ -1335,7 +1335,7 @@ public:
virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->get_variable(variable, p_outputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("VariableGet not found in script: ") + "'" + String(variable) + "'";
+ r_error_str = RTR("VariableGet not found in script:") + " '" + String(variable) + "'";
return 0;
}
return 0;
@@ -1447,7 +1447,7 @@ public:
virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->set_variable(variable, *p_inputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("VariableSet not found in script: ") + "'" + String(variable) + "'";
+ r_error_str = RTR("VariableSet not found in script:") + " '" + String(variable) + "'";
}
return 0;
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
index b4d97077e3..fed67397d1 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
@@ -95,6 +95,13 @@
Call this method frequently (e.g. in [method Node._process] or [method Node._physics_process]) to properly receive signals.
</description>
</method>
+ <method name="set_default_extension" qualifiers="static">
+ <return type="void" />
+ <argument index="0" name="extension_class" type="StringName" />
+ <description>
+ Sets the [code]extension_class[/code] as the default [WebRTCPeerConnectionExtension] returned when creating a new [WebRTCPeerConnection].
+ </description>
+ </method>
<method name="set_local_description">
<return type="int" enum="Error" />
<argument index="0" name="type" type="String" />
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
index e88acdc845..163d939ac1 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -62,10 +62,5 @@
<description>
</description>
</method>
- <method name="make_default">
- <return type="void" />
- <description>
- </description>
- </method>
</methods>
</class>
diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h
index eac8f85a84..75e29283ec 100644
--- a/modules/webrtc/webrtc_data_channel.h
+++ b/modules/webrtc/webrtc_data_channel.h
@@ -33,7 +33,7 @@
#include "core/io/packet_peer.h"
-#define WRTC_IN_BUF "network/limits/webrtc/max_channel_in_buffer_kb"
+#define WRTC_IN_BUF PNAME("network/limits/webrtc/max_channel_in_buffer_kb")
class WebRTCDataChannel : public PacketPeer {
GDCLASS(WebRTCDataChannel, PacketPeer);
diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp
index 7fdf26d3cd..75716017d7 100644
--- a/modules/webrtc/webrtc_peer_connection.cpp
+++ b/modules/webrtc/webrtc_peer_connection.cpp
@@ -32,13 +32,14 @@
#ifdef JAVASCRIPT_ENABLED
#include "webrtc_peer_connection_js.h"
-#else
-#include "webrtc_peer_connection_extension.h"
#endif
+#include "webrtc_peer_connection_extension.h"
+
StringName WebRTCPeerConnection::default_extension;
void WebRTCPeerConnection::set_default_extension(const StringName &p_extension) {
+ ERR_FAIL_COND_MSG(!ClassDB::is_parent_class(p_extension, WebRTCPeerConnectionExtension::get_class_static()), vformat("Can't make %s the default WebRTC extension since it does not extend WebRTCPeerConnectionExtension.", p_extension));
default_extension = p_extension;
}
@@ -56,6 +57,8 @@ WebRTCPeerConnection *WebRTCPeerConnection::create() {
}
void WebRTCPeerConnection::_bind_methods() {
+ ClassDB::bind_static_method(get_class_static(), D_METHOD("set_default_extension", "extension_class"), &WebRTCPeerConnectionExtension::set_default_extension);
+
ClassDB::bind_method(D_METHOD("initialize", "configuration"), &WebRTCPeerConnection::initialize, DEFVAL(Dictionary()));
ClassDB::bind_method(D_METHOD("create_data_channel", "label", "options"), &WebRTCPeerConnection::create_data_channel, DEFVAL(Dictionary()));
ClassDB::bind_method(D_METHOD("create_offer"), &WebRTCPeerConnection::create_offer);
diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp
index 3bc7de217e..85c04b3b19 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.cpp
+++ b/modules/webrtc/webrtc_peer_connection_extension.cpp
@@ -31,8 +31,6 @@
#include "webrtc_peer_connection_extension.h"
void WebRTCPeerConnectionExtension::_bind_methods() {
- ClassDB::bind_method(D_METHOD("make_default"), &WebRTCPeerConnectionExtension::make_default);
-
GDVIRTUAL_BIND(_get_connection_state);
GDVIRTUAL_BIND(_initialize, "p_config");
GDVIRTUAL_BIND(_create_data_channel, "p_label", "p_config");
@@ -44,11 +42,6 @@ void WebRTCPeerConnectionExtension::_bind_methods() {
GDVIRTUAL_BIND(_close);
}
-void WebRTCPeerConnectionExtension::make_default() {
- ERR_FAIL_COND_MSG(!_get_extension(), vformat("Can't make %s the default without extending it.", get_class()));
- WebRTCPeerConnection::set_default_extension(get_class());
-}
-
WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionExtension::get_connection_state() const {
int state;
if (GDVIRTUAL_CALL(_get_connection_state, state)) {
diff --git a/modules/webrtc/webrtc_peer_connection_extension.h b/modules/webrtc/webrtc_peer_connection_extension.h
index 82e32b5602..bde19c173b 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.h
+++ b/modules/webrtc/webrtc_peer_connection_extension.h
@@ -44,8 +44,6 @@ protected:
static void _bind_methods();
public:
- void make_default();
-
virtual ConnectionState get_connection_state() const override;
virtual Error initialize(Dictionary p_config = Dictionary()) override;