summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md3
-rw-r--r--.github/workflows/static_checks.yml4
-rw-r--r--core/config/project_settings.cpp28
-rw-r--r--core/config/project_settings.h1
-rw-r--r--core/doc_data.cpp2
-rw-r--r--core/doc_data.h25
-rw-r--r--core/extension/gdextension_interface.h6
-rw-r--r--core/input/input.cpp2
-rw-r--r--core/input/input_event.cpp4
-rw-r--r--core/io/file_access.cpp5
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/ip.h1
-rw-r--r--core/io/resource_format_binary.cpp9
-rw-r--r--core/io/xml_parser.cpp2
-rw-r--r--core/io/xml_parser.h2
-rw-r--r--core/math/delaunay_2d.h2
-rw-r--r--core/object/object.cpp24
-rw-r--r--core/object/object.h12
-rw-r--r--core/object/script_language.h2
-rw-r--r--core/object/undo_redo.cpp12
-rw-r--r--core/os/keyboard.cpp29
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/time.cpp3
-rw-r--r--core/os/time.h3
-rw-r--r--core/variant/variant_internal.h2
-rw-r--r--core/variant/variant_op.cpp33
-rw-r--r--core/variant/variant_op.h6
-rw-r--r--doc/class.xsd9
-rw-r--r--doc/classes/ArrayMesh.xml4
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/Callable.xml11
-rw-r--r--doc/classes/CanvasItem.xml12
-rw-r--r--doc/classes/Control.xml4
-rw-r--r--doc/classes/DisplayServer.xml9
-rw-r--r--doc/classes/EditorInspectorPlugin.xml2
-rw-r--r--doc/classes/EditorSettings.xml3
-rw-r--r--doc/classes/EditorSpinSlider.xml2
-rw-r--r--doc/classes/Font.xml20
-rw-r--r--doc/classes/FontFile.xml2
-rw-r--r--doc/classes/ImageFormatLoaderExtension.xml2
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml2
-rw-r--r--doc/classes/Label.xml4
-rw-r--r--doc/classes/Label3D.xml2
-rw-r--r--doc/classes/NavigationAgent2D.xml2
-rw-r--r--doc/classes/NavigationAgent3D.xml2
-rw-r--r--doc/classes/NavigationMeshGenerator.xml24
-rw-r--r--doc/classes/NavigationMeshSourceGeometryData3D.xml77
-rw-r--r--doc/classes/NavigationPathQueryParameters2D.xml2
-rw-r--r--doc/classes/NavigationPathQueryParameters3D.xml2
-rw-r--r--doc/classes/NavigationServer2D.xml32
-rw-r--r--doc/classes/NavigationServer3D.xml52
-rw-r--r--doc/classes/Node.xml14
-rw-r--r--doc/classes/PackedColorArray.xml4
-rw-r--r--doc/classes/PackedVector2Array.xml4
-rw-r--r--doc/classes/PackedVector3Array.xml4
-rw-r--r--doc/classes/RDTextureFormat.xml2
-rw-r--r--doc/classes/Range.xml2
-rw-r--r--doc/classes/RenderingDevice.xml26
-rw-r--r--doc/classes/RenderingServer.xml18
-rw-r--r--doc/classes/ResourceSaver.xml2
-rw-r--r--doc/classes/RichTextLabel.xml2
-rw-r--r--doc/classes/SceneTree.xml2
-rw-r--r--doc/classes/SpinBox.xml2
-rw-r--r--doc/classes/TextEdit.xml3
-rw-r--r--doc/classes/TextLine.xml2
-rw-r--r--doc/classes/TextMesh.xml2
-rw-r--r--doc/classes/TextParagraph.xml4
-rw-r--r--doc/classes/TextServer.xml14
-rw-r--r--doc/classes/TextServerExtension.xml14
-rw-r--r--doc/classes/TextureProgressBar.xml2
-rw-r--r--doc/classes/Tween.xml2
-rw-r--r--doc/classes/VScrollBar.xml4
-rw-r--r--doc/classes/VSlider.xml4
-rwxr-xr-xdoc/tools/make_rst.py23
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp59
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp122
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h1
-rw-r--r--drivers/gles3/storage/light_storage.cpp100
-rw-r--r--drivers/gles3/storage/material_storage.cpp4
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp56
-rw-r--r--drivers/gles3/storage/particles_storage.cpp44
-rw-r--r--drivers/gles3/storage/texture_storage.cpp84
-rw-r--r--drivers/gles3/storage/texture_storage.h6
-rw-r--r--drivers/gles3/storage/utilities.cpp38
-rw-r--r--drivers/gles3/storage/utilities.h64
-rw-r--r--drivers/unix/file_access_unix.cpp4
-rw-r--r--drivers/vulkan/vulkan_context.cpp1
-rw-r--r--editor/code_editor.cpp1
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp6
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.h6
-rw-r--r--editor/doc_tools.cpp25
-rw-r--r--editor/editor_file_system.cpp2
-rw-r--r--editor/editor_help.cpp24
-rw-r--r--editor/editor_help.h2
-rw-r--r--editor/editor_inspector.cpp5
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/editor_plugin.cpp9
-rw-r--r--editor/editor_properties_array_dict.cpp6
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/export/editor_export_platform.cpp5
-rw-r--r--editor/export/editor_export_platform.h4
-rw-r--r--editor/export/editor_export_platform_pc.cpp2
-rw-r--r--editor/export/editor_export_platform_pc.h2
-rw-r--r--editor/gui/editor_object_selector.cpp1
-rw-r--r--editor/gui/editor_spin_slider.cpp2
-rw-r--r--editor/gui/scene_tree_editor.cpp117
-rw-r--r--editor/gui/scene_tree_editor.h2
-rw-r--r--editor/import/resource_importer_csv_translation.cpp11
-rw-r--r--editor/import/resource_importer_scene.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_text_editor.cpp2
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp2
-rw-r--r--editor/rename_dialog.cpp6
-rw-r--r--editor/scene_tree_dock.cpp7
-rw-r--r--main/main.cpp19
-rw-r--r--misc/extension_api_validation/4.0-stable.expected4
-rwxr-xr-xmisc/scripts/codespell.sh2
-rw-r--r--modules/basis_universal/register_types.cpp59
-rw-r--r--modules/camera/camera_macos.mm1
-rw-r--r--modules/csg/csg_shape.h4
-rw-r--r--modules/csg/editor/csg_gizmos.h1
-rw-r--r--modules/cvtt/register_types.cpp2
-rw-r--r--modules/denoise/denoise_wrapper.cpp4
-rw-r--r--modules/denoise/lightmap_denoiser.cpp1
-rw-r--r--modules/denoise/register_types.cpp4
-rw-r--r--modules/enet/enet_connection.h4
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp1
-rw-r--r--modules/enet/enet_multiplayer_peer.h3
-rw-r--r--modules/enet/register_types.cpp4
-rw-r--r--modules/etcpak/register_types.h2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml8
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp1
-rw-r--r--modules/gdscript/editor/gdscript_docgen.h1
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp2
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp3
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h3
-rw-r--r--modules/gdscript/gdscript.cpp315
-rw-r--r--modules/gdscript/gdscript.h4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp109
-rw-r--r--modules/gdscript/gdscript_analyzer.h9
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp17
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h5
-rw-r--r--modules/gdscript/gdscript_cache.cpp11
-rw-r--r--modules/gdscript/gdscript_cache.h3
-rw-r--r--modules/gdscript/gdscript_codegen.h8
-rw-r--r--modules/gdscript/gdscript_compiler.cpp172
-rw-r--r--modules/gdscript/gdscript_compiler.h3
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp34
-rw-r--r--modules/gdscript/gdscript_editor.cpp43
-rw-r--r--modules/gdscript/gdscript_function.h10
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp3
-rw-r--r--modules/gdscript/gdscript_parser.cpp45
-rw-r--r--modules/gdscript/gdscript_parser.h12
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp81
-rw-r--r--modules/gdscript/gdscript_tokenizer.h2
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp3
-rw-r--r--modules/gdscript/gdscript_vm.cpp52
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h3
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h7
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h3
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp5
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h3
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp3
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h5
-rw-r--r--modules/gdscript/register_types.cpp40
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h1
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd347
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out229
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd17
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out16
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_separators.gd32
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_separators.out23
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.gd10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.out3
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.gd58
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.out25
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.gd17
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.out3
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_variables.gd18
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_variables.out18
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_variables_2.gd56
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_variables_2.out15
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp10
-rw-r--r--modules/gdscript/tests/test_gdscript.h1
-rw-r--r--modules/glslang/register_types.cpp4
-rw-r--r--modules/gltf/config.py2
-rw-r--r--modules/gltf/doc_classes/GLTFCollider.xml65
-rw-r--r--modules/gltf/doc_classes/GLTFPhysicsShape.xml65
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp4
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.h3
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp4
-rw-r--r--modules/gltf/extensions/physics/gltf_document_extension_physics.cpp22
-rw-r--r--modules/gltf/extensions/physics/gltf_document_extension_physics.h3
-rw-r--r--modules/gltf/extensions/physics/gltf_physics_shape.cpp (renamed from modules/gltf/extensions/physics/gltf_collider.cpp)195
-rw-r--r--modules/gltf/extensions/physics/gltf_physics_shape.h (renamed from modules/gltf/extensions/physics/gltf_collider.h)19
-rw-r--r--modules/gltf/register_types.cpp7
-rw-r--r--modules/gltf/structures/gltf_accessor.h1
-rw-r--r--modules/gltf/structures/gltf_buffer_view.h1
-rw-r--r--modules/gltf/structures/gltf_mesh.h1
-rw-r--r--modules/gltf/structures/gltf_node.h1
-rw-r--r--modules/gltf/structures/gltf_skeleton.cpp1
-rw-r--r--modules/gltf/structures/gltf_skeleton.h1
-rw-r--r--modules/gltf/structures/gltf_skin.cpp1
-rw-r--r--modules/gltf/structures/gltf_skin.h1
-rw-r--r--modules/gltf/structures/gltf_texture.h1
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h1
-rw-r--r--modules/gridmap/register_types.cpp3
-rw-r--r--modules/jpg/image_loader_jpegd.cpp1
-rw-r--r--modules/jsonrpc/register_types.cpp4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp5
-rw-r--r--modules/lightmapper_rd/register_types.cpp3
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp10
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.cpp1
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.h3
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.h3
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.h3
-rw-r--r--modules/mbedtls/tests/test_crypto_mbedtls.cpp3
-rw-r--r--modules/mbedtls/tls_context_mbedtls.h1
-rw-r--r--modules/meshoptimizer/register_types.cpp2
-rw-r--r--modules/minimp3/audio_stream_mp3.h2
-rw-r--r--modules/minimp3/register_types.cpp5
-rw-r--r--modules/minimp3/resource_importer_mp3.h1
-rw-r--r--modules/mono/csharp_script.cpp46
-rw-r--r--modules/mono/csharp_script.h6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs25
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs25
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs22
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs9
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs18
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs2
-rw-r--r--modules/mono/editor/bindings_generator.cpp10
-rw-r--r--modules/mono/editor/bindings_generator.h9
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp23
-rw-r--r--modules/mono/editor/hostfxr_resolver.cpp6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs20
-rw-r--r--modules/mono/glue/runtime_interop.cpp15
-rw-r--r--modules/mono/godotsharp_dirs.cpp16
-rw-r--r--modules/mono/managed_callable.h4
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp39
-rw-r--r--modules/mono/mono_gd/gd_mono.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h5
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp26
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm6
-rw-r--r--modules/mono/register_types.cpp4
-rw-r--r--modules/mono/signal_awaiter_utils.h4
-rw-r--r--modules/mono/utils/path_utils.cpp36
-rw-r--r--modules/mono/utils/path_utils.h3
-rw-r--r--modules/multiplayer/editor/editor_network_profiler.h4
-rw-r--r--modules/multiplayer/editor/multiplayer_editor_plugin.h1
-rw-r--r--modules/multiplayer/editor/replication_editor.h3
-rw-r--r--modules/multiplayer/multiplayer_debugger.h1
-rw-r--r--modules/multiplayer/multiplayer_spawner.h5
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.h4
-rw-r--r--modules/multiplayer/register_types.cpp3
-rw-r--r--modules/multiplayer/scene_cache_interface.cpp4
-rw-r--r--modules/multiplayer/scene_multiplayer.cpp4
-rw-r--r--modules/multiplayer/scene_multiplayer.h4
-rw-r--r--modules/multiplayer/scene_replication_config.h1
-rw-r--r--modules/multiplayer/scene_replication_interface.h4
-rw-r--r--modules/multiplayer/scene_rpc_interface.cpp4
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp7
-rw-r--r--modules/navigation/godot_navigation_server.cpp49
-rw-r--r--modules/navigation/godot_navigation_server.h17
-rw-r--r--modules/navigation/nav_agent.cpp20
-rw-r--r--modules/navigation/nav_agent.h9
-rw-r--r--modules/navigation/nav_base.h1
-rw-r--r--modules/navigation/nav_map.cpp16
-rw-r--r--modules/navigation/nav_map.h6
-rw-r--r--modules/navigation/nav_obstacle.cpp22
-rw-r--r--modules/navigation/nav_obstacle.h7
-rw-r--r--modules/navigation/nav_region.h4
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp320
-rw-r--r--modules/navigation/navigation_mesh_generator.h27
-rw-r--r--modules/navigation/register_types.cpp6
-rw-r--r--modules/noise/editor/noise_editor_plugin.cpp6
-rw-r--r--modules/noise/fastnoise_lite.h3
-rw-r--r--modules/noise/noise_texture_2d.cpp3
-rw-r--r--modules/noise/noise_texture_3d.cpp3
-rw-r--r--modules/noise/register_types.cpp5
-rw-r--r--modules/noise/tests/test_fastnoise_lite.h4
-rw-r--r--modules/noise/tests/test_noise_texture_2d.h4
-rw-r--r--modules/noise/tests/test_noise_texture_3d.h4
-rw-r--r--modules/ogg/ogg_packet_sequence.cpp1
-rw-r--r--modules/openxr/action_map/openxr_action.cpp1
-rw-r--r--modules/openxr/action_map/openxr_action_map.h4
-rw-r--r--modules/openxr/action_map/openxr_action_set.h4
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.h4
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp1
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_meta_data.h4
-rw-r--r--modules/openxr/editor/openxr_action_editor.h1
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h6
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp1
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h1
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.cpp1
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.h3
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp1
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h4
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.cpp1
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.h1
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.h1
-rw-r--r--modules/openxr/extensions/openxr_android_extension.cpp4
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_provider.h1
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h1
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h1
-rw-r--r--modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h1
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.cpp2
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.h3
-rw-r--r--modules/openxr/extensions/openxr_htc_controller_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp2
-rw-r--r--modules/openxr/extensions/openxr_huawei_controller_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_ml2_controller_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.cpp4
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.h9
-rw-r--r--modules/openxr/extensions/openxr_palm_pose_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_pico_controller_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp5
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h11
-rw-r--r--modules/openxr/extensions/openxr_wmr_controller_extension.cpp1
-rw-r--r--modules/openxr/openxr_api.cpp11
-rw-r--r--modules/openxr/openxr_api.h13
-rw-r--r--modules/openxr/openxr_interface.h7
-rw-r--r--modules/openxr/openxr_util.cpp1
-rw-r--r--modules/openxr/openxr_util.h1
-rw-r--r--modules/openxr/register_types.cpp30
-rw-r--r--modules/openxr/scene/openxr_hand.cpp3
-rw-r--r--modules/openxr/scene/openxr_hand.h2
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp1
-rw-r--r--modules/raycast/static_raycaster_embree.cpp4
-rw-r--r--modules/regex/regex.cpp1
-rw-r--r--modules/regex/regex.h2
-rw-r--r--modules/regex/register_types.cpp4
-rw-r--r--modules/regex/tests/test_regex.h3
-rw-r--r--modules/text_server_adv/icu_data/icudata_stub.cpp6
-rw-r--r--modules/text_server_adv/text_server_adv.cpp8
-rw-r--r--modules/text_server_adv/text_server_adv.h7
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp3
-rw-r--r--modules/text_server_fb/text_server_fb.cpp8
-rw-r--r--modules/text_server_fb/text_server_fb.h3
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp3
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp1
-rw-r--r--modules/upnp/register_types.cpp4
-rw-r--r--modules/upnp/upnp.h4
-rw-r--r--modules/vhacd/register_types.cpp2
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp6
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.h1
-rw-r--r--modules/webp/image_loader_webp.cpp6
-rw-r--r--modules/webp/resource_saver_webp.cpp3
-rw-r--r--modules/webp/webp_common.cpp3
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml2
-rw-r--r--modules/webrtc/register_types.cpp7
-rw-r--r--modules/webrtc/webrtc_data_channel.cpp1
-rw-r--r--modules/webrtc/webrtc_data_channel_js.cpp6
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h3
-rw-r--r--modules/webrtc/webrtc_peer_connection.h3
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.cpp11
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.h7
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.cpp6
-rw-r--r--modules/websocket/editor/editor_debugger_server_websocket.cpp1
-rw-r--r--modules/websocket/emws_peer.cpp4
-rw-r--r--modules/websocket/emws_peer.h8
-rw-r--r--modules/websocket/register_types.cpp16
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h4
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h3
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h6
-rw-r--r--modules/webxr/godot_webxr.h2
-rw-r--r--modules/webxr/webxr_interface.cpp1
-rw-r--r--modules/webxr/webxr_interface_js.cpp7
-rw-r--r--modules/xatlas_unwrap/register_types.cpp4
-rw-r--r--modules/zip/register_types.cpp3
-rw-r--r--platform/android/display_server_android.cpp4
-rw-r--r--platform/android/display_server_android.h1
-rw-r--r--platform/android/export/export_plugin.cpp11
-rw-r--r--platform/android/export/export_plugin.h2
-rw-r--r--platform/android/java/app/AndroidManifest.xml2
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt27
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java29
-rw-r--r--platform/ios/display_server_ios.h1
-rw-r--r--platform/ios/display_server_ios.mm4
-rw-r--r--platform/ios/export/export_plugin.cpp2
-rw-r--r--platform/ios/export/export_plugin.h2
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp45
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp9
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h1
-rw-r--r--platform/macos/display_server_macos.h2
-rw-r--r--platform/macos/display_server_macos.mm9
-rw-r--r--platform/macos/export/export_plugin.cpp2
-rw-r--r--platform/macos/export/export_plugin.h2
-rw-r--r--platform/macos/export/lipo.cpp30
-rw-r--r--platform/macos/godot_window_delegate.mm11
-rw-r--r--platform/uwp/export/export_plugin.cpp2
-rw-r--r--platform/uwp/export/export_plugin.h2
-rw-r--r--platform/web/display_server_web.cpp4
-rw-r--r--platform/web/display_server_web.h1
-rw-r--r--platform/web/export/export_plugin.cpp2
-rw-r--r--platform/web/export/export_plugin.h2
-rw-r--r--platform/windows/display_server_windows.cpp9
-rw-r--r--platform/windows/display_server_windows.h1
-rw-r--r--platform/windows/export/export_plugin.cpp4
-rw-r--r--platform/windows/export/export_plugin.h2
-rw-r--r--platform/windows/gl_manager_windows.cpp2
-rw-r--r--scene/2d/line_2d.cpp5
-rw-r--r--scene/2d/line_2d.h5
-rw-r--r--scene/2d/navigation_agent_2d.cpp17
-rw-r--r--scene/2d/navigation_agent_2d.h3
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp2
-rw-r--r--scene/2d/navigation_region_2d.cpp178
-rw-r--r--scene/2d/navigation_region_2d.h8
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/navigation_agent_3d.cpp16
-rw-r--r--scene/3d/navigation_agent_3d.h3
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp2
-rw-r--r--scene/3d/navigation_region_3d.cpp37
-rw-r--r--scene/3d/navigation_region_3d.h2
-rw-r--r--scene/3d/node_3d.cpp16
-rw-r--r--scene/3d/node_3d.h1
-rw-r--r--scene/3d/path_3d.cpp2
-rw-r--r--scene/3d/vehicle_body_3d.cpp12
-rw-r--r--scene/gui/base_button.cpp8
-rw-r--r--scene/gui/code_edit.cpp4
-rw-r--r--scene/gui/dialogs.cpp35
-rw-r--r--scene/gui/dialogs.h3
-rw-r--r--scene/gui/menu_bar.cpp1
-rw-r--r--scene/gui/menu_button.cpp14
-rw-r--r--scene/gui/popup_menu.cpp4
-rw-r--r--scene/gui/popup_menu.h3
-rw-r--r--scene/gui/rich_text_label.cpp130
-rw-r--r--scene/gui/rich_text_label.h1
-rw-r--r--scene/gui/text_edit.cpp104
-rw-r--r--scene/gui/text_edit.h7
-rw-r--r--scene/main/node.cpp11
-rw-r--r--scene/main/node.h4
-rw-r--r--scene/main/scene_tree.cpp16
-rw-r--r--scene/main/scene_tree.h8
-rw-r--r--scene/main/window.cpp8
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/navigation_mesh_source_geometry_data_3d.cpp181
-rw-r--r--scene/resources/navigation_mesh_source_geometry_data_3d.h75
-rw-r--r--scene/resources/packed_scene.cpp5
-rw-r--r--scene/resources/texture.cpp6
-rw-r--r--scene/resources/tile_set.cpp4
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/display_server_headless.h1
-rw-r--r--servers/navigation_server_2d.cpp8
-rw-r--r--servers/navigation_server_2d.h8
-rw-r--r--servers/navigation_server_3d.cpp7
-rw-r--r--servers/navigation_server_3d.h13
-rw-r--r--servers/navigation_server_3d_dummy.h6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp11
-rw-r--r--servers/rendering/renderer_viewport.cpp2
-rw-r--r--servers/rendering/renderer_viewport.h2
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--tests/core/io/test_file_access.h10
-rw-r--r--tests/core/string/test_translation.h32
-rw-r--r--tests/core/variant/test_variant.h16
-rw-r--r--tests/data/testdata.csv8
-rw-r--r--tests/data/translations.csv11
-rw-r--r--tests/scene/test_code_edit.h6
-rw-r--r--tests/scene/test_navigation_obstacle_2d.h69
-rw-r--r--tests/scene/test_navigation_obstacle_3d.h69
-rw-r--r--tests/scene/test_navigation_region_2d.h51
-rw-r--r--tests/scene/test_navigation_region_3d.h51
-rw-r--r--tests/scene/test_text_edit.h8
-rw-r--r--tests/test_main.cpp4
490 files changed, 4838 insertions, 2151 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 8dc712c78d..3d623fe5c3 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,4 +4,7 @@ PRs can target `3.x` if the same change was done in `master`, or is not relevant
Relevant fixes are cherry-picked for stable branches as needed by maintainers.
You can mention in the description if the change is compatible with `3.x`.
+
+To speed up the contribution process and avoid CI errors, please set up pre-commit hooks locally:
+https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html
-->
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index f35206ab57..c6ec244b7d 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -103,8 +103,8 @@ jobs:
- name: Spell checks via codespell
if: github.event_name == 'pull_request' && env.CHANGED_FILES != ''
- uses: codespell-project/actions-codespell@v1
+ uses: codespell-project/actions-codespell@v2
with:
skip: "./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/project_converter_3_to_4.cpp,./misc/scripts/codespell.sh,./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json"
- ignore_words_list: "curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai"
+ ignore_words_list: "curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,vai"
path: ${{ env.CHANGED_FILES }}
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index cb25dc9ebf..79fab50882 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -67,14 +67,6 @@ String ProjectSettings::get_resource_path() const {
return resource_path;
}
-String ProjectSettings::get_safe_project_name() const {
- String safe_name = OS::get_singleton()->get_safe_dir_name(get("application/config/name"));
- if (safe_name.is_empty()) {
- safe_name = "UnnamedProject";
- }
- return safe_name;
-}
-
String ProjectSettings::get_imported_files_path() const {
return get_project_data_path().path_join("imported");
}
@@ -930,10 +922,26 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
}
Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array?
-
return save_custom(p_file);
}
+#ifdef TOOLS_ENABLED
+bool _csproj_exists(String p_root_dir) {
+ Ref<DirAccess> dir = DirAccess::open(p_root_dir);
+
+ dir->list_dir_begin();
+ String file_name = dir->_get_next();
+ while (file_name != "") {
+ if (!dir->current_is_dir() && file_name.get_extension() == "csproj") {
+ return true;
+ }
+ file_name = dir->_get_next();
+ }
+
+ return false;
+}
+#endif // TOOLS_ENABLED
+
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
@@ -952,7 +960,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
+ if (_csproj_exists(get_resource_path())) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index a0249ef267..b89e6694b0 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -166,7 +166,6 @@ public:
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
- String get_safe_project_name() const;
String get_imported_files_path() const;
static ProjectSettings *get_singleton();
diff --git a/core/doc_data.cpp b/core/doc_data.cpp
index 2d909f5335..7549ba884e 100644
--- a/core/doc_data.cpp
+++ b/core/doc_data.cpp
@@ -51,6 +51,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper
if (p_method.return_enum.begins_with("_")) { //proxy class
p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
}
+ p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_method.return_type = "int";
} else if (p_retinfo.class_name != StringName()) {
p_method.return_type = p_retinfo.class_name;
@@ -82,6 +83,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const
if (p_argument.enumeration.begins_with("_")) { //proxy class
p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
}
+ p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_argument.type = "int";
} else if (p_arginfo.class_name != StringName()) {
p_argument.type = p_arginfo.class_name;
diff --git a/core/doc_data.h b/core/doc_data.h
index fc184c411c..0fe7414b98 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -50,6 +50,7 @@ public:
String name;
String type;
String enumeration;
+ bool is_bitfield = false;
String default_value;
bool operator<(const ArgumentDoc &p_arg) const {
if (name == p_arg.name) {
@@ -70,6 +71,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("default_value")) {
@@ -91,6 +95,7 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.default_value.is_empty()) {
@@ -105,6 +110,7 @@ public:
String name;
String return_type;
String return_enum;
+ bool return_is_bitfield = false;
String qualifiers;
String description;
bool is_deprecated = false;
@@ -152,6 +158,9 @@ public:
if (p_dict.has("return_enum")) {
doc.return_enum = p_dict["return_enum"];
+ if (p_dict.has("return_is_bitfield")) {
+ doc.return_is_bitfield = p_dict["return_is_bitfield"];
+ }
}
if (p_dict.has("qualifiers")) {
@@ -201,6 +210,7 @@ public:
if (!p_doc.return_enum.is_empty()) {
dict["return_enum"] = p_doc.return_enum;
+ dict["return_is_bitfield"] = p_doc.return_is_bitfield;
}
if (!p_doc.qualifiers.is_empty()) {
@@ -264,10 +274,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
- }
-
- if (p_dict.has("is_bitfield")) {
- doc.is_bitfield = p_dict["is_bitfield"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("description")) {
@@ -299,10 +308,9 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
- dict["is_bitfield"] = p_doc.is_bitfield;
-
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
@@ -319,6 +327,7 @@ public:
String name;
String type;
String enumeration;
+ bool is_bitfield = false;
String description;
String setter, getter;
String default_value;
@@ -342,6 +351,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("description")) {
@@ -391,6 +403,7 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.description.is_empty()) {
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 3aa41f28da..2a328c9a34 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -195,11 +195,11 @@ typedef struct {
int32_t expected;
} GDExtensionCallError;
-typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr);
-typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionTypePtr, GDExtensionVariantPtr);
+typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
+typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
-typedef void (*GDExtensionPtrConstructor)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args);
+typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
typedef void (*GDExtensionPtrDestructor)(GDExtensionTypePtr p_base);
typedef void (*GDExtensionPtrSetter)(GDExtensionTypePtr p_base, GDExtensionConstTypePtr p_value);
typedef void (*GDExtensionPtrGetter)(GDExtensionConstTypePtr p_base, GDExtensionTypePtr r_value);
diff --git a/core/input/input.cpp b/core/input/input.cpp
index b4945b41a8..cf8d71b9a7 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -1544,7 +1544,7 @@ Input::Input() {
legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
if (Engine::get_singleton()->is_editor_hint()) {
- // Always use standard behaviour in the editor.
+ // Always use standard behavior in the editor.
legacy_just_pressed_behavior = false;
}
}
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 6010c2a2b4..e547b04d0b 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -201,7 +201,7 @@ bool InputEventWithModifiers::is_alt_pressed() const {
}
void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) {
- ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Control directly!");
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Control directly!");
ctrl_pressed = p_enabled;
emit_changed();
}
@@ -211,7 +211,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const {
}
void InputEventWithModifiers::set_meta_pressed(bool p_enabled) {
- ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Meta directly!");
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Meta directly!");
meta_pressed = p_enabled;
emit_changed();
}
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index a6a1a224b3..b669afdc99 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -441,6 +441,11 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
current += c;
}
}
+
+ if (in_quote) {
+ WARN_PRINT(vformat("Reached end of file before closing '\"' in CSV file '%s'.", get_path()));
+ }
+
strings.push_back(current);
return strings;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 65728f34f6..772f700916 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -35,8 +35,6 @@
#include "core/templates/hash_map.h"
#include "core/variant/typed_array.h"
-VARIANT_ENUM_CAST(IP::ResolverStatus);
-
/************* RESOLVER ******************/
struct _IP_ResolverPrivate {
diff --git a/core/io/ip.h b/core/io/ip.h
index b768f0b9d4..4816d59ac2 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -109,5 +109,6 @@ public:
};
VARIANT_ENUM_CAST(IP::Type);
+VARIANT_ENUM_CAST(IP::ResolverStatus);
#endif // IP_H
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index b4da314e96..2a7a675f2d 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -920,8 +920,11 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p
for (int i = 0; i < external_resources.size(); i++) {
String dep;
+ String fallback_path;
+
if (external_resources[i].uid != ResourceUID::INVALID_ID) {
dep = ResourceUID::get_singleton()->id_to_text(external_resources[i].uid);
+ fallback_path = external_resources[i].path; // Used by Dependency Editor, in case uid path fails.
} else {
dep = external_resources[i].path;
}
@@ -929,6 +932,12 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p
if (p_add_types && !external_resources[i].type.is_empty()) {
dep += "::" + external_resources[i].type;
}
+ if (!fallback_path.is_empty()) {
+ if (!p_add_types) {
+ dep += "::"; // Ensure that path comes third, even if there is no type.
+ }
+ dep += "::" + fallback_path;
+ }
p_dependencies->push_back(dep);
}
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 5c0a017bfc..958734addf 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -34,8 +34,6 @@
//#define DEBUG_XML
-VARIANT_ENUM_CAST(XMLParser::NodeType);
-
static inline bool _is_white_space(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index b96478c7a5..77df99a881 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -126,4 +126,6 @@ public:
~XMLParser();
};
+VARIANT_ENUM_CAST(XMLParser::NodeType);
+
#endif // XML_PARSER_H
diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h
index cf7ba8d48e..fc70724308 100644
--- a/core/math/delaunay_2d.h
+++ b/core/math/delaunay_2d.h
@@ -145,7 +145,7 @@ public:
// Filter out the triangles containing vertices of the bounding triangle.
int preserved_count = 0;
Triangle *triangles_ptrw = triangles.ptrw();
- for (int i = 0; i < triangles.size() - 1; i++) {
+ for (int i = 0; i < triangles.size(); i++) {
if (!(triangles[i].points[0] >= point_count || triangles[i].points[1] >= point_count || triangles[i].points[2] >= point_count)) {
triangles_ptrw[preserved_count] = triangles[i];
preserved_count++;
diff --git a/core/object/object.cpp b/core/object/object.cpp
index d6937539c7..c76188a2cd 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1719,6 +1719,30 @@ uint32_t Object::get_edited_version() const {
}
#endif
+StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
+ // Only return the class name per the extension if it matches the given p_library.
+ if (_extension && _extension->library == p_library) {
+ return _extension->class_name;
+ }
+
+ // Extensions only have wrapper classes for classes exposed in ClassDB.
+ const StringName *class_name = _get_class_namev();
+ if (ClassDB::is_class_exposed(*class_name)) {
+ return *class_name;
+ }
+
+ // Find the nearest parent class that's exposed.
+ StringName parent_class = ClassDB::get_parent_class(*class_name);
+ while (parent_class != StringName()) {
+ if (ClassDB::is_class_exposed(parent_class)) {
+ return parent_class;
+ }
+ parent_class = ClassDB::get_parent_class(parent_class);
+ }
+
+ return SNAME("Object");
+}
+
void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
// This is only meant to be used on creation by the binder.
ERR_FAIL_COND(_instance_bindings != nullptr);
diff --git a/core/object/object.h b/core/object/object.h
index 6f626b0ed0..a3e9d025ea 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -800,17 +800,7 @@ public:
return *_class_name_ptr;
}
- _FORCE_INLINE_ const StringName &get_class_name_for_extension(const GDExtension *p_library) const {
- // Only return the class name per the extension if it matches the given p_library.
- if (_extension && _extension->library == p_library) {
- return _extension->class_name;
- }
- // Otherwise, return the name of the built-in class.
- if (unlikely(!_class_name_ptr)) {
- return *_get_class_namev();
- }
- return *_class_name_ptr;
- }
+ StringName get_class_name_for_extension(const GDExtension *p_library) const;
/* IAPI */
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 829f01fbcc..c22890e30a 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -338,7 +338,7 @@ public:
Ref<Resource> icon;
Variant default_value;
Vector<Pair<int, int>> matches;
- Vector<Pair<int, int>> last_matches;
+ Vector<Pair<int, int>> last_matches = { { -1, -1 } }; // This value correspond to an impossible match
int location = LOCATION_OTHER;
CodeCompletionOption() {}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 17d9eaff0b..f04961c760 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -312,6 +312,11 @@ void UndoRedo::commit_action(bool p_execute) {
}
void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
+ const int PREALLOCATE_ARGS_COUNT = 16;
+
+ LocalVector<const Variant *> args;
+ args.reserve(PREALLOCATE_ARGS_COUNT);
+
for (; E; E = E->next()) {
Operation &op = E->get();
@@ -347,12 +352,13 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
if (binds.is_empty()) {
method_callback(method_callback_ud, obj, op.name, nullptr, 0);
} else {
- const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+ args.clear();
+
for (int i = 0; i < binds.size(); i++) {
- args[i] = (const Variant *)&binds[i];
+ args.push_back(&binds[i]);
}
- method_callback(method_callback_ud, obj, op.name, args, binds.size());
+ method_callback(method_callback_ud, obj, op.name, args.ptr(), binds.size());
}
}
} break;
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 1e32e6e096..1a51624030 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -400,17 +400,38 @@ String keycode_get_string(Key p_code) {
return codestr;
}
-Key find_keycode(const String &p_code) {
+Key find_keycode(const String &p_codestr) {
+ Key keycode = Key::NONE;
+ Vector<String> code_parts = p_codestr.split("+");
+ if (code_parts.size() < 1) {
+ return keycode;
+ }
+
+ String last_part = code_parts[code_parts.size() - 1];
const _KeyCodeText *kct = &_keycodes[0];
while (kct->text) {
- if (p_code.nocasecmp_to(kct->text) == 0) {
- return kct->code;
+ if (last_part.nocasecmp_to(kct->text) == 0) {
+ keycode = kct->code;
+ break;
}
kct++;
}
- return Key::NONE;
+ for (int part = 0; part < code_parts.size() - 1; part++) {
+ String code_part = code_parts[part];
+ if (code_part.nocasecmp_to(find_keycode_name(Key::SHIFT)) == 0) {
+ keycode |= KeyModifierMask::SHIFT;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::CTRL)) == 0) {
+ keycode |= KeyModifierMask::CTRL;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::META)) == 0) {
+ keycode |= KeyModifierMask::META;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::ALT)) == 0) {
+ keycode |= KeyModifierMask::ALT;
+ }
+ }
+
+ return keycode;
}
const char *find_keycode_name(Key p_keycode) {
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 84017e89a6..cf276dc49f 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -330,7 +330,7 @@ constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
String keycode_get_string(Key p_code);
bool keycode_has_unicode(Key p_keycode);
-Key find_keycode(const String &p_code);
+Key find_keycode(const String &p_codestr);
const char *find_keycode_name(Key p_keycode);
int keycode_get_count();
int keycode_get_value_by_index(int p_index);
diff --git a/core/os/time.cpp b/core/os/time.cpp
index 038e4adc03..bad5cc2e4f 100644
--- a/core/os/time.cpp
+++ b/core/os/time.cpp
@@ -52,9 +52,6 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = {
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
-VARIANT_ENUM_CAST(Month);
-VARIANT_ENUM_CAST(Weekday);
-
#define UNIX_TIME_TO_HMS \
uint8_t hour, minute, second; \
{ \
diff --git a/core/os/time.h b/core/os/time.h
index 19bc900aee..ccd2d92b8b 100644
--- a/core/os/time.h
+++ b/core/os/time.h
@@ -81,4 +81,7 @@ public:
virtual ~Time();
};
+VARIANT_ENUM_CAST(Month);
+VARIANT_ENUM_CAST(Weekday);
+
#endif // TIME_H
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index c23066c0c6..782053b613 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -1541,7 +1541,7 @@ struct VariantTypeConstructor {
_FORCE_INLINE_ static void type_from_variant(void *r_value, void *p_variant) {
// r_value is provided by caller as uninitialized memory
- memnew_placement(r_value, T(VariantInternalAccessor<T>::get(reinterpret_cast<Variant *>(p_variant))));
+ memnew_placement(r_value, T(*reinterpret_cast<Variant *>(p_variant)));
}
};
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 33c285dc6d..aed83ac010 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -900,6 +900,39 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL);
register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL);
register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorNot<String>>(Variant::OP_NOT, Variant::STRING, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector2>>(Variant::OP_NOT, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector2i>>(Variant::OP_NOT, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Rect2>>(Variant::OP_NOT, Variant::RECT2, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Rect2i>>(Variant::OP_NOT, Variant::RECT2I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector3>>(Variant::OP_NOT, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector3i>>(Variant::OP_NOT, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Transform2D>>(Variant::OP_NOT, Variant::TRANSFORM2D, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector4>>(Variant::OP_NOT, Variant::VECTOR4, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector4i>>(Variant::OP_NOT, Variant::VECTOR4I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Plane>>(Variant::OP_NOT, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Quaternion>>(Variant::OP_NOT, Variant::QUATERNION, Variant::NIL);
+ register_op<OperatorEvaluatorNot<::AABB>>(Variant::OP_NOT, Variant::AABB, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Basis>>(Variant::OP_NOT, Variant::BASIS, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Transform3D>>(Variant::OP_NOT, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Projection>>(Variant::OP_NOT, Variant::PROJECTION, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Color>>(Variant::OP_NOT, Variant::COLOR, Variant::NIL);
+ register_op<OperatorEvaluatorNot<StringName>>(Variant::OP_NOT, Variant::STRING_NAME, Variant::NIL);
+ register_op<OperatorEvaluatorNot<NodePath>>(Variant::OP_NOT, Variant::NODE_PATH, Variant::NIL);
+ register_op<OperatorEvaluatorNot<::RID>>(Variant::OP_NOT, Variant::RID, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Callable>>(Variant::OP_NOT, Variant::CALLABLE, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Signal>>(Variant::OP_NOT, Variant::SIGNAL, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Dictionary>>(Variant::OP_NOT, Variant::DICTIONARY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Array>>(Variant::OP_NOT, Variant::ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedByteArray>>(Variant::OP_NOT, Variant::PACKED_BYTE_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedInt32Array>>(Variant::OP_NOT, Variant::PACKED_INT32_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedInt64Array>>(Variant::OP_NOT, Variant::PACKED_INT64_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedFloat32Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT32_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedFloat64Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT64_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedStringArray>>(Variant::OP_NOT, Variant::PACKED_STRING_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedVector2Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR2_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedVector3Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR3_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedColorArray>>(Variant::OP_NOT, Variant::PACKED_COLOR_ARRAY, Variant::NIL);
register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN);
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index d2163cf92d..5db4d63806 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -805,14 +805,14 @@ class OperatorEvaluatorNot {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
- *r_ret = !a;
+ *r_ret = a == A();
r_valid = true;
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == A();
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<bool>::encode(!PtrToArg<A>::convert(left));
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == A(), r_ret);
}
static Variant::Type get_return_type() { return Variant::BOOL; }
};
diff --git a/doc/class.xsd b/doc/class.xsd
index d29d053006..83880ed5f9 100644
--- a/doc/class.xsd
+++ b/doc/class.xsd
@@ -33,6 +33,7 @@
</xs:sequence>
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="param" maxOccurs="unbounded" minOccurs="0">
@@ -44,6 +45,7 @@
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
</xs:complexType>
</xs:element>
@@ -69,6 +71,7 @@
</xs:sequence>
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="returns_error" maxOccurs="unbounded" minOccurs="0">
@@ -88,6 +91,7 @@
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
</xs:complexType>
</xs:element>
@@ -115,6 +119,7 @@
<xs:attribute type="xs:string" name="getter" />
<xs:attribute type="xs:string" name="overrides" use="optional" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
@@ -182,6 +187,7 @@
</xs:sequence>
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="param" maxOccurs="unbounded" minOccurs="0">
@@ -193,6 +199,7 @@
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
</xs:complexType>
</xs:element>
@@ -236,6 +243,7 @@
</xs:sequence>
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="param" maxOccurs="unbounded" minOccurs="0">
@@ -247,6 +255,7 @@
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
</xs:complexType>
</xs:element>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index 91b333ae89..6d2b05e729 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -65,7 +65,7 @@
<param index="1" name="arrays" type="Array" />
<param index="2" name="blend_shapes" type="Array[]" default="[]" />
<param index="3" name="lods" type="Dictionary" default="{}" />
- <param index="4" name="flags" type="int" enum="Mesh.ArrayFormat" default="0" />
+ <param index="4" name="flags" type="int" enum="Mesh.ArrayFormat" is_bitfield="true" default="0" />
<description>
Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
@@ -145,7 +145,7 @@
</description>
</method>
<method name="surface_get_format" qualifiers="const">
- <return type="int" enum="Mesh.ArrayFormat" />
+ <return type="int" enum="Mesh.ArrayFormat" is_bitfield="true" />
<param index="0" name="surf_idx" type="int" />
<description>
Returns the format mask of the requested surface (see [method add_surface_from_arrays]).
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 1290bfc0f2..cc95c97e68 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -51,7 +51,7 @@
The [ButtonGroup] associated with the button. Not to be confused with node groups.
[b]Note:[/b] The button will be configured as a radio button if a [ButtonGroup] is assigned to it.
</member>
- <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButtonMask" default="1">
+ <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButtonMask" is_bitfield="true" default="1">
Binary mask to choose which mouse buttons this button will respond to.
To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT[/code].
</member>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 87f1f0b538..5eea774cf4 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -46,6 +46,17 @@
# Prints "Attack!", when the button_pressed signal is emitted.
button_pressed.connect(func(): print("Attack!"))
[/codeblock]
+ [b]Note:[/b] Methods of native types such as [Signal], [Array], or [Dictionary] are not of type [Callable] in order to avoid unnecessary overhead. If you need to pass those methods as [Callable], use a lambda function as a wrapper.
+ [codeblock]
+ func _init():
+ var my_dictionary = { "hello": "world" }
+
+ # This will not work, `clear` is not a callable.
+ create_tween().tween_callback(my_dictionary.clear)
+
+ # This will work, as lambdas are custom callables.
+ create_tween().tween_callback(func(): my_dictionary.clear())
+ [/codeblock]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index cb10367183..ba280ab0fa 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -193,8 +193,8 @@
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="max_lines" type="int" default="-1" />
<param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <param index="9" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
+ <param index="9" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -212,8 +212,8 @@
<param index="6" name="max_lines" type="int" default="-1" />
<param index="7" name="size" type="int" default="1" />
<param index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <param index="10" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
+ <param index="10" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -309,7 +309,7 @@
<param index="4" name="width" type="float" default="-1" />
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="7" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="7" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -346,7 +346,7 @@
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="size" type="int" default="1" />
<param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="8" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index e0dd0eb9a8..e20651b1ee 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -1028,13 +1028,13 @@
<member name="size" type="Vector2" setter="_set_size" getter="get_size" default="Vector2(0, 0)">
The size of the node's bounding rectangle, in the node's coordinate system. [Container] nodes update this property automatically.
</member>
- <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" enum="Control.SizeFlags" default="1">
+ <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" enum="Control.SizeFlags" is_bitfield="true" default="1">
Tells the parent [Container] nodes how they should resize and place the node on the X axis. Use a combination of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does.
</member>
<member name="size_flags_stretch_ratio" type="float" setter="set_stretch_ratio" getter="get_stretch_ratio" default="1.0">
If the node and at least one of its neighbors uses the [constant SIZE_EXPAND] size flag, the parent [Container] will let it take more or less space depending on this property. If this node has a stretch ratio of 2 and its neighbor a ratio of 1, this node will take two thirds of the available space.
</member>
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" enum="Control.SizeFlags" default="1">
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" enum="Control.SizeFlags" is_bitfield="true" default="1">
Tells the parent [Container] nodes how they should resize and place the node on the Y axis. Use a combination of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does.
</member>
<member name="theme" type="Theme" setter="set_theme" getter="get_theme">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index cd39543c45..789975eafa 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -807,7 +807,7 @@
</description>
</method>
<method name="mouse_get_button_state" qualifiers="const">
- <return type="int" enum="MouseButtonMask" />
+ <return type="int" enum="MouseButtonMask" is_bitfield="true" />
<description>
Returns the current state of mouse buttons (whether each button is pressed) as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together. Equivalent to [method Input.get_mouse_button_mask].
</description>
@@ -1258,6 +1258,13 @@
Returns the V-Sync mode of the given window.
</description>
</method>
+ <method name="window_is_focused" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="window_id" type="int" default="0" />
+ <description>
+ Returns [code]true[/code] if the window specified by [param window_id] is focused.
+ </description>
+ </method>
<method name="window_is_maximize_allowed" qualifiers="const">
<return type="bool" />
<param index="0" name="window_id" type="int" default="0" />
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index f6bd0ee844..340e22c46a 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -60,7 +60,7 @@
<param index="2" name="name" type="String" />
<param index="3" name="hint_type" type="int" enum="PropertyHint" />
<param index="4" name="hint_string" type="String" />
- <param index="5" name="usage_flags" type="int" enum="PropertyUsageFlags" />
+ <param index="5" name="usage_flags" type="int" enum="PropertyUsageFlags" is_bitfield="true" />
<param index="6" name="wide" type="bool" />
<description>
Called to allow adding property-specific editors to the property list for [param object]. The added editor control must extend [EditorProperty]. Returning [code]true[/code] removes the built-in editor for this property, otherwise allows to insert a custom editor before the built-in one.
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 59a74b5cd1..fbabdf9c81 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -746,6 +746,9 @@
<member name="text_editor/appearance/gutters/show_line_numbers" type="bool" setter="" getter="">
If [code]true[/code], displays line numbers in a gutter at the left.
</member>
+ <member name="text_editor/appearance/lines/autowrap_mode" type="int" setter="" getter="">
+ If [member text_editor/appearance/lines/word_wrap] is set to [code]1[/code], sets text wrapping mode. To see how each mode behaves, see [enum TextServer.AutowrapMode].
+ </member>
<member name="text_editor/appearance/lines/code_folding" type="bool" setter="" getter="">
If [code]true[/code], displays the folding arrows next to indented code sections and allows code folding. If [code]false[/code], hides the folding arrows next to indented code sections and disallows code folding.
</member>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 9ef778f7b6..045a1796dd 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -22,7 +22,7 @@
<member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false">
If [code]true[/code], the slider can't be interacted with.
</member>
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="1" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
<member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index 57c31bebb5..5d34e38b13 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -44,8 +44,8 @@
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="max_lines" type="int" default="-1" />
<param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <param index="9" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
+ <param index="9" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -64,8 +64,8 @@
<param index="6" name="max_lines" type="int" default="-1" />
<param index="7" name="size" type="int" default="1" />
<param index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <param index="10" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
+ <param index="10" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -82,7 +82,7 @@
<param index="4" name="width" type="float" default="-1" />
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="7" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="7" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -100,7 +100,7 @@
<param index="5" name="font_size" type="int" default="16" />
<param index="6" name="size" type="int" default="1" />
<param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <param index="8" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -168,7 +168,7 @@
</description>
</method>
<method name="get_font_style" qualifiers="const">
- <return type="int" enum="TextServer.FontStyle" />
+ <return type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<description>
Returns font style flags, see [enum TextServer.FontStyle].
</description>
@@ -200,8 +200,8 @@
<param index="2" name="width" type="float" default="-1" />
<param index="3" name="font_size" type="int" default="16" />
<param index="4" name="max_lines" type="int" default="-1" />
- <param index="5" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <param index="6" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="5" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
+ <param index="6" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="7" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="8" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
@@ -240,7 +240,7 @@
<param index="1" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
<param index="2" name="width" type="float" default="-1" />
<param index="3" name="font_size" type="int" default="16" />
- <param index="4" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="4" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<param index="5" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="6" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index 1430f79614..7f438435bd 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -580,7 +580,7 @@
<member name="font_stretch" type="int" setter="set_font_stretch" getter="get_font_stretch" default="100">
Font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code].
</member>
- <member name="font_style" type="int" setter="set_font_style" getter="get_font_style" enum="TextServer.FontStyle" default="0">
+ <member name="font_style" type="int" setter="set_font_style" getter="get_font_style" enum="TextServer.FontStyle" is_bitfield="true" default="0">
Font style flags, see [enum TextServer.FontStyle].
</member>
<member name="font_weight" type="int" setter="set_font_weight" getter="get_font_weight" default="400">
diff --git a/doc/classes/ImageFormatLoaderExtension.xml b/doc/classes/ImageFormatLoaderExtension.xml
index 98d682d868..be695de629 100644
--- a/doc/classes/ImageFormatLoaderExtension.xml
+++ b/doc/classes/ImageFormatLoaderExtension.xml
@@ -20,7 +20,7 @@
<return type="int" enum="Error" />
<param index="0" name="image" type="Image" />
<param index="1" name="fileaccess" type="FileAccess" />
- <param index="2" name="flags" type="int" enum="ImageFormatLoader.LoaderFlags" />
+ <param index="2" name="flags" type="int" enum="ImageFormatLoader.LoaderFlags" is_bitfield="true" />
<param index="3" name="scale" type="float" />
<description>
Loads the content of [param fileaccess] into the provided [param image].
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index fab4d2385b..cea8e66e52 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -156,7 +156,7 @@
</description>
</method>
<method name="get_mouse_button_mask" qualifiers="const">
- <return type="int" enum="MouseButtonMask" />
+ <return type="int" enum="MouseButtonMask" is_bitfield="true" />
<description>
Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together. Equivalent to [method DisplayServer.mouse_get_button_state].
</description>
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index 0f3794a1f6..061438dd9a 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -10,7 +10,7 @@
<link title="Using InputEvent">$DOCS_URL/tutorials/inputs/inputevent.html</link>
</tutorials>
<members>
- <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButtonMask" default="0">
+ <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButtonMask" is_bitfield="true" default="0">
The mouse button mask identifier, one of or a bitwise combination of the [enum MouseButton] button masks.
</member>
<member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" default="Vector2(0, 0)">
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index 9ba0d5d641..9de6469dfb 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -11,7 +11,7 @@
</tutorials>
<methods>
<method name="get_modifiers_mask" qualifiers="const">
- <return type="int" enum="KeyModifierMask" />
+ <return type="int" enum="KeyModifierMask" is_bitfield="true" />
<description>
Returns the keycode combination of modifier keys.
</description>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index 466b353f15..d54f209244 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -48,7 +48,7 @@
<member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0">
Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants.
</member>
- <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" default="163">
+ <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163">
Line fill alignment rules. For more info see [enum TextServer.JustificationFlag].
</member>
<member name="label_settings" type="LabelSettings" setter="set_label_settings" getter="get_label_settings">
@@ -64,7 +64,7 @@
Limits the lines of text the node shows on screen.
</member>
<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="2" />
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="4" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="4" />
<member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="TextServer.StructuredTextParser" default="0">
Set BiDi algorithm override for the structured text.
</member>
diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml
index 7b2f054703..79e96d0d45 100644
--- a/doc/classes/Label3D.xml
+++ b/doc/classes/Label3D.xml
@@ -71,7 +71,7 @@
<member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="1">
Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants.
</member>
- <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" default="163">
+ <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163">
Line fill alignment rules. For more info see [enum TextServer.JustificationFlag].
</member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 00aedb490d..332219be1e 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -184,7 +184,7 @@
<member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="100.0">
The maximum distance the agent is allowed away from the ideal path to the final position. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
- <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7">
+ <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" is_bitfield="true" default="7">
Additional information to return with the navigation path.
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters2D.PathPostProcessing" default="0">
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index f341686d57..2450f84929 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -187,7 +187,7 @@
<member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="5.0">
The maximum distance the agent is allowed away from the ideal path to the final position. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
- <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7">
+ <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" is_bitfield="true" default="7">
Additional information to return with the navigation path.
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters3D.PathPostProcessing" default="0">
diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml
index e10e23a5cf..f13d6b570a 100644
--- a/doc/classes/NavigationMeshGenerator.xml
+++ b/doc/classes/NavigationMeshGenerator.xml
@@ -14,12 +14,21 @@
<link title="Using NavigationMeshes">$DOCS_URL/tutorials/navigation/navigation_using_navigationmeshes.html</link>
</tutorials>
<methods>
- <method name="bake">
+ <method name="bake" is_deprecated="true">
<return type="void" />
<param index="0" name="navigation_mesh" type="NavigationMesh" />
<param index="1" name="root_node" type="Node" />
<description>
- Bakes navigation data to the provided [param navigation_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource.
+ The bake function is deprecated due to core threading changes. To upgrade existing code, first create a [NavigationMeshSourceGeometryData3D] resource. Use this resource with [method parse_source_geometry_data] to parse the SceneTree for nodes that should contribute to the navigation mesh baking. The SceneTree parsing needs to happen on the main thread. After the parsing is finished use the resource with [method bake_from_source_geometry_data] to bake a navigation mesh.
+ </description>
+ </method>
+ <method name="bake_from_source_geometry_data">
+ <return type="void" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
+ <param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData3D" />
+ <param index="2" name="callback" type="Callable" />
+ <description>
+ Bakes the provided [param navigation_mesh] with the data from the provided [param source_geometry_data]. After the process is finished the optional [param callback] will be called.
</description>
</method>
<method name="clear">
@@ -29,5 +38,16 @@
Removes all polygons and vertices from the provided [param navigation_mesh] resource.
</description>
</method>
+ <method name="parse_source_geometry_data">
+ <return type="void" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
+ <param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData3D" />
+ <param index="2" name="root_node" type="Node" />
+ <param index="3" name="callback" type="Callable" />
+ <description>
+ Parses the [SceneTree] for source geometry according to the properties of [param navigation_mesh]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
+ [b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
+ </description>
+ </method>
</methods>
</class>
diff --git a/doc/classes/NavigationMeshSourceGeometryData3D.xml b/doc/classes/NavigationMeshSourceGeometryData3D.xml
new file mode 100644
index 0000000000..b929e82436
--- /dev/null
+++ b/doc/classes/NavigationMeshSourceGeometryData3D.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationMeshSourceGeometryData3D" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Container for parsed source geometry data used in navigation mesh baking.
+ </brief_description>
+ <description>
+ Container for parsed source geometry data used in navigation mesh baking.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_faces">
+ <return type="void" />
+ <param index="0" name="faces" type="PackedVector3Array" />
+ <param index="1" name="xform" type="Transform3D" />
+ <description>
+ Adds an array of vertex positions to the geometry data for navigation mesh baking to form triangulated faces. For each face the array must have three vertex positions in clockwise winding order. Since [NavigationMesh] resource have no transform all vertex positions need to be offset by the node's transform using the [code]xform[/code] parameter.
+ </description>
+ </method>
+ <method name="add_mesh">
+ <return type="void" />
+ <param index="0" name="mesh" type="Mesh" />
+ <param index="1" name="xform" type="Transform3D" />
+ <description>
+ Adds the geometry data of a [Mesh] resource to the navigation mesh baking data. The mesh must have valid triangulated mesh data to be considered. Since [NavigationMesh] resource have no transform all vertex positions need to be offset by the node's transform using the [code]xform[/code] parameter.
+ </description>
+ </method>
+ <method name="add_mesh_array">
+ <return type="void" />
+ <param index="0" name="mesh_array" type="Array" />
+ <param index="1" name="xform" type="Transform3D" />
+ <description>
+ Adds an [Array] the size of [constant Mesh.ARRAY_MAX] and with vertices at index [constant Mesh.ARRAY_VERTEX] and indices at index [constant Mesh.ARRAY_INDEX] to the navigation mesh baking data. The array must have valid triangulated mesh data to be considered. Since [NavigationMesh] resource have no transform all vertex positions need to be offset by the node's transform using the [code]xform[/code] parameter.
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the internal data.
+ </description>
+ </method>
+ <method name="get_indices" qualifiers="const">
+ <return type="PackedInt32Array" />
+ <description>
+ Returns the parsed source geometry data indices array.
+ </description>
+ </method>
+ <method name="get_vertices" qualifiers="const">
+ <return type="PackedFloat32Array" />
+ <description>
+ Returns the parsed source geometry data vertices array.
+ </description>
+ </method>
+ <method name="has_data">
+ <return type="bool" />
+ <description>
+ Returns [b]true[/b] when parsed source geometry data exists.
+ </description>
+ </method>
+ <method name="set_indices">
+ <return type="void" />
+ <param index="0" name="indices" type="PackedInt32Array" />
+ <description>
+ Sets the parsed source geometry data indices. The indices need to be matched with appropriated vertices.
+ [b]Warning:[/b] Inappropriate data can crash the baking process of the involved third-party libraries.
+ </description>
+ </method>
+ <method name="set_vertices">
+ <return type="void" />
+ <param index="0" name="vertices" type="PackedFloat32Array" />
+ <description>
+ Sets the parsed source geometry data vertices. The vertices need to be matched with appropriated indices.
+ [b]Warning:[/b] Inappropriate data can crash the baking process of the involved third-party libraries.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
index 0e48508197..a4fd04696d 100644
--- a/doc/classes/NavigationPathQueryParameters2D.xml
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -13,7 +13,7 @@
<member name="map" type="RID" setter="set_map" getter="get_map">
The navigation [code]map[/code] [RID] used in the path query.
</member>
- <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7">
+ <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" is_bitfield="true" default="7">
Additional information to include with the navigation path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
index 7564c6a858..e63a3582bd 100644
--- a/doc/classes/NavigationPathQueryParameters3D.xml
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -13,7 +13,7 @@
<member name="map" type="RID" setter="set_map" getter="get_map">
The navigation [code]map[/code] [RID] used in the path query.
</member>
- <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7">
+ <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" is_bitfield="true" default="7">
Additional information to include with the navigation path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index f46f2912b3..5364c3f13d 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -38,6 +38,13 @@
Returns the navigation map [RID] the requested [param agent] is currently assigned to.
</description>
</method>
+ <method name="agent_get_paused" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="agent" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param agent] is paused.
+ </description>
+ </method>
<method name="agent_is_map_changed" qualifiers="const">
<return type="bool" />
<param index="0" name="agent" type="RID" />
@@ -119,6 +126,14 @@
Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
+ <method name="agent_set_paused">
+ <return type="void" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="paused" type="bool" />
+ <description>
+ If [param paused] is true the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks.
+ </description>
+ </method>
<method name="agent_set_position">
<return type="void" />
<param index="0" name="agent" type="RID" />
@@ -156,7 +171,7 @@
<param index="0" name="agent" type="RID" />
<param index="1" name="velocity" type="Vector2" />
<description>
- Sets [param velocity] as the new wanted velocity for the specified [param agent]. The avoidance simulation will try to fulfil this velocity if possible but will modify it to avoid collision with other agent's and obstacles. When an agent is teleported to a new position far away use [method agent_set_velocity_forced] instead to reset the internal velocity state.
+ Sets [param velocity] as the new wanted velocity for the specified [param agent]. The avoidance simulation will try to fulfill this velocity if possible but will modify it to avoid collision with other agent's and obstacles. When an agent is teleported to a new position far away use [method agent_set_velocity_forced] instead to reset the internal velocity state.
</description>
</method>
<method name="agent_set_velocity_forced">
@@ -478,6 +493,13 @@
Returns the navigation map [RID] the requested [param obstacle] is currently assigned to.
</description>
</method>
+ <method name="obstacle_get_paused" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="obstacle" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param obstacle] is paused.
+ </description>
+ </method>
<method name="obstacle_set_avoidance_enabled">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
@@ -502,6 +524,14 @@
Sets the navigation map [RID] for the obstacle.
</description>
</method>
+ <method name="obstacle_set_paused">
+ <return type="void" />
+ <param index="0" name="obstacle" type="RID" />
+ <param index="1" name="paused" type="bool" />
+ <description>
+ If [param paused] is true the specified [param obstacle] will not be processed, e.g. affect avoidance velocities.
+ </description>
+ </method>
<method name="obstacle_set_position">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index ac9646da4a..9ee22ab861 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -38,6 +38,13 @@
Returns the navigation map [RID] the requested [param agent] is currently assigned to.
</description>
</method>
+ <method name="agent_get_paused" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="agent" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param agent] is paused.
+ </description>
+ </method>
<method name="agent_get_use_3d_avoidance" qualifiers="const">
<return type="bool" />
<param index="0" name="agent" type="RID" />
@@ -134,6 +141,14 @@
Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
+ <method name="agent_set_paused">
+ <return type="void" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="paused" type="bool" />
+ <description>
+ If [param paused] is true the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks.
+ </description>
+ </method>
<method name="agent_set_position">
<return type="void" />
<param index="0" name="agent" type="RID" />
@@ -181,7 +196,7 @@
<param index="0" name="agent" type="RID" />
<param index="1" name="velocity" type="Vector3" />
<description>
- Sets [param velocity] as the new wanted velocity for the specified [param agent]. The avoidance simulation will try to fulfil this velocity if possible but will modify it to avoid collision with other agent's and obstacles. When an agent is teleported to a new position use [method agent_set_velocity_forced] as well to reset the internal simulation velocity.
+ Sets [param velocity] as the new wanted velocity for the specified [param agent]. The avoidance simulation will try to fulfill this velocity if possible but will modify it to avoid collision with other agent's and obstacles. When an agent is teleported to a new position use [method agent_set_velocity_forced] as well to reset the internal simulation velocity.
</description>
</method>
<method name="agent_set_velocity_forced">
@@ -192,6 +207,15 @@
Replaces the internal velocity in the collision avoidance simulation with [param velocity] for the specified [param agent]. When an agent is teleported to a new position this function should be used in the same frame. If called frequently this function can get agents stuck.
</description>
</method>
+ <method name="bake_from_source_geometry_data">
+ <return type="void" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
+ <param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData3D" />
+ <param index="2" name="callback" type="Callable" />
+ <description>
+ Bakes the provided [param navigation_mesh] with the data from the provided [param source_geometry_data]. After the process is finished the optional [param callback] will be called.
+ </description>
+ </method>
<method name="free_rid">
<return type="void" />
<param index="0" name="rid" type="RID" />
@@ -558,6 +582,13 @@
Returns the navigation map [RID] the requested [param obstacle] is currently assigned to.
</description>
</method>
+ <method name="obstacle_get_paused" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="obstacle" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param obstacle] is paused.
+ </description>
+ </method>
<method name="obstacle_get_use_3d_avoidance" qualifiers="const">
<return type="bool" />
<param index="0" name="obstacle" type="RID" />
@@ -597,6 +628,14 @@
Assigns the [param obstacle] to a navigation map.
</description>
</method>
+ <method name="obstacle_set_paused">
+ <return type="void" />
+ <param index="0" name="obstacle" type="RID" />
+ <param index="1" name="paused" type="bool" />
+ <description>
+ If [param paused] is true the specified [param obstacle] will not be processed, e.g. affect avoidance velocities.
+ </description>
+ </method>
<method name="obstacle_set_position">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
@@ -637,6 +676,17 @@
Sets the outline vertices for the obstacle. If the vertices are winded in clockwise order agents will be pushed in by the obstacle, else they will be pushed out.
</description>
</method>
+ <method name="parse_source_geometry_data">
+ <return type="void" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
+ <param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData3D" />
+ <param index="2" name="root_node" type="Node" />
+ <param index="3" name="callback" type="Callable" />
+ <description>
+ Parses the [SceneTree] for source geometry according to the properties of [param navigation_mesh]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
+ [b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
+ </description>
+ </method>
<method name="query_path" qualifiers="const">
<return type="void" />
<param index="0" name="parameters" type="NavigationPathQueryParameters3D" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 1557b5f3c2..b6bd82eacc 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -877,7 +877,7 @@
<member name="process_thread_group_order" type="int" setter="set_process_thread_group_order" getter="get_process_thread_group_order">
Change the process thread group order. Groups with a lesser order will process before groups with a greater order. This is useful when a large amount of nodes process in sub thread and, afterwards, another group wants to collect their result in the main thread, as an example.
</member>
- <member name="process_thread_messages" type="int" setter="set_process_thread_messages" getter="get_process_thread_messages" enum="Node.ProcessThreadMessages">
+ <member name="process_thread_messages" type="int" setter="set_process_thread_messages" getter="get_process_thread_messages" enum="Node.ProcessThreadMessages" is_bitfield="true">
Set whether the current thread group will process messages (calls to [method call_deferred_thread_group] on threads, and whether it wants to receive them during regular process or physics process callbacks.
</member>
<member name="scene_file_path" type="String" setter="set_scene_file_path" getter="get_scene_file_path">
@@ -1028,10 +1028,12 @@
Implemented on desktop and web platforms.
</constant>
<constant name="NOTIFICATION_WM_WINDOW_FOCUS_IN" value="1004">
- Notification received from the OS when the node's parent [Window] is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also emitted).
+ Notification received when the node's parent [Window] is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also emitted).
+ A [Window] node receives this notification when it is focused.
</constant>
<constant name="NOTIFICATION_WM_WINDOW_FOCUS_OUT" value="1005">
- Notification received from the OS when the node's parent [Window] is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also emitted).
+ Notification received when the node's parent [Window] is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also emitted).
+ A [Window] node receives this notification when it is defocused.
</constant>
<constant name="NOTIFICATION_WM_CLOSE_REQUEST" value="1006">
Notification received from the OS when a close request is sent (e.g. closing the window with a "Close" button or [kbd]Alt + F4[/kbd]).
@@ -1115,11 +1117,11 @@
<constant name="PROCESS_THREAD_GROUP_SUB_THREAD" value="2" enum="ProcessThreadGroup">
Process this node (and children nodes set to inherit) on a sub-thread. See [member process_thread_group] for more information.
</constant>
- <constant name="FLAG_PROCESS_THREAD_MESSAGES" value="1" enum="ProcessThreadMessages">
+ <constant name="FLAG_PROCESS_THREAD_MESSAGES" value="1" enum="ProcessThreadMessages" is_bitfield="true">
</constant>
- <constant name="FLAG_PROCESS_THREAD_MESSAGES_PHYSICS" value="2" enum="ProcessThreadMessages">
+ <constant name="FLAG_PROCESS_THREAD_MESSAGES_PHYSICS" value="2" enum="ProcessThreadMessages" is_bitfield="true">
</constant>
- <constant name="FLAG_PROCESS_THREAD_MESSAGES_ALL" value="3" enum="ProcessThreadMessages">
+ <constant name="FLAG_PROCESS_THREAD_MESSAGES_ALL" value="3" enum="ProcessThreadMessages" is_bitfield="true">
</constant>
<constant name="DUPLICATE_SIGNALS" value="1" enum="DuplicateFlags">
Duplicate the node's signals.
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 663050e567..eb5a0edfd6 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -27,6 +27,10 @@
<param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedColorArray]. Optionally, you can pass in a generic [Array] that will be converted.
+ [b]Note:[/b] When initializing a [PackedColorArray] with elements, it must be initialized with an [Array] of [Color] values:
+ [codeblock]
+ var array = PackedColorArray([Color(0.1, 0.2, 0.3), Color(0.4, 0.5, 0.6)])
+ [/codeblock]
</description>
</constructor>
</constructors>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index 0f74e0d2e5..a5a5d2f2df 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -28,6 +28,10 @@
<param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedVector2Array]. Optionally, you can pass in a generic [Array] that will be converted.
+ [b]Note:[/b] When initializing a [PackedVector2Array] with elements, it must be initialized with an [Array] of [Vector2] values:
+ [codeblock]
+ var array = PackedVector2Array([Vector2(12, 34), Vector2(56, 78)])
+ [/codeblock]
</description>
</constructor>
</constructors>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 9d0fdaa717..2557549703 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -27,6 +27,10 @@
<param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedVector3Array]. Optionally, you can pass in a generic [Array] that will be converted.
+ [b]Note:[/b] When initializing a [PackedVector3Array] with elements, it must be initialized with an [Array] of [Vector3] values:
+ [codeblock]
+ var array = PackedVector3Array([Vector3(12, 34, 56), Vector3(78, 90, 12)])
+ [/codeblock]
</description>
</constructor>
</constructors>
diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml
index ff674a8d7e..7308127c3f 100644
--- a/doc/classes/RDTextureFormat.xml
+++ b/doc/classes/RDTextureFormat.xml
@@ -44,7 +44,7 @@
<member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="RenderingDevice.TextureType" default="1">
The texture type.
</member>
- <member name="usage_bits" type="int" setter="set_usage_bits" getter="get_usage_bits" enum="RenderingDevice.TextureUsageBits" default="0">
+ <member name="usage_bits" type="int" setter="set_usage_bits" getter="get_usage_bits" enum="RenderingDevice.TextureUsageBits" is_bitfield="true" default="0">
The texture's usage bits, which determine what can be done using the texture.
</member>
<member name="width" type="int" setter="set_width" getter="get_width" default="1">
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index a6b29f9e26..e75b47af24 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -62,7 +62,7 @@
<member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values" default="false">
If [code]true[/code], [member value] will always be rounded to the nearest integer.
</member>
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="0" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="0" />
<member name="step" type="float" setter="set_step" getter="get_step" default="0.01">
If greater than 0, [member value] will always be rounded to a multiple of this property's value. If [member rounded] is also [code]true[/code], [member value] will first be rounded to a multiple of this property's value, then rounded to the nearest integer.
</member>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index e19bb440ec..f557dc2fdd 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -16,8 +16,8 @@
<methods>
<method name="barrier">
<return type="void" />
- <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" default="7" />
- <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Puts a memory barrier in place. This is used for synchronization to avoid data races. See also [method full_barrier], which may be useful for debugging.
</description>
@@ -27,7 +27,7 @@
<param index="0" name="buffer" type="RID" />
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
</description>
</method>
@@ -46,7 +46,7 @@
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
<param index="3" name="data" type="PackedByteArray" />
- <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
</description>
</method>
@@ -114,7 +114,7 @@
</method>
<method name="compute_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Finishes a list of compute commands created with the [code]compute_*[/code] methods.
</description>
@@ -296,7 +296,7 @@
</method>
<method name="draw_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Finishes a list of raster drawing commands created with the [code]draw_*[/code] methods.
</description>
@@ -534,7 +534,7 @@
<param index="5" name="multisample_state" type="RDPipelineMultisampleState" />
<param index="6" name="stencil_state" type="RDPipelineDepthStencilState" />
<param index="7" name="color_blend_state" type="RDPipelineColorBlendState" />
- <param index="8" name="dynamic_state_flags" type="int" enum="RenderingDevice.PipelineDynamicStateFlags" default="0" />
+ <param index="8" name="dynamic_state_flags" type="int" enum="RenderingDevice.PipelineDynamicStateFlags" is_bitfield="true" default="0" />
<param index="9" name="for_render_pass" type="int" default="0" />
<param index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
<description>
@@ -643,7 +643,7 @@
<return type="RID" />
<param index="0" name="size_bytes" type="int" />
<param index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
- <param index="2" name="usage" type="int" enum="RenderingDevice.StorageBufferUsage" default="0" />
+ <param index="2" name="usage" type="int" enum="RenderingDevice.StorageBufferUsage" is_bitfield="true" default="0" />
<description>
Creates a [url=https://vkguide.dev/docs/chapter-4/storage_buffers/]storage buffer[/url] with the specified [param data] and [param usage]. It can be accessed with the RID that is returned.
Once finished with your RID, you will want to free the RID using the RenderingDevice's [method free_rid] method.
@@ -682,7 +682,7 @@
<param index="3" name="mipmap_count" type="int" />
<param index="4" name="base_layer" type="int" />
<param index="5" name="layer_count" type="int" />
- <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Clears the specified [param texture] by replacing all of its pixels with the specified [param color]. [param base_mipmap] and [param mipmap_count] determine which mipmaps of the texture are affected by this clear operation, while [param base_layer] and [param layer_count] determine which layers of a 3D texture (or texture array) are affected by this clear operation. For 2D textures (which only have one layer by design), [param base_layer] and [param layer_count] must both be [code]0[/code].
[b]Note:[/b] [param texture] can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to clear this texture.
@@ -699,7 +699,7 @@
<param index="6" name="dst_mipmap" type="int" />
<param index="7" name="src_layer" type="int" />
<param index="8" name="dst_layer" type="int" />
- <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Copies the [param from_texture] to [param to_texture] with the specified [param from_pos], [param to_pos] and [param size] coordinates. The Z axis of the [param from_pos], [param to_pos] and [param size] must be [code]0[/code] for 2-dimensional textures. Source and destination mipmaps/layers must also be specified, with these parameters being [code]0[/code] for textures without mipmaps or single-layer textures. Returns [constant @GlobalScope.OK] if the texture copy was successful or [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to copy this texture.
@@ -763,7 +763,7 @@
<method name="texture_is_format_supported_for_usage" qualifiers="const">
<return type="bool" />
<param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
- <param index="1" name="usage_flags" type="int" enum="RenderingDevice.TextureUsageBits" />
+ <param index="1" name="usage_flags" type="int" enum="RenderingDevice.TextureUsageBits" is_bitfield="true" />
<description>
Returns [code]true[/code] if the specified [param format] is supported for the given [param usage_flags], [code]false[/code] otherwise.
</description>
@@ -786,7 +786,7 @@
<return type="int" enum="Error" />
<param index="0" name="from_texture" type="RID" />
<param index="1" name="to_texture" type="RID" />
- <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Resolves the [param from_texture] texture onto [param to_texture] with multisample antialiasing enabled. This must be used when rendering a framebuffer for MSAA to work. Returns [constant @GlobalScope.OK] if successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] and [param to_texture] textures must have the same dimension, format and type (color or depth).
@@ -803,7 +803,7 @@
<param index="0" name="texture" type="RID" />
<param index="1" name="layer" type="int" />
<param index="2" name="data" type="PackedByteArray" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" />
+ <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
<description>
Updates texture data with new data, replacing the previous data in place. The updated texture data must have the same dimensions and format. For 2D textures (which only have one layer), [param layer] must be [code]0[/code]. Returns [constant @GlobalScope.OK] if the update was successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] Updating textures is forbidden during creation of a draw or compute list.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 6b65302a7d..878b685c67 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -2096,7 +2096,7 @@
<param index="2" name="arrays" type="Array" />
<param index="3" name="blend_shapes" type="Array" default="[]" />
<param index="4" name="lods" type="Dictionary" default="{}" />
- <param index="5" name="compress_format" type="int" enum="RenderingServer.ArrayFormat" default="0" />
+ <param index="5" name="compress_format" type="int" enum="RenderingServer.ArrayFormat" is_bitfield="true" default="0" />
<description>
</description>
</method>
@@ -2199,14 +2199,14 @@
</method>
<method name="mesh_surface_get_format_attribute_stride" qualifiers="const">
<return type="int" />
- <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" />
+ <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" is_bitfield="true" />
<param index="1" name="vertex_count" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_format_offset" qualifiers="const">
<return type="int" />
- <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" />
+ <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" is_bitfield="true" />
<param index="1" name="vertex_count" type="int" />
<param index="2" name="array_index" type="int" />
<description>
@@ -2214,14 +2214,14 @@
</method>
<method name="mesh_surface_get_format_skin_stride" qualifiers="const">
<return type="int" />
- <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" />
+ <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" is_bitfield="true" />
<param index="1" name="vertex_count" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_format_vertex_stride" qualifiers="const">
<return type="int" />
- <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" />
+ <param index="0" name="format" type="int" enum="RenderingServer.ArrayFormat" is_bitfield="true" />
<param index="1" name="vertex_count" type="int" />
<description>
</description>
@@ -4575,7 +4575,7 @@
Number of objects drawn in a single frame.
</constant>
<constant name="VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME" value="1" enum="ViewportRenderInfo">
- Number of vertices drawn in a single frame.
+ Number of points, lines, or triangles drawn in a single frame.
</constant>
<constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="2" enum="ViewportRenderInfo">
Number of draw calls during this frame.
@@ -5201,7 +5201,7 @@
Number of objects rendered in the current 3D scene. This varies depending on camera position and rotation.
</constant>
<constant name="RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME" value="1" enum="RenderingInfo">
- Number of vertices/indices rendered in the current 3D scene. This varies depending on camera position and rotation.
+ Number of points, lines, or triangles rendered in the current 3D scene. This varies depending on camera position and rotation.
</constant>
<constant name="RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME" value="2" enum="RenderingInfo">
Number of draw calls performed to render in the current 3D scene. This varies depending on camera position and rotation.
@@ -5210,10 +5210,10 @@
Texture memory used (in bytes).
</constant>
<constant name="RENDERING_INFO_BUFFER_MEM_USED" value="4" enum="RenderingInfo">
- Buffer memory used (in bytes).
+ Buffer memory used (in bytes). This includes vertex data, uniform buffers, and many miscellaneous buffer types used internally.
</constant>
<constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo">
- Video memory used (in bytes). This is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics.
+ Video memory used (in bytes). When using the Forward+ or mobile rendering backends, this is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics. When using the GL Compatibility backend, this is equal to the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED].
</constant>
<constant name="FEATURE_SHADERS" value="0" enum="Features">
Hardware supports shaders. This enum is currently unused in Godot 3.x.
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index f173f34c5a..9d19d81f05 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -37,7 +37,7 @@
<return type="int" enum="Error" />
<param index="0" name="resource" type="Resource" />
<param index="1" name="path" type="String" default="&quot;&quot;" />
- <param index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" default="0" />
+ <param index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" is_bitfield="true" default="0" />
<description>
Saves a resource to disk to the given path, using a [ResourceFormatSaver] that recognizes the resource object. If [param path] is empty, [ResourceSaver] will try to use [member Resource.resource_path].
The [param flags] bitmask can be specified to customize the save behavior using [enum SaverFlags] flags.
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 44936925ce..6fbdb4faad 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -410,7 +410,7 @@
<param index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0" />
<param index="2" name="language" type="String" default="&quot;&quot;" />
<param index="3" name="st_parser" type="int" enum="TextServer.StructuredTextParser" default="0" />
- <param index="4" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="163" />
+ <param index="4" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="163" />
<param index="5" name="tab_stops" type="PackedFloat32Array" default="PackedFloat32Array()" />
<description>
Adds a [code][p][/code] tag to the tag stack.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index ce793deec1..789d9695fa 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -61,7 +61,7 @@
<param index="2" name="process_in_physics" type="bool" default="false" />
<param index="3" name="ignore_time_scale" type="bool" default="false" />
<description>
- Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree].
+ Returns a [SceneTreeTimer] which will emit [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree].
If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
If [param process_in_physics] is set to [code]true[/code], will update the [SceneTreeTimer] during the physics frame instead of the process frame (fixed framerate processing).
If [param ignore_time_scale] is set to [code]true[/code], will ignore [member Engine.time_scale] and update the [SceneTreeTimer] with the actual frame delta.
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index 8fbd97e78b..e276ca6903 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -60,7 +60,7 @@
<member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
If [code]true[/code], the [SpinBox] will select the whole text when the [LineEdit] gains focus. Clicking the up and down arrows won't trigger this behavior.
</member>
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="1" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
<member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
Adds the specified [code]suffix[/code] string after the numerical value of the [SpinBox].
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index d042a0b9a7..55a5ea18f2 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -1088,6 +1088,9 @@
</method>
</methods>
<members>
+ <member name="autowrap_mode" type="int" setter="set_autowrap_mode" getter="get_autowrap_mode" enum="TextServer.AutowrapMode" default="3">
+ If [member wrap_mode] is set to [constant LINE_WRAPPING_BOUNDARY], sets text wrapping mode. To see how each mode behaves, see [enum TextServer.AutowrapMode].
+ </member>
<member name="caret_blink" type="bool" setter="set_caret_blink_enabled" getter="is_caret_blink_enabled" default="false">
If [code]true[/code], makes the caret blink.
</member>
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index 93cd8065e2..e9bdd67167 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -151,7 +151,7 @@
<member name="direction" type="int" setter="set_direction" getter="get_direction" enum="TextServer.Direction" default="0">
Text writing direction.
</member>
- <member name="flags" type="int" setter="set_flags" getter="get_flags" enum="TextServer.JustificationFlag" default="3">
+ <member name="flags" type="int" setter="set_flags" getter="get_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="3">
Line alignment rules. For more info see [TextServer].
</member>
<member name="orientation" type="int" setter="set_orientation" getter="get_orientation" enum="TextServer.Orientation" default="0">
diff --git a/doc/classes/TextMesh.xml b/doc/classes/TextMesh.xml
index 9258dca657..e1999c5f6a 100644
--- a/doc/classes/TextMesh.xml
+++ b/doc/classes/TextMesh.xml
@@ -29,7 +29,7 @@
<member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="1">
Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants.
</member>
- <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" default="163">
+ <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163">
Line fill alignment rules. For more info see [enum TextServer.JustificationFlag].
</member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index c7e9880fe7..2452c9d262 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -265,7 +265,7 @@
<member name="alignment" type="int" setter="set_alignment" getter="get_alignment" enum="HorizontalAlignment" default="0">
Paragraph horizontal alignment.
</member>
- <member name="break_flags" type="int" setter="set_break_flags" getter="get_break_flags" enum="TextServer.LineBreakFlag" default="3">
+ <member name="break_flags" type="int" setter="set_break_flags" getter="get_break_flags" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3">
Line breaking rules. For more info see [TextServer].
</member>
<member name="custom_punctuation" type="String" setter="set_custom_punctuation" getter="get_custom_punctuation" default="&quot;&quot;">
@@ -274,7 +274,7 @@
<member name="direction" type="int" setter="set_direction" getter="get_direction" enum="TextServer.Direction" default="0">
Text writing direction.
</member>
- <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" default="163">
+ <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163">
Line fill alignment rules. For more info see [enum TextServer.JustificationFlag].
</member>
<member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1">
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 6d4ecb255e..17805f259c 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -386,7 +386,7 @@
</description>
</method>
<method name="font_get_style" qualifiers="const">
- <return type="int" enum="TextServer.FontStyle" />
+ <return type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<param index="0" name="font_rid" type="RID" />
<description>
Returns font style flags, see [enum FontStyle].
@@ -840,7 +840,7 @@
<method name="font_set_style">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
- <param index="1" name="style" type="int" enum="TextServer.FontStyle" />
+ <param index="1" name="style" type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<description>
Sets the font style flags, see [enum FontStyle].
[b]Note:[/b] This value is used for font matching only and will not affect font rendering. Use [method font_set_face_index], [method font_set_variation_coordinates], [method font_set_embolden], or [method font_set_transform] instead.
@@ -1168,7 +1168,7 @@
<return type="float" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" />
- <param index="2" name="justification_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="2" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" default="3" />
<description>
Adjusts text width to fit to specified width, returns new text width.
</description>
@@ -1275,7 +1275,7 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" />
<param index="2" name="start" type="int" default="0" />
- <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
<description>
Breaks text to the lines and returns character ranges for each line.
</description>
@@ -1286,7 +1286,7 @@
<param index="1" name="width" type="PackedFloat32Array" />
<param index="2" name="start" type="int" default="0" />
<param index="3" name="once" type="bool" default="true" />
- <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" default="3" />
<description>
Breaks text to the lines and columns. Returns character ranges for each segment.
</description>
@@ -1397,7 +1397,7 @@
<method name="shaped_text_get_word_breaks" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="shaped" type="RID" />
- <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" default="264" />
+ <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" is_bitfield="true" default="264" />
<description>
Breaks text into words and returns array of character ranges. Use [param grapheme_flags] to set what characters are used for breaking (see [enum GraphemeFlag]).
</description>
@@ -1444,7 +1444,7 @@
<return type="void" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" default="0" />
- <param index="2" name="overrun_trim_flags" type="int" enum="TextServer.TextOverrunFlag" default="0" />
+ <param index="2" name="overrun_trim_flags" type="int" enum="TextServer.TextOverrunFlag" is_bitfield="true" default="0" />
<description>
Trims text if it exceeds the given width.
</description>
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 7efd5a2a75..3240b025bf 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -332,7 +332,7 @@
</description>
</method>
<method name="_font_get_style" qualifiers="virtual const">
- <return type="int" enum="TextServer.FontStyle" />
+ <return type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<param index="0" name="font_rid" type="RID" />
<description>
</description>
@@ -734,7 +734,7 @@
<method name="_font_set_style" qualifiers="virtual">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
- <param index="1" name="style" type="int" enum="TextServer.FontStyle" />
+ <param index="1" name="style" type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<description>
</description>
</method>
@@ -1008,7 +1008,7 @@
<return type="float" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" />
- <param index="2" name="justification_flags" type="int" enum="TextServer.JustificationFlag" />
+ <param index="2" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" />
<description>
</description>
</method>
@@ -1100,7 +1100,7 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" />
<param index="2" name="start" type="int" />
- <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
+ <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" />
<description>
</description>
</method>
@@ -1110,7 +1110,7 @@
<param index="1" name="width" type="PackedFloat32Array" />
<param index="2" name="start" type="int" />
<param index="3" name="once" type="bool" />
- <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
+ <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" />
<description>
</description>
</method>
@@ -1205,7 +1205,7 @@
<method name="_shaped_text_get_word_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
<param index="0" name="shaped" type="RID" />
- <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" />
+ <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" is_bitfield="true" />
<description>
</description>
</method>
@@ -1240,7 +1240,7 @@
<return type="void" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="width" type="float" />
- <param index="2" name="trim_flags" type="int" enum="TextServer.TextOverrunFlag" />
+ <param index="2" name="trim_flags" type="int" enum="TextServer.TextOverrunFlag" is_bitfield="true" />
<description>
</description>
</method>
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index c969573d37..5fd90e6b4d 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -43,7 +43,7 @@
<member name="radial_initial_angle" type="float" setter="set_radial_initial_angle" getter="get_radial_initial_angle" default="0.0">
Starting angle for the fill of [member texture_progress] if [member fill_mode] is [constant FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its [code]min_value[/code], the texture doesn't show up at all. When the [code]value[/code] increases, the texture fills and tends towards [member radial_fill_degrees].
</member>
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="1" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
<member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="stretch_margin_bottom" type="int" setter="set_stretch_margin" getter="get_stretch_margin" default="0">
The height of the 9-patch's bottom row. A margin of 16 means the 9-slice's bottom corners and side will have a height of 16 pixels. You can set all 4 margin values individually to create panels with non-uniform borders.
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 51efbd31d8..bbb4e1b4e3 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -88,7 +88,7 @@
[/csharp]
[/codeblocks]
Some [Tweener]s use transitions and eases. The first accepts a [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best.
- [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url]
+ [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.webp]Tween easing and transition types cheatsheet[/url]
[b]Note:[/b] Tweens are not designed to be re-used and trying to do so results in an undefined behavior. Create a new Tween for each animation and every time you replay an animation from start. Keep in mind that Tweens start immediately, so only create a Tween when you want to start animating.
[b]Note:[/b] Tweens are processing after all of nodes in the current frame, i.e. after [method Node._process] or [method Node._physics_process] (depending on [enum TweenProcessMode]).
</description>
diff --git a/doc/classes/VScrollBar.xml b/doc/classes/VScrollBar.xml
index 3a6acb529a..9ecbcdef8a 100644
--- a/doc/classes/VScrollBar.xml
+++ b/doc/classes/VScrollBar.xml
@@ -9,8 +9,8 @@
<tutorials>
</tutorials>
<members>
- <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" default="0" />
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="1" />
+ <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="0" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
</members>
<theme_items>
<theme_item name="decrement" data_type="icon" type="Texture2D">
diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml
index 5c1d61d0f9..964facc45c 100644
--- a/doc/classes/VSlider.xml
+++ b/doc/classes/VSlider.xml
@@ -9,8 +9,8 @@
<tutorials>
</tutorials>
<members>
- <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" default="0" />
- <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" default="1" />
+ <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="0" />
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
</members>
<theme_items>
<theme_item name="center_grabber" data_type="constant" type="int" default="0">
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 2594fa8cbd..7cc05087b7 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -27,7 +27,7 @@ MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>"
# Used to translate section headings and other hardcoded strings when required with
# the --lang argument. The BASE_STRINGS list should be synced with what we actually
# write in this script (check `translate()` uses), and also hardcoded in
-# `doc/translations/extract.py` to include them in the source POT file.
+# `scripts/extract_classes.py` (godotengine/godot-editor-l10n repo) to include them in the source POT file.
BASE_STRINGS = [
"All classes",
"Globals",
@@ -65,6 +65,7 @@ BASE_STRINGS = [
"This method is used to construct a type.",
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
"This method describes a valid operator to use with this type as left-hand operand.",
+ "This value is an integer composed as a bitmask of the following flags.",
]
strings_l10n: Dict[str, str] = {}
@@ -362,13 +363,14 @@ class State:
class TypeName:
- def __init__(self, type_name: str, enum: Optional[str] = None) -> None:
+ def __init__(self, type_name: str, enum: Optional[str] = None, is_bitfield: bool = False) -> None:
self.type_name = type_name
self.enum = enum
+ self.is_bitfield = is_bitfield
def to_rst(self, state: State) -> str:
if self.enum is not None:
- return make_enum(self.enum, state)
+ return make_enum(self.enum, self.is_bitfield, state)
elif self.type_name == "void":
return "void"
else:
@@ -376,7 +378,7 @@ class TypeName:
@classmethod
def from_element(cls, element: ET.Element) -> "TypeName":
- return cls(element.attrib["type"], element.get("enum"))
+ return cls(element.attrib["type"], element.get("enum"), element.get("is_bitfield") == "true")
class DefinitionBase:
@@ -1280,7 +1282,7 @@ def make_type(klass: str, state: State) -> str:
return klass
-def make_enum(t: str, state: State) -> str:
+def make_enum(t: str, is_bitfield: bool, state: State) -> str:
p = t.find(".")
if p >= 0:
c = t[0:p]
@@ -1296,7 +1298,12 @@ def make_enum(t: str, state: State) -> str:
c = "@GlobalScope"
if c in state.classes and e in state.classes[c].enums:
- return f":ref:`{e}<enum_{c}_{e}>`"
+ if is_bitfield:
+ if not state.classes[c].enums[e].is_bitfield:
+ print_error(f'{state.current_class}.xml: Enum "{t}" is not bitfield.', state)
+ return f"|bitfield|\<:ref:`{e}<enum_{c}_{e}>`\>"
+ else:
+ return f":ref:`{e}<enum_{c}_{e}>`"
# Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
if f"{c}.{e}" != "Vector3.Axis":
@@ -1412,6 +1419,7 @@ def make_footer() -> str:
"This method doesn't need an instance to be called, so it can be called directly using the class name."
)
operator_msg = translate("This method describes a valid operator to use with this type as left-hand operand.")
+ bitfield_msg = translate("This value is an integer composed as a bitmask of the following flags.")
return (
f".. |virtual| replace:: :abbr:`virtual ({virtual_msg})`\n"
@@ -1420,6 +1428,7 @@ def make_footer() -> str:
f".. |constructor| replace:: :abbr:`constructor ({constructor_msg})`\n"
f".. |static| replace:: :abbr:`static ({static_msg})`\n"
f".. |operator| replace:: :abbr:`operator ({operator_msg})`\n"
+ f".. |bitfield| replace:: :abbr:`BitField ({bitfield_msg})`\n"
)
@@ -1834,7 +1843,7 @@ def format_text_block(
escape_post = True
elif cmd.startswith("enum"):
- tag_text = make_enum(link_target, state)
+ tag_text = make_enum(link_target, False, state)
escape_pre = True
escape_post = True
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 59a65b4538..86405fa3f0 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1790,6 +1790,7 @@ void RasterizerCanvasGLES3::_update_shadow_atlas() {
state.shadow_depth_buffer = 0;
WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
}
+ GLES3::Utilities::get_singleton()->texture_allocated_data(state.shadow_texture, state.shadow_texture_size * data.max_lights_per_render * 2 * 4, "2D shadow atlas texture");
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
}
}
@@ -1894,8 +1895,8 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
if (oc->line_point_count != lines.size() && oc->vertex_array != 0) {
glDeleteVertexArrays(1, &oc->vertex_array);
- glDeleteBuffers(1, &oc->vertex_buffer);
- glDeleteBuffers(1, &oc->index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(oc->vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(oc->index_buffer);
oc->vertex_array = 0;
oc->vertex_buffer = 0;
@@ -1954,13 +1955,15 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
glGenBuffers(1, &oc->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, oc->vertex_buffer, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW, "Occluder polygon vertex buffer");
+
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glGenBuffers(1, &oc->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW, "Occluder polygon index buffer");
+
glBindVertexArray(0);
} else {
glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
@@ -1995,8 +1998,8 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array != 0) {
glDeleteVertexArrays(1, &oc->sdf_vertex_array);
- glDeleteBuffers(1, &oc->sdf_vertex_buffer);
- glDeleteBuffers(1, &oc->sdf_index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(oc->sdf_vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(oc->sdf_index_buffer);
oc->sdf_vertex_array = 0;
oc->sdf_vertex_buffer = 0;
@@ -2015,13 +2018,15 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
glGenBuffers(1, &oc->sdf_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer, oc->sdf_point_count * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW, "Occluder polygon SDF vertex buffer");
+
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
glGenBuffers(1, &oc->sdf_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer, oc->sdf_index_count * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW, "Occluder polygon SDF index buffer");
+
glBindVertexArray(0);
} else {
glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
@@ -2410,7 +2415,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
}
ERR_FAIL_COND_V(base_offset != stride, 0);
- glBufferData(GL_ARRAY_BUFFER, vertex_count * stride * sizeof(float), polygon_buffer.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, pb.vertex_buffer, vertex_count * stride * sizeof(float), polygon_buffer.ptr(), GL_STATIC_DRAW, "Polygon 2D vertex buffer");
}
if (p_indices.size()) {
@@ -2423,7 +2428,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
}
glGenBuffers(1, &pb.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW, "Polygon 2D index buffer");
pb.count = p_indices.size();
}
@@ -2444,11 +2449,11 @@ void RasterizerCanvasGLES3::free_polygon(PolygonID p_polygon) {
PolygonBuffers &pb = *pb_ptr;
if (pb.index_buffer != 0) {
- glDeleteBuffers(1, &pb.index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(pb.index_buffer);
}
glDeleteVertexArrays(1, &pb.vertex_array);
- glDeleteBuffers(1, &pb.vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(pb.vertex_buffer);
polygon_buffers.polygons.erase(p_polygon);
}
@@ -2462,13 +2467,13 @@ void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
glGenBuffers(3, new_buffers);
// Batch UBO.
glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
- glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffers[0], data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "2D Batch UBO[" + itos(state.current_data_buffer_index) + "][0]");
// Light uniform buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[1], sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW, "2D Lights UBO[" + itos(state.current_data_buffer_index) + "]");
// State buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[2], sizeof(StateBuffer), nullptr, GL_STREAM_DRAW, "2D State UBO[" + itos(state.current_data_buffer_index) + "]");
state.current_data_buffer_index = (state.current_data_buffer_index + 1);
DataBuffer db;
@@ -2493,7 +2498,7 @@ void RasterizerCanvasGLES3::_allocate_instance_buffer() {
glGenBuffers(1, &new_buffer);
glBindBuffer(GL_ARRAY_BUFFER, new_buffer);
- glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffer, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "Batch UBO[" + itos(state.current_data_buffer_index) + "][" + itos(state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.size()) + "]");
state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(new_buffer);
@@ -2656,13 +2661,13 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
glGenBuffers(3, new_buffers);
// Batch UBO.
glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
- glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffers[0], data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "Batch UBO[0][0]");
// Light uniform buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[1], sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW, "2D lights UBO[0]");
// State buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[2], sizeof(StateBuffer), nullptr, GL_STREAM_DRAW, "2D state UBO[0]");
DataBuffer db;
db.instance_buffers.push_back(new_buffers[0]);
db.light_ubo = new_buffers[1];
@@ -2779,12 +2784,26 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
if (state.shadow_fb != 0) {
glDeleteFramebuffers(1, &state.shadow_fb);
- glDeleteTextures(1, &state.shadow_texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(state.shadow_texture);
glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
state.shadow_fb = 0;
state.shadow_texture = 0;
state.shadow_depth_buffer = 0;
}
+
+ for (uint32_t i = 0; i < state.canvas_instance_data_buffers.size(); i++) {
+ for (int j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) {
+ if (state.canvas_instance_data_buffers[i].instance_buffers[j]) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].instance_buffers[j]);
+ }
+ }
+ if (state.canvas_instance_data_buffers[i].light_ubo) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].light_ubo);
+ }
+ if (state.canvas_instance_data_buffers[i].state_ubo) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].state_ubo);
+ }
+ }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 3d8f7924a7..6ed5b3b2f8 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -443,8 +443,10 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
if (p_sky->radiance != 0) {
- glDeleteTextures(1, &p_sky->radiance);
+ GLES3::Utilities::get_singleton()->texture_free_data(p_sky->radiance);
p_sky->radiance = 0;
+ GLES3::Utilities::get_singleton()->texture_free_data(p_sky->raw_radiance);
+ p_sky->raw_radiance = 0;
glDeleteFramebuffers(1, &p_sky->radiance_framebuffer);
p_sky->radiance_framebuffer = 0;
}
@@ -546,6 +548,8 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(sky->radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky radiance map");
+
glGenTextures(1, &sky->raw_radiance);
glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
@@ -568,6 +572,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(sky->raw_radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky raw radiance map");
}
sky->reflection_dirty = true;
@@ -1154,6 +1159,11 @@ void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_inst
void RasterizerSceneGLES3::voxel_gi_set_quality(RS::VoxelGIQuality) {
}
+_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
+ static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
+ static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
+ return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
+}
void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
@@ -1258,7 +1268,8 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
uint32_t indices = 0;
surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, indices);
- /*
+ surf->index_count = indices;
+
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1267,21 +1278,20 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
}
}
- */
+
} else {
surf->lod_index = 0;
- /*
+
if (p_render_data->render_info) {
uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
to_draw = _indices_to_primitives(surf->primitive, to_draw);
- to_draw *= inst->instance_count;
+ to_draw *= inst->instance_count > 0 ? inst->instance_count : 1;
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
}
}
- */
}
// ADD Element
@@ -1451,17 +1461,26 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
if (scene_state.ubo_buffer == 0) {
glGenBuffers(1, &scene_state.ubo_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.ubo_buffer, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW, "Scene state UBO");
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ } else {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
}
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
+
glBindBuffer(GL_UNIFORM_BUFFER, 0);
if (p_render_data->view_count > 1) {
if (scene_state.multiview_buffer == 0) {
glGenBuffers(1, &scene_state.multiview_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.multiview_buffer, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW, "Multiview UBO");
+ } else {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
}
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
+
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
}
@@ -1792,9 +1811,14 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (scene_state.tonemap_buffer == 0) {
// Only create if using 3D
glGenBuffers(1, &scene_state.tonemap_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.tonemap_buffer, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW, "Tonemap UBO");
+ } else {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
}
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
@@ -2086,6 +2110,12 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
bool should_request_redraw = false;
+ if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
+ // Don't count elements during depth pre-pass to match the RD renderers.
+ if (p_render_data->render_info) {
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += p_to_element - p_from_element;
+ }
+ }
for (uint32_t i = p_from_element; i < p_to_element; i++) {
const GeometryInstanceSurface *surf = p_params->elements[i];
@@ -2326,6 +2356,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
+
+ // Can be index count or vertex count
+ uint32_t count = 0;
+ if (surf->lod_index > 0) {
+ count = surf->index_count;
+ } else {
+ count = mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface);
+ }
+ if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
+ // Don't count draw calls during depth pre-pass to match the RD renderers.
+ if (p_render_data->render_info) {
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++;
+ }
+ }
+
if (inst->instance_count > 0) {
// Using MultiMesh or Particles.
// Bind instance buffers.
@@ -2366,16 +2411,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glVertexAttribDivisor(15, 1);
}
if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+ glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
} else {
- glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), inst->instance_count);
+ glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count);
}
} else {
// Using regular Mesh.
if (use_index_buffer) {
- glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
} else {
- glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface));
+ glDrawArrays(primitive_gl, 0, count);
}
}
if (inst->instance_count > 0) {
@@ -2579,19 +2624,20 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
scene_state.omni_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
glGenBuffers(1, &scene_state.omni_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
- glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer, light_buffer_size, nullptr, GL_STREAM_DRAW, "OmniLight UBO");
scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
scene_state.spot_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
glGenBuffers(1, &scene_state.spot_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
- glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer, light_buffer_size, nullptr, GL_STREAM_DRAW, "SpotLight UBO");
uint32_t directional_light_buffer_size = MAX_DIRECTIONAL_LIGHTS * sizeof(DirectionalLightData);
scene_state.directional_lights = memnew_arr(DirectionalLightData, MAX_DIRECTIONAL_LIGHTS);
glGenBuffers(1, &scene_state.directional_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer);
- glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer, directional_light_buffer_size, nullptr, GL_STREAM_DRAW, "DirectionalLight UBO");
+
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -2603,7 +2649,8 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
sky_globals.last_frame_directional_light_count = sky_globals.max_directional_lights + 1;
glGenBuffers(1, &sky_globals.directional_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer);
- glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer, directional_light_buffer_size, nullptr, GL_STREAM_DRAW, "Sky DirectionalLight UBO");
+
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -2702,6 +2749,8 @@ void sky() {
}
{
+ glGenVertexArrays(1, &sky_globals.screen_triangle_array);
+ glBindVertexArray(sky_globals.screen_triangle_array);
glGenBuffers(1, &sky_globals.screen_triangle);
glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
@@ -2714,12 +2763,8 @@ void sky() {
3.0f,
};
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, sky_globals.screen_triangle, sizeof(float) * 6, qv, GL_STATIC_DRAW, "Screen triangle vertex buffer");
- glGenVertexArrays(1, &sky_globals.screen_triangle_array);
- glBindVertexArray(sky_globals.screen_triangle_array);
- glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glBindVertexArray(0);
@@ -2735,9 +2780,9 @@ void sky() {
}
RasterizerSceneGLES3::~RasterizerSceneGLES3() {
- glDeleteBuffers(1, &scene_state.directional_light_buffer);
- glDeleteBuffers(1, &scene_state.omni_light_buffer);
- glDeleteBuffers(1, &scene_state.spot_light_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.directional_light_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.omni_light_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.spot_light_buffer);
memdelete_arr(scene_state.directional_lights);
memdelete_arr(scene_state.omni_lights);
memdelete_arr(scene_state.spot_lights);
@@ -2756,13 +2801,26 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() {
RSG::material_storage->shader_free(sky_globals.default_shader);
RSG::material_storage->material_free(sky_globals.fog_material);
RSG::material_storage->shader_free(sky_globals.fog_shader);
- glDeleteBuffers(1, &sky_globals.screen_triangle);
+ GLES3::Utilities::get_singleton()->buffer_free_data(sky_globals.screen_triangle);
glDeleteVertexArrays(1, &sky_globals.screen_triangle_array);
glDeleteTextures(1, &sky_globals.radical_inverse_vdc_cache_tex);
- glDeleteBuffers(1, &sky_globals.directional_light_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(sky_globals.directional_light_buffer);
memdelete_arr(sky_globals.directional_lights);
memdelete_arr(sky_globals.last_frame_directional_lights);
+ // UBOs
+ if (scene_state.ubo_buffer != 0) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.ubo_buffer);
+ }
+
+ if (scene_state.multiview_buffer != 0) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.multiview_buffer);
+ }
+
+ if (scene_state.tonemap_buffer != 0) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.tonemap_buffer);
+ }
+
singleton = nullptr;
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index b4e787ad85..9709d6be2a 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -220,6 +220,7 @@ private:
uint32_t flags = 0;
uint32_t surface_index = 0;
uint32_t lod_index = 0;
+ uint32_t index_count = 0;
void *surface = nullptr;
GLES3::SceneShaderData *shader = nullptr;
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 8da5e657cd..5aab91e8ae 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -595,106 +595,6 @@ void LightStorage::lightmap_instance_free(RID p_lightmap) {
void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
}
-/* LIGHT SHADOW MAPPING */
-/*
-
-RID LightStorage::canvas_light_occluder_create() {
- CanvasOccluder *co = memnew(CanvasOccluder);
- co->index_id = 0;
- co->vertex_id = 0;
- co->len = 0;
-
- return canvas_occluder_owner.make_rid(co);
-}
-
-void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
- CanvasOccluder *co = canvas_occluder_owner.get(p_occluder);
- ERR_FAIL_COND(!co);
-
- co->lines = p_lines;
-
- if (p_lines.size() != co->len) {
- if (co->index_id) {
- glDeleteBuffers(1, &co->index_id);
- } if (co->vertex_id) {
- glDeleteBuffers(1, &co->vertex_id);
- }
-
- co->index_id = 0;
- co->vertex_id = 0;
- co->len = 0;
- }
-
- if (p_lines.size()) {
- PoolVector<float> geometry;
- PoolVector<uint16_t> indices;
- int lc = p_lines.size();
-
- geometry.resize(lc * 6);
- indices.resize(lc * 3);
-
- PoolVector<float>::Write vw = geometry.write();
- PoolVector<uint16_t>::Write iw = indices.write();
-
- PoolVector<Vector2>::Read lr = p_lines.read();
-
- const int POLY_HEIGHT = 16384;
-
- for (int i = 0; i < lc / 2; i++) {
- vw[i * 12 + 0] = lr[i * 2 + 0].x;
- vw[i * 12 + 1] = lr[i * 2 + 0].y;
- vw[i * 12 + 2] = POLY_HEIGHT;
-
- vw[i * 12 + 3] = lr[i * 2 + 1].x;
- vw[i * 12 + 4] = lr[i * 2 + 1].y;
- vw[i * 12 + 5] = POLY_HEIGHT;
-
- vw[i * 12 + 6] = lr[i * 2 + 1].x;
- vw[i * 12 + 7] = lr[i * 2 + 1].y;
- vw[i * 12 + 8] = -POLY_HEIGHT;
-
- vw[i * 12 + 9] = lr[i * 2 + 0].x;
- vw[i * 12 + 10] = lr[i * 2 + 0].y;
- vw[i * 12 + 11] = -POLY_HEIGHT;
-
- iw[i * 6 + 0] = i * 4 + 0;
- iw[i * 6 + 1] = i * 4 + 1;
- iw[i * 6 + 2] = i * 4 + 2;
-
- iw[i * 6 + 3] = i * 4 + 2;
- iw[i * 6 + 4] = i * 4 + 3;
- iw[i * 6 + 5] = i * 4 + 0;
- }
-
- //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
-
- if (!co->vertex_id) {
- glGenBuffers(1, &co->vertex_id);
- glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
- glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW);
- } else {
- glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
- glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr());
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
-
- if (!co->index_id) {
- glGenBuffers(1, &co->index_id);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW);
- } else {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
- glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr());
- }
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
-
- co->len = lc;
- }
-}
-*/
-
/* SHADOW ATLAS API */
RID LightStorage::shadow_atlas_create() {
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 473974fc7c..ce9cf78c12 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -2968,10 +2968,6 @@ void SceneShaderData::set_code(const String &p_code) {
WARN_PRINT_ONCE_ED("Transmittance is only available when using the Forward+ rendering backend.");
}
- if (uses_screen_texture) {
- WARN_PRINT_ONCE_ED("Reading from the screen texture is not supported when using the GL Compatibility backend yet. Support will be added in a future release.");
- }
-
if (uses_depth_texture) {
WARN_PRINT_ONCE_ED("Reading from the depth texture is not supported when using the GL Compatibility backend yet. Support will be added in a future release.");
}
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 585ed5ff96..ad4bdae272 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -193,26 +193,26 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
if (p_surface.vertex_data.size()) {
glGenBuffers(1, &s->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
s->vertex_buffer_size = p_surface.vertex_data.size();
}
if (p_surface.attribute_data.size()) {
glGenBuffers(1, &s->attribute_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
- glBufferData(GL_ARRAY_BUFFER, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer");
s->attribute_buffer_size = p_surface.attribute_data.size();
}
+
if (p_surface.skin_data.size()) {
glGenBuffers(1, &s->skin_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
- glBufferData(GL_ARRAY_BUFFER, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer");
s->skin_buffer_size = p_surface.skin_data.size();
}
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
s->vertex_count = p_surface.vertex_count;
if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
@@ -223,7 +223,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
glGenBuffers(1, &s->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
s->index_count = p_surface.index_count;
s->index_buffer_size = p_surface.index_data.size();
@@ -235,7 +235,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
for (int i = 0; i < p_surface.lods.size(); i++) {
glGenBuffers(1, &s->lods[i].index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
s->lods[i].edge_length = p_surface.lods[i].edge_length;
s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
@@ -282,7 +282,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
glBindVertexArray(s->blend_shapes[i].vertex_array);
glGenBuffers(1, &s->blend_shapes[i].vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer");
if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
glEnableVertexAttribArray(RS::ARRAY_VERTEX + 3);
@@ -633,11 +633,17 @@ void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
void MeshStorage::mesh_clear(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
+
+ // Clear instance data before mesh data.
+ for (MeshInstance *mi : mesh->instances) {
+ _mesh_instance_clear(mi);
+ }
+
for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];
if (s.vertex_buffer != 0) {
- glDeleteBuffers(1, &s.vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.vertex_buffer);
s.vertex_buffer = 0;
}
@@ -649,17 +655,17 @@ void MeshStorage::mesh_clear(RID p_mesh) {
}
if (s.attribute_buffer != 0) {
- glDeleteBuffers(1, &s.attribute_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.attribute_buffer);
s.attribute_buffer = 0;
}
if (s.skin_buffer != 0) {
- glDeleteBuffers(1, &s.skin_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.skin_buffer);
s.skin_buffer = 0;
}
if (s.index_buffer != 0) {
- glDeleteBuffers(1, &s.index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.index_buffer);
s.index_buffer = 0;
}
@@ -670,7 +676,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
if (s.lod_count) {
for (uint32_t j = 0; j < s.lod_count; j++) {
if (s.lods[j].index_buffer != 0) {
- glDeleteBuffers(1, &s.lods[j].index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.lods[j].index_buffer);
s.lods[j].index_buffer = 0;
}
}
@@ -680,7 +686,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
if (mesh->blend_shape_count) {
for (uint32_t j = 0; j < mesh->blend_shape_count; j++) {
if (s.blend_shapes[j].vertex_buffer != 0) {
- glDeleteBuffers(1, &s.blend_shapes[j].vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.blend_shapes[j].vertex_buffer);
s.blend_shapes[j].vertex_buffer = 0;
}
if (s.blend_shapes[j].vertex_array != 0) {
@@ -704,10 +710,6 @@ void MeshStorage::mesh_clear(RID p_mesh) {
mesh->surfaces = nullptr;
mesh->surface_count = 0;
mesh->material_cache.clear();
- //clear instance data
- for (MeshInstance *mi : mesh->instances) {
- _mesh_instance_clear(mi);
- }
mesh->has_bone_weights = false;
mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
@@ -916,13 +918,14 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
}
if (mi->surfaces[i].vertex_buffers[0] != 0) {
- glDeleteBuffers(2, mi->surfaces[i].vertex_buffers);
+ GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[0]);
+ GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[1]);
mi->surfaces[i].vertex_buffers[0] = 0;
mi->surfaces[i].vertex_buffers[1] = 0;
}
if (mi->surfaces[i].vertex_buffer != 0) {
- glDeleteBuffers(1, &mi->surfaces[i].vertex_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffer);
mi->surfaces[i].vertex_buffer = 0;
}
}
@@ -963,13 +966,13 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
// Buffer to be used for rendering. Final output of skeleton and blend shapes.
glGenBuffers(1, &s.vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
if (mesh->blend_shape_count > 0) {
// Ping-Pong buffers for processing blendshapes.
glGenBuffers(2, s.vertex_buffers);
for (uint32_t i = 0; i < 2; i++) {
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]);
- glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
@@ -1271,7 +1274,7 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
}
if (multimesh->buffer) {
- glDeleteBuffers(1, &multimesh->buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(multimesh->buffer);
multimesh->buffer = 0;
}
@@ -1298,7 +1301,7 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
if (multimesh->instances) {
glGenBuffers(1, &multimesh->buffer);
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
- glBufferData(GL_ARRAY_BUFFER, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW, "MultiMesh buffer");
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@@ -1958,7 +1961,7 @@ void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_
}
if (skeleton->transforms_texture != 0) {
- glDeleteTextures(1, &skeleton->transforms_texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(skeleton->transforms_texture);
skeleton->transforms_texture = 0;
skeleton->data.clear();
}
@@ -1973,6 +1976,7 @@ void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(skeleton->transforms_texture, skeleton->data.size() * sizeof(float), "Skeleton transforms texture");
memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index 4b64e2aec1..dbd86451d2 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -141,23 +141,23 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
if (particles->front_process_buffer != 0) {
glDeleteVertexArrays(1, &particles->front_vertex_array);
- glDeleteBuffers(1, &particles->front_process_buffer);
- glDeleteBuffers(1, &particles->front_instance_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_process_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_instance_buffer);
particles->front_vertex_array = 0;
particles->front_process_buffer = 0;
particles->front_instance_buffer = 0;
glDeleteVertexArrays(1, &particles->back_vertex_array);
- glDeleteBuffers(1, &particles->back_process_buffer);
- glDeleteBuffers(1, &particles->back_instance_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_process_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_instance_buffer);
particles->back_vertex_array = 0;
particles->back_process_buffer = 0;
particles->back_instance_buffer = 0;
}
if (particles->sort_buffer != 0) {
- glDeleteBuffers(1, &particles->last_frame_buffer);
- glDeleteBuffers(1, &particles->sort_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->last_frame_buffer);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->sort_buffer);
particles->last_frame_buffer = 0;
particles->sort_buffer = 0;
particles->sort_buffer_filled = false;
@@ -165,7 +165,7 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
}
if (particles->frame_params_ubo != 0) {
- glDeleteBuffers(1, &particles->frame_params_ubo);
+ GLES3::Utilities::get_singleton()->buffer_free_data(particles->frame_params_ubo);
particles->frame_params_ubo = 0;
}
}
@@ -680,10 +680,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
if (p_particles->frame_params_ubo == 0) {
glGenBuffers(1, &p_particles->frame_params_ubo);
+ glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, p_particles->frame_params_ubo, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW, "Particle Frame UBO");
+ } else {
+ // Update per-frame UBO.
+ glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
}
- // Update per-frame UBO.
- glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
// Get shader and set shader uniforms;
ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, RS::SHADER_PARTICLES));
@@ -831,7 +834,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glGenBuffers(1, &particles->front_instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles front process buffer");
for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
glEnableVertexAttribArray(j);
@@ -840,7 +843,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles front instance buffer");
}
{
@@ -850,7 +853,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glGenBuffers(1, &particles->back_instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles back process buffer");
for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
glEnableVertexAttribArray(j);
@@ -859,7 +862,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles back instance buffer");
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -871,11 +874,12 @@ void ParticlesStorage::_particles_allocate_history_buffers(Particles *particles)
if (particles->sort_buffer == 0) {
glGenBuffers(1, &particles->last_frame_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->last_frame_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->last_frame_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles last frame buffer");
glGenBuffers(1, &particles->sort_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
- glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->sort_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles sort buffer");
+
particles->sort_buffer_filled = false;
particles->last_frame_buffer_filled = false;
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -1179,7 +1183,7 @@ void ParticlesStorage::particles_collision_free(RID p_rid) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);
if (particles_collision->heightfield_texture != 0) {
- glDeleteTextures(1, &particles_collision->heightfield_texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
particles_collision->heightfield_texture = 0;
glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
particles_collision->heightfield_fb = 0;
@@ -1226,6 +1230,8 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p
WARN_PRINT("Could create heightmap texture status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
}
#endif
+ GLES3::Utilities::get_singleton()->texture_allocated_data(particles_collision->heightfield_texture, size.x * size.y * 4, "Particles collision heightfield texture");
+
particles_collision->heightfield_fb_size = size;
glBindTexture(GL_TEXTURE_2D, 0);
@@ -1244,7 +1250,7 @@ void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_co
}
if (particles_collision->heightfield_texture != 0) {
- glDeleteTextures(1, &particles_collision->heightfield_texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
particles_collision->heightfield_texture = 0;
glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
particles_collision->heightfield_fb = 0;
@@ -1319,7 +1325,7 @@ void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_par
particles_collision->heightfield_resolution = p_resolution;
if (particles_collision->heightfield_texture != 0) {
- glDeleteTextures(1, &particles_collision->heightfield_texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
particles_collision->heightfield_texture = 0;
glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
particles_collision->heightfield_fb = 0;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index c4fef89cfd..f362a21d8c 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -33,6 +33,7 @@
#include "texture_storage.h"
#include "config.h"
#include "drivers/gles3/effects/copy_effects.h"
+#include "utilities.h"
#ifdef ANDROID_ENABLED
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
@@ -164,6 +165,7 @@ TextureStorage::TextureStorage() {
glBindTexture(GL_TEXTURE_2D, texture.tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 4, 4, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pixel_data);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, 4 * 4 * 4, "Default uint texture");
texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
}
{
@@ -185,6 +187,7 @@ TextureStorage::TextureStorage() {
glBindTexture(GL_TEXTURE_2D, texture.tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 4, 4, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, pixel_data);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, 4 * 4 * 2, "Default depth texture");
texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
}
}
@@ -203,6 +206,7 @@ TextureStorage::TextureStorage() {
glGenTextures(1, &texture_atlas.texture);
glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture_atlas.texture, 4 * 4 * 4, "Texture atlas (Default)");
}
glBindTexture(GL_TEXTURE_2D, 0);
@@ -222,8 +226,9 @@ TextureStorage::~TextureStorage() {
for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) {
texture_free(default_gl_textures[i]);
}
-
- glDeleteTextures(1, &texture_atlas.texture);
+ if (texture_atlas.texture != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
+ }
texture_atlas.texture = 0;
glDeleteFramebuffers(1, &texture_atlas.framebuffer);
texture_atlas.framebuffer = 0;
@@ -706,7 +711,7 @@ void TextureStorage::texture_free(RID p_texture) {
if (t->tex_id != 0) {
if (!t->is_external) {
- glDeleteTextures(1, &t->tex_id);
+ GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id);
}
t->tex_id = 0;
}
@@ -743,9 +748,10 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D;
_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
- //texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
+ texture.total_data_size = p_image->get_image_data_size(texture.width, texture.height, texture.format, texture.mipmaps);
texture.active = true;
glGenTextures(1, &texture.tex_id);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture 2D");
texture_owner.initialize_rid(p_texture, texture);
texture_set_data(p_texture, p_image);
}
@@ -792,8 +798,10 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R
texture.target = p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY;
texture.layers = p_layers.size();
_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
+ texture.total_data_size = p_layers[0]->get_image_data_size(texture.width, texture.height, texture.format, texture.mipmaps) * texture.layers;
texture.active = true;
glGenTextures(1, &texture.tex_id);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture Layered");
texture_owner.initialize_rid(p_texture, texture);
for (int i = 0; i < p_layers.size(); i++) {
_texture_set_data(p_texture, p_layers[i], i, i == 0);
@@ -850,10 +858,12 @@ RID TextureStorage::texture_create_external(Texture::Type p_type, Image::Format
void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
texture_set_data(p_texture, p_image, p_layer);
-#ifdef TOOLS_ENABLED
+
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
+ GLES3::Utilities::get_singleton()->texture_resize_data(tex->tex_id, tex->total_data_size);
+#ifdef TOOLS_ENABLED
tex->image_cache_2d.unref();
#endif
}
@@ -1063,14 +1073,14 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
}
if (tex_to->tex_id) {
- glDeleteTextures(1, &tex_to->tex_id);
+ GLES3::Utilities::get_singleton()->texture_free_data(tex_to->tex_id);
tex_to->tex_id = 0;
}
Vector<RID> proxies_to_update = tex_to->proxies;
Vector<RID> proxies_to_redirect = tex_from->proxies;
- tex_to->copy_from(*tex_from);
+ *tex_to = *tex_from;
tex_to->proxies = proxies_to_update; //restore proxies, so they can be updated
@@ -1213,15 +1223,11 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
ERR_FAIL_COND(!p_image->get_width());
ERR_FAIL_COND(!p_image->get_height());
- // ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
-
GLenum type;
GLenum format;
GLenum internal_format;
bool compressed = false;
- // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
-
Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), real_format, format, internal_format, type, compressed, texture->resize_to_po2);
ERR_FAIL_COND(img.is_null());
@@ -1322,21 +1328,13 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
h = MAX(1, h >> 1);
}
- // info.texture_mem -= texture->total_data_size; // TODO make this work again!!
texture->total_data_size = tsize;
- // info.texture_mem += texture->total_data_size; // TODO make this work again!!
-
- // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
texture->stored_cube_sides |= (1 << p_layer);
texture->mipmaps = mipmaps;
}
-void TextureStorage::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
- ERR_PRINT("Not implemented yet, sorry :(");
-}
-
Image::Format TextureStorage::texture_get_format(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
@@ -1386,10 +1384,6 @@ void TextureStorage::texture_bind(RID p_texture, uint32_t p_texture_no) {
glBindTexture(texture->target, texture->tex_id);
}
-RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resolution) const {
- return RID();
-}
-
/* TEXTURE ATLAS API */
void TextureStorage::texture_add_to_texture_atlas(RID p_texture) {
@@ -1442,7 +1436,7 @@ void TextureStorage::update_texture_atlas() {
texture_atlas.dirty = false;
if (texture_atlas.texture != 0) {
- glDeleteTextures(1, &texture_atlas.texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
texture_atlas.texture = 0;
glDeleteFramebuffers(1, &texture_atlas.framebuffer);
texture_atlas.framebuffer = 0;
@@ -1559,6 +1553,7 @@ void TextureStorage::update_texture_atlas() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_atlas.size.width, texture_atlas.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(texture_atlas.texture, texture_atlas.size.width * texture_atlas.size.height * 4, "Texture atlas");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1576,7 +1571,7 @@ void TextureStorage::update_texture_atlas() {
if (status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &texture_atlas.framebuffer);
texture_atlas.framebuffer = 0;
- glDeleteTextures(1, &texture_atlas.texture);
+ GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
texture_atlas.texture = 0;
WARN_PRINT("Could not create texture atlas, status: " + get_framebuffer_error(status));
return;
@@ -1698,10 +1693,10 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
}
- glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * 4, "Render target color texture");
}
#ifndef IOS_ENABLED
if (use_multiview) {
@@ -1733,6 +1728,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target depth texture");
}
#ifndef IOS_ENABLED
if (use_multiview) {
@@ -1747,7 +1744,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &rt->fbo);
- glDeleteTextures(1, &rt->color);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->color);
rt->fbo = 0;
rt->size.x = 0;
rt->size.y = 0;
@@ -1805,8 +1802,10 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
glGenTextures(1, &rt->backbuffer);
glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
+ uint32_t texture_size_bytes = 0;
for (int l = 0; l < count; l++) {
+ texture_size_bytes += width * height * 4;
glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr);
width = MAX(1, (width / 2));
height = MAX(1, (height / 2));
@@ -1826,6 +1825,7 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
return;
}
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, texture_size_bytes, "Render target backbuffer color texture");
// Initialize all levels to opaque Magenta.
for (int j = 0; j < count; j++) {
@@ -1862,7 +1862,7 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
} else {
glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
}
-
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * 4, "Render target backbuffer color texture (3D)");
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1885,6 +1885,8 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
} else {
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
}
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target backbuffer depth texture");
+
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1941,7 +1943,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->overridden.color.is_valid()) {
rt->overridden.color = RID();
} else if (rt->color) {
- glDeleteTextures(1, &rt->color);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->color);
if (rt->texture.is_valid()) {
Texture *tex = get_texture(rt->texture);
tex->tex_id = 0;
@@ -1952,7 +1954,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->overridden.depth.is_valid()) {
rt->overridden.depth = RID();
} else if (rt->depth) {
- glDeleteTextures(1, &rt->depth);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->depth);
}
rt->depth = 0;
@@ -1961,12 +1963,12 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->backbuffer_fbo != 0) {
glDeleteFramebuffers(1, &rt->backbuffer_fbo);
- glDeleteTextures(1, &rt->backbuffer);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer);
rt->backbuffer = 0;
rt->backbuffer_fbo = 0;
}
if (rt->backbuffer_depth != 0) {
- glDeleteTextures(1, &rt->backbuffer_depth);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer_depth);
rt->backbuffer_depth = 0;
}
_render_target_clear_sdf(rt);
@@ -2331,6 +2333,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width, size.height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_write, size.width * size.height, "SDF texture");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
@@ -2371,6 +2374,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_process[0], rt->process_size.width * rt->process_size.height * 4, "SDF process texture[0]");
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
@@ -2380,6 +2384,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_process[1], rt->process_size.width * rt->process_size.height * 4, "SDF process texture[1]");
glGenTextures(1, &rt->sdf_texture_read);
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_read);
@@ -2390,13 +2395,16 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_read, rt->process_size.width * rt->process_size.height * 4, "SDF texture (read)");
}
void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
if (rt->sdf_texture_write_fb != 0) {
- glDeleteTextures(1, &rt->sdf_texture_read);
- glDeleteTextures(1, &rt->sdf_texture_write);
- glDeleteTextures(2, rt->sdf_texture_process);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_read);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_write);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_process[0]);
+ GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_process[1]);
+
glDeleteFramebuffers(1, &rt->sdf_texture_write_fb);
rt->sdf_texture_read = 0;
rt->sdf_texture_write = 0;
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 2b939aa7fa..fefcd56570 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -496,8 +496,6 @@ public:
virtual bool can_create_resources_async() const override;
- RID texture_create();
-
virtual RID texture_allocate() override;
virtual void texture_free(RID p_rid) override;
@@ -542,16 +540,12 @@ public:
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override;
void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
- void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
- //Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
- void texture_set_sampler(RID p_texture, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat);
Image::Format texture_get_format(RID p_texture) const;
uint32_t texture_get_texid(RID p_texture) const;
uint32_t texture_get_width(RID p_texture) const;
uint32_t texture_get_height(RID p_texture) const;
uint32_t texture_get_depth(RID p_texture) const;
void texture_bind(RID p_texture, uint32_t p_texture_no);
- RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
/* TEXTURE ATLAS API */
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 5f21d8f70a..3e6e72edad 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -67,6 +67,37 @@ Utilities::~Utilities() {
for (int i = 0; i < FRAME_COUNT; i++) {
glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
}
+
+ if (texture_mem_cache) {
+ uint32_t leaked_data_size = 0;
+ for (const KeyValue<GLuint, ResourceAllocation> &E : texture_allocs_cache) {
+#ifdef DEV_ENABLED
+ ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
+#else
+ ERR_PRINT("Texture with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
+#endif
+ leaked_data_size += E.value.size;
+ }
+ if (leaked_data_size < texture_mem_cache) {
+ ERR_PRINT("Texture cache is not empty. There may be an additional texture leak of " + itos(texture_mem_cache - leaked_data_size) + " bytes.");
+ }
+ }
+
+ if (buffer_mem_cache) {
+ uint32_t leaked_data_size = 0;
+
+ for (const KeyValue<GLuint, ResourceAllocation> &E : buffer_allocs_cache) {
+#ifdef DEV_ENABLED
+ ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
+#else
+ ERR_PRINT("Buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
+#endif
+ leaked_data_size += E.value.size;
+ }
+ if (leaked_data_size < buffer_mem_cache) {
+ ERR_PRINT("Buffer cache is not empty. There may be an additional buffer leak of " + itos(buffer_mem_cache - leaked_data_size) + " bytes.");
+ }
+ }
}
Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
@@ -324,6 +355,13 @@ void Utilities::update_memory_info() {
}
uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
+ if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
+ return texture_mem_cache;
+ } else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
+ return buffer_mem_cache;
+ } else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
+ return texture_mem_cache + buffer_mem_cache;
+ }
return 0;
}
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index 92131aff8c..243342014b 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -48,6 +48,18 @@ class Utilities : public RendererUtilities {
private:
static Utilities *singleton;
+ struct ResourceAllocation {
+#ifdef DEV_ENABLED
+ String name;
+#endif
+ uint32_t size = 0;
+ };
+ HashMap<GLuint, ResourceAllocation> buffer_allocs_cache;
+ HashMap<GLuint, ResourceAllocation> texture_allocs_cache;
+
+ uint64_t buffer_mem_cache = 0;
+ uint64_t texture_mem_cache = 0;
+
public:
static Utilities *get_singleton() { return singleton; }
@@ -57,6 +69,58 @@ public:
// Buffer size is specified in bytes
static Vector<uint8_t> buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size);
+ // Allocate memory with glBufferData. Does not handle resizing.
+ _FORCE_INLINE_ void buffer_allocate_data(GLenum p_target, GLuint p_id, uint32_t p_size, const void *p_data, GLenum p_usage, String p_name = "") {
+ glBufferData(p_target, p_size, p_data, p_usage);
+ buffer_mem_cache += p_size;
+
+#ifdef DEV_ENABLED
+ ERR_FAIL_COND_MSG(buffer_allocs_cache.has(p_id), "trying to allocate buffer with name " + p_name + " but ID already used by " + buffer_allocs_cache[p_id].name);
+#endif
+
+ ResourceAllocation resource_allocation;
+ resource_allocation.size = p_size;
+#ifdef DEV_ENABLED
+ resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
+#endif
+ buffer_allocs_cache[p_id] = resource_allocation;
+ }
+
+ _FORCE_INLINE_ void buffer_free_data(GLuint p_id) {
+ ERR_FAIL_COND(!buffer_allocs_cache.has(p_id));
+ glDeleteBuffers(1, &p_id);
+ buffer_mem_cache -= buffer_allocs_cache[p_id].size;
+ buffer_allocs_cache.erase(p_id);
+ }
+
+ // Records that data was allocated for state tracking purposes.
+ _FORCE_INLINE_ void texture_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
+ texture_mem_cache += p_size;
+#ifdef DEV_ENABLED
+ ERR_FAIL_COND_MSG(texture_allocs_cache.has(p_id), "trying to allocate texture with name " + p_name + " but ID already used by " + texture_allocs_cache[p_id].name);
+#endif
+ ResourceAllocation resource_allocation;
+ resource_allocation.size = p_size;
+#ifdef DEV_ENABLED
+ resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
+#endif
+ texture_allocs_cache[p_id] = resource_allocation;
+ }
+
+ _FORCE_INLINE_ void texture_free_data(GLuint p_id) {
+ ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
+ glDeleteTextures(1, &p_id);
+ texture_mem_cache -= texture_allocs_cache[p_id].size;
+ texture_allocs_cache.erase(p_id);
+ }
+
+ _FORCE_INLINE_ void texture_resize_data(GLuint p_id, uint32_t p_size) {
+ ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
+ texture_mem_cache -= texture_allocs_cache[p_id].size;
+ texture_mem_cache += p_size;
+ texture_allocs_cache[p_id].size = p_size;
+ }
+
/* INSTANCES */
virtual RS::InstanceType get_base_type(RID p_rid) const override;
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index e9affe41af..45f9f14dab 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -108,6 +108,10 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
last_error = ERR_FILE_CANT_OPEN;
return last_error;
}
+ // Fix temporary file permissions (defaults to 0600 instead of 0666 & ~umask).
+ mode_t mask = umask(022);
+ umask(mask);
+ fchmod(fd, 0666 & ~mask);
path = String::utf8(cs.ptr());
f = fdopen(fd, mode_string);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index f65056951d..3feed2b109 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -2276,6 +2276,7 @@ Error VulkanContext::prepare_buffers() {
// presentation engine will still present the image correctly.
print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
_update_swap_chain(w);
+ break;
} else if (err != VK_SUCCESS) {
ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
} else {
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 821d1c54e0..b48bd4ab5f 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1035,6 +1035,7 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_line_folding_enabled(EDITOR_GET("text_editor/appearance/lines/code_folding"));
text_editor->set_draw_fold_gutter(EDITOR_GET("text_editor/appearance/lines/code_folding"));
text_editor->set_line_wrapping_mode((TextEdit::LineWrappingMode)EDITOR_GET("text_editor/appearance/lines/word_wrap").operator int());
+ text_editor->set_autowrap_mode((TextServer::AutowrapMode)EDITOR_GET("text_editor/appearance/lines/autowrap_mode").operator int());
// Appearance: Whitespace
text_editor->set_draw_tabs(EDITOR_GET("text_editor/appearance/whitespace/draw_tabs"));
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index c788fee7f8..f4b7b14e99 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -303,7 +303,7 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
break;
}
- if (stype == Variant::OBJECT && mtype == Variant::OBJECT && E->get().class_name != F->get().class_name) {
+ if (stype == Variant::OBJECT && mtype == Variant::OBJECT && !ClassDB::is_parent_class(E->get().class_name, F->get().class_name)) {
type_mismatch = true;
break;
}
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index e3686a0217..929f323e80 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -340,6 +340,12 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
return prepare_error_response(p_params, DAP::ErrorType::WRONG_PATH, variables);
}
+ // If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase
+ if (source.path.find("\\") != -1) {
+ source.path = source.path.replace("\\", "/");
+ source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1);
+ }
+
Array breakpoints = args["breakpoints"], lines;
for (int i = 0; i < breakpoints.size(); i++) {
DAP::SourceBreakpoint breakpoint;
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h
index eb5255dc78..9995066ab4 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.h
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.h
@@ -45,6 +45,12 @@ private:
friend DebugAdapterProtocol;
_FORCE_INLINE_ bool is_valid_path(const String &p_path) const {
+ // If path contains \, it's a Windows path, so we need to convert it to /, and check as case-insensitive.
+ if (p_path.contains("\\")) {
+ String project_path = ProjectSettings::get_singleton()->get_resource_path();
+ String path = p_path.replace("\\", "/");
+ return path.findn(project_path) != -1;
+ }
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());
}
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 67a8814aa1..91358c3475 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -502,6 +502,7 @@ void DocTools::generate(bool p_basic_types) {
found_type = true;
if (retinfo.type == Variant::INT && retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
prop.enumeration = retinfo.class_name;
+ prop.is_bitfield = retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
prop.type = "int";
} else if (retinfo.class_name != StringName()) {
prop.type = retinfo.class_name;
@@ -1065,6 +1066,9 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
method.return_type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
method.return_enum = parser->get_named_attribute_value("enum");
+ if (parser->has_attribute("is_bitfield")) {
+ method.return_is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
+ }
}
} else if (name == "returns_error") {
ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
@@ -1077,6 +1081,9 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
argument.type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
argument.enumeration = parser->get_named_attribute_value("enum");
+ if (parser->has_attribute("is_bitfield")) {
+ argument.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
+ }
}
method.arguments.push_back(argument);
@@ -1267,6 +1274,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
}
if (parser->has_attribute("enum")) {
prop2.enumeration = parser->get_named_attribute_value("enum");
+ if (parser->has_attribute("is_bitfield")) {
+ prop2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
+ }
}
if (parser->has_attribute("is_deprecated")) {
prop2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
@@ -1334,9 +1344,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
constant2.is_value_valid = true;
if (parser->has_attribute("enum")) {
constant2.enumeration = parser->get_named_attribute_value("enum");
- }
- if (parser->has_attribute("is_bitfield")) {
- constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
+ if (parser->has_attribute("is_bitfield")) {
+ constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
+ }
}
if (parser->has_attribute("is_deprecated")) {
constant2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
@@ -1407,6 +1417,9 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
String enum_text;
if (!m.return_enum.is_empty()) {
enum_text = " enum=\"" + m.return_enum + "\"";
+ if (m.return_is_bitfield) {
+ enum_text += " is_bitfield=\"true\"";
+ }
}
_write_string(f, 3, "<return type=\"" + m.return_type.xml_escape(true) + "\"" + enum_text + " />");
}
@@ -1422,6 +1435,9 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
String enum_text;
if (!a.enumeration.is_empty()) {
enum_text = " enum=\"" + a.enumeration + "\"";
+ if (a.is_bitfield) {
+ enum_text += " is_bitfield=\"true\"";
+ }
}
if (!a.default_value.is_empty()) {
@@ -1512,6 +1528,9 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
String additional_attributes;
if (!c.properties[i].enumeration.is_empty()) {
additional_attributes += " enum=\"" + c.properties[i].enumeration + "\"";
+ if (c.properties[i].is_bitfield) {
+ additional_attributes += " is_bitfield=\"true\"";
+ }
}
if (!c.properties[i].default_value.is_empty()) {
additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 58a8329b71..b71c66d776 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -262,7 +262,7 @@ void EditorFileSystem::_scan_filesystem() {
} else {
Vector<String> split = l.split("::");
- ERR_CONTINUE(split.size() != 9);
+ ERR_CONTINUE(split.size() < 9);
String name = split[0];
String file;
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index e709371ec6..991807ccbb 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -293,7 +293,7 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) {
}
}
-void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
+void EditorHelp::_add_type(const String &p_type, const String &p_enum, bool p_is_bitfield) {
if (p_type.is_empty() || p_type == "void") {
class_desc->push_color(Color(theme_cache.type_color, 0.5));
class_desc->push_hint(TTR("No return value."));
@@ -304,6 +304,7 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
}
bool is_enum_type = !p_enum.is_empty();
+ bool is_bitfield = p_is_bitfield && is_enum_type;
bool can_ref = !p_type.contains("*") || is_enum_type;
String link_t = p_type; // For links in metadata
@@ -327,6 +328,13 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
class_desc->add_text("Array");
class_desc->pop();
class_desc->add_text("[");
+ } else if (is_bitfield) {
+ class_desc->push_color(Color(theme_cache.type_color, 0.5));
+ class_desc->push_hint(TTR("This value is an integer composed as a bitmask of the following flags."));
+ class_desc->add_text("BitField");
+ class_desc->pop();
+ class_desc->add_text("[");
+ class_desc->pop();
}
if (is_enum_type) {
@@ -340,6 +348,10 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
class_desc->pop(); // Pushed meta above.
if (add_array) {
class_desc->add_text("]");
+ } else if (is_bitfield) {
+ class_desc->push_color(Color(theme_cache.type_color, 0.5));
+ class_desc->add_text("]");
+ class_desc->pop();
}
}
class_desc->pop();
@@ -403,7 +415,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
_add_bulletpoint();
}
- _add_type(p_method.return_type, p_method.return_enum);
+ _add_type(p_method.return_type, p_method.return_enum, p_method.return_is_bitfield);
if (p_overview) {
class_desc->pop(); // align
@@ -437,7 +449,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
_add_text(p_method.arguments[j].name);
class_desc->add_text(": ");
- _add_type(p_method.arguments[j].type, p_method.arguments[j].enumeration);
+ _add_type(p_method.arguments[j].type, p_method.arguments[j].enumeration, p_method.arguments[j].is_bitfield);
if (!p_method.arguments[j].default_value.is_empty()) {
class_desc->push_color(theme_cache.symbol_color);
class_desc->add_text(" = ");
@@ -953,7 +965,7 @@ void EditorHelp::_update_doc() {
class_desc->push_cell();
class_desc->push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
_push_code_font();
- _add_type(cd.properties[i].type, cd.properties[i].enumeration);
+ _add_type(cd.properties[i].type, cd.properties[i].enumeration, cd.properties[i].is_bitfield);
_pop_code_font();
class_desc->pop();
class_desc->pop(); // cell
@@ -1252,7 +1264,7 @@ void EditorHelp::_update_doc() {
_add_text(cd.signals[i].arguments[j].name);
class_desc->add_text(": ");
- _add_type(cd.signals[i].arguments[j].type, cd.signals[i].arguments[j].enumeration);
+ _add_type(cd.signals[i].arguments[j].type, cd.signals[i].arguments[j].enumeration, cd.signals[i].arguments[j].is_bitfield);
if (!cd.signals[i].arguments[j].default_value.is_empty()) {
class_desc->push_color(theme_cache.symbol_color);
class_desc->add_text(" = ");
@@ -1630,7 +1642,7 @@ void EditorHelp::_update_doc() {
_push_code_font();
_add_bulletpoint();
- _add_type(cd.properties[i].type, cd.properties[i].enumeration);
+ _add_type(cd.properties[i].type, cd.properties[i].enumeration, cd.properties[i].is_bitfield);
class_desc->add_text(" ");
_pop_code_font();
class_desc->pop(); // cell
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 4175ece816..0aa8302b27 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -158,7 +158,7 @@ class EditorHelp : public VBoxContainer {
bool scroll_locked = false;
//void _button_pressed(int p_idx);
- void _add_type(const String &p_type, const String &p_enum = String());
+ void _add_type(const String &p_type, const String &p_enum = String(), bool p_is_bitfield = false);
void _add_type_icon(const String &p_type, int p_size = 0, const String &p_fallback = "");
void _add_method(const DocData::MethodDoc &p_method, bool p_overview = true);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 3f6db778c5..e3514b4691 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -3690,8 +3690,9 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
Variant v_undo_redo = undo_redo;
Variant v_object = object;
Variant v_name = p_name;
- for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) {
- const Callable &callback = EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback()[i];
+ const Vector<Callable> &callbacks = EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback();
+ for (int i = 0; i < callbacks.size(); i++) {
+ const Callable &callback = callbacks[i];
const Variant *p_arguments[] = { &v_undo_redo, &v_object, &v_name, &p_value };
Variant return_value;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 51603adb28..da14f5374c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -983,7 +983,7 @@ void EditorNode::_fs_changed() {
} else { // Normal project export.
String config_error;
bool missing_templates;
- if (!platform->can_export(export_preset, config_error, missing_templates)) {
+ if (!platform->can_export(export_preset, config_error, missing_templates, export_defer.debug)) {
ERR_PRINT(vformat("Cannot export project with preset \"%s\" due to configuration errors:\n%s", preset_name, config_error));
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 9e22a0ead6..4232eacd76 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -62,7 +62,14 @@ void EditorPlugin::remove_custom_type(const String &p_type) {
}
void EditorPlugin::add_autoload_singleton(const String &p_name, const String &p_path) {
- EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_add(p_name, p_path);
+ if (p_path.begins_with("res://")) {
+ EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_add(p_name, p_path);
+ } else {
+ const Ref<Script> plugin_script = static_cast<Ref<Script>>(get_script());
+ ERR_FAIL_COND(plugin_script.is_null());
+ const String script_base_path = plugin_script->get_path().get_base_dir();
+ EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_add(p_name, script_base_path.path_join(p_path));
+ }
}
void EditorPlugin::remove_autoload_singleton(const String &p_name) {
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 3a84fcb785..cd5cafc42f 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -208,6 +208,9 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_
array.set(index, p_value);
object->set_array(array);
emit_changed(get_edited_property(), array, "", true);
+ if (!p_changing) {
+ update_property();
+ }
}
void EditorPropertyArray::_change_type(Object *p_button, int p_index) {
@@ -738,6 +741,9 @@ void EditorPropertyDictionary::_property_changed(const String &p_property, Varia
object->set_dict(dict);
emit_changed(get_edited_property(), dict, "", true);
}
+ if (!p_changing) {
+ update_property();
+ }
}
void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5deb590875..7316883132 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -562,6 +562,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Appearance: Lines
_initial_set("text_editor/appearance/lines/code_folding", true);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/lines/word_wrap", 0, "None,Boundary")
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/lines/autowrap_mode", 3, "Arbitrary:1,Word:2,Word (Smart):3")
// Appearance: Whitespace
_initial_set("text_editor/appearance/whitespace/draw_tabs", true);
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 65ffa45b38..00fbd85166 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1788,11 +1788,12 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags
}
}
-bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
bool valid = true;
+
#ifndef ANDROID_ENABLED
String templates_error;
- valid = valid && has_valid_export_configuration(p_preset, templates_error, r_missing_templates);
+ valid = valid && has_valid_export_configuration(p_preset, templates_error, r_missing_templates, p_debug);
if (!templates_error.is_empty()) {
r_error += templates_error;
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 3b9663ebdf..121e00ccae 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -238,8 +238,8 @@ public:
String test_etc2() const;
String test_bc() const;
- bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
+ bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const = 0;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const = 0;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 35f5542f23..df1026d0ed 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -77,7 +77,7 @@ Ref<Texture2D> EditorExportPlatformPC::get_logo() const {
return logo;
}
-bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h
index b49aa09e07..53574c2333 100644
--- a/editor/export/editor_export_platform_pc.h
+++ b/editor/export/editor_export_platform_pc.h
@@ -52,7 +52,7 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
diff --git a/editor/gui/editor_object_selector.cpp b/editor/gui/editor_object_selector.cpp
index 9988e285c7..7cc830416c 100644
--- a/editor/gui/editor_object_selector.cpp
+++ b/editor/gui/editor_object_selector.cpp
@@ -100,7 +100,6 @@ void EditorObjectSelector::_show_popup() {
sub_objects_menu->set_position(gp);
sub_objects_menu->set_size(Size2(size.width, 1));
- sub_objects_menu->set_parent_rect(Rect2(Point2(gp - sub_objects_menu->get_position()), size));
sub_objects_menu->take_mouse_focus();
sub_objects_menu->popup();
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index 6d02fcef1d..451827da09 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -106,7 +106,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
grabbing_spinner_dist_cache += diff_x * grabbing_spinner_speed;
- if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4 * EDSCALE) {
+ if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4 * grabbing_spinner_speed * EDSCALE) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
grabbing_spinner = true;
}
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 76e09769cc..520cf42687 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -656,15 +656,13 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
}
}
- if (keep_for_children) {
- if (keep) {
- p_parent->clear_custom_color(0);
- p_parent->set_selectable(0, true);
- } else {
- p_parent->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
- p_parent->set_selectable(0, false);
- p_parent->deselect(0);
- }
+ if (keep) {
+ p_parent->clear_custom_color(0);
+ p_parent->set_selectable(0, true);
+ } else if (keep_for_children) {
+ p_parent->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
+ p_parent->set_selectable(0, false);
+ p_parent->deselect(0);
}
if (editor_selection) {
@@ -964,62 +962,74 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
}
}
-void SceneTreeEditor::_rename_node(ObjectID p_node, const String &p_name) {
- Object *o = ObjectDB::get_instance(p_node);
- ERR_FAIL_COND(!o);
- Node *n = Object::cast_to<Node>(o);
- ERR_FAIL_COND(!n);
- TreeItem *item = _find(tree->get_root(), n->get_path());
+void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) {
+ TreeItem *item = _find(tree->get_root(), p_node->get_path());
ERR_FAIL_COND(!item);
+ String new_name = p_name.validate_node_name();
- n->set_name(p_name);
- item->set_metadata(0, n->get_path());
- item->set_text(0, p_name);
-}
-
-void SceneTreeEditor::_renamed() {
- TreeItem *which = tree->get_edited();
-
- ERR_FAIL_COND(!which);
- NodePath np = which->get_metadata(0);
- Node *n = get_node(np);
- ERR_FAIL_COND(!n);
-
- String raw_new_name = which->get_text(0);
- if (raw_new_name.strip_edges().is_empty()) {
- // If name is empty, fallback to class name.
- if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
- raw_new_name = Node::adjust_name_casing(n->get_class());
- } else {
- raw_new_name = n->get_class();
- }
- }
-
- String new_name = raw_new_name.validate_node_name();
-
- if (new_name != raw_new_name) {
+ if (new_name != p_name) {
error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + String::get_invalid_node_name_characters());
error->popup_centered();
if (new_name.is_empty()) {
- which->set_text(0, n->get_name());
+ item->set_text(0, p_node->get_name());
return;
}
- which->set_text(0, new_name);
+ item->set_text(0, new_name);
}
- if (new_name == n->get_name()) {
- if (which->get_text(0).is_empty()) {
- which->set_text(0, new_name);
+ if (new_name == p_node->get_name()) {
+ if (item->get_text(0).is_empty()) {
+ item->set_text(0, new_name);
}
return;
}
-
// Trim leading/trailing whitespace to prevent node names from containing accidental whitespace, which would make it more difficult to get the node via `get_node()`.
new_name = new_name.strip_edges();
+ if (!is_scene_tree_dock) {
+ p_node->set_name(new_name);
+ item->set_metadata(0, p_node->get_path());
+ emit_signal(SNAME("node_renamed"));
+ } else {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action("Rename Node", UndoRedo::MERGE_DISABLE, p_node);
+
+ emit_signal(SNAME("node_prerename"), p_node, new_name);
+
+ undo_redo->add_undo_method(p_node, "set_name", p_node->get_name());
+ undo_redo->add_undo_method(item, "set_metadata", 0, p_node->get_path());
+ undo_redo->add_undo_method(item, "set_text", 0, p_node->get_name());
+
+ p_node->set_name(p_name);
+ undo_redo->add_do_method(p_node, "set_name", new_name);
+ undo_redo->add_do_method(item, "set_metadata", 0, p_node->get_path());
+ undo_redo->add_do_method(item, "set_text", 0, new_name);
+
+ undo_redo->commit_action();
+ }
+}
+
+void SceneTreeEditor::_renamed() {
+ TreeItem *which = tree->get_edited();
+
+ ERR_FAIL_COND(!which);
+ NodePath np = which->get_metadata(0);
+ Node *n = get_node(np);
+ ERR_FAIL_COND(!n);
+
+ String new_name = which->get_text(0);
+ if (new_name.strip_edges().is_empty()) {
+ // If name is empty, fallback to class name.
+ if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
+ new_name = Node::adjust_name_casing(n->get_class());
+ } else {
+ new_name = n->get_class();
+ }
+ }
+
if (n->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name) != nullptr) {
error->set_text(TTR("Another node already uses this unique name in the scene."));
error->popup_centered();
@@ -1027,18 +1037,7 @@ void SceneTreeEditor::_renamed() {
return;
}
- if (!is_scene_tree_dock) {
- n->set_name(new_name);
- which->set_metadata(0, n->get_path());
- emit_signal(SNAME("node_renamed"));
- } else {
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Rename Node"), UndoRedo::MERGE_DISABLE, n);
- emit_signal(SNAME("node_prerename"), n, new_name);
- undo_redo->add_do_method(this, "_rename_node", n->get_instance_id(), new_name);
- undo_redo->add_undo_method(this, "_rename_node", n->get_instance_id(), n->get_name());
- undo_redo->commit_action();
- }
+ _rename_node(n, new_name);
}
Node *SceneTreeEditor::get_selected() {
diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h
index 20cc62d675..8878256009 100644
--- a/editor/gui/scene_tree_editor.h
+++ b/editor/gui/scene_tree_editor.h
@@ -85,7 +85,7 @@ class SceneTreeEditor : public Control {
void _notification(int p_what);
void _selected_changed();
void _deselect_items();
- void _rename_node(ObjectID p_node, const String &p_name);
+ void _rename_node(Node *p_node, const String &p_name);
void _cell_collapsed(Object *p_obj);
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 5971f3b07f..92d244c79a 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -107,18 +107,17 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
translations.push_back(translation);
}
- line = f->get_csv_line(delimiter);
-
- while (line.size() == locales.size() + 1) {
+ do {
+ line = f->get_csv_line(delimiter);
String key = line[0];
if (!key.is_empty()) {
+ ERR_FAIL_COND_V_MSG(line.size() != locales.size() + 1, ERR_PARSE_ERROR, vformat("Error importing CSV translation: expected %d locale(s), but the '%s' key has %d locale(s).", locales.size(), key, line.size() - 1));
+
for (int i = 1; i < line.size(); i++) {
translations.write[i - 1]->add_message(key, line[i].c_unescape());
}
}
-
- line = f->get_csv_line(delimiter);
- }
+ } while (!f->eof_reached());
for (int i = 0; i < translations.size(); i++) {
Ref<Translation> xlt = translations[i];
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 15bb504d8d..4485b09f76 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -33,6 +33,7 @@
#include "core/error/error_macros.h"
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
#include "editor/import/scene_import_settings.h"
#include "scene/3d/area_3d.h"
#include "scene/3d/collision_shape_3d.h"
@@ -2528,6 +2529,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
progress.step(TTR("Saving..."), 104);
+ int flags = 0;
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
+ flags |= ResourceSaver::FLAG_COMPRESS;
+ }
+
if (animation_importer) {
Ref<AnimationLibrary> library;
for (int i = 0; i < scene->get_child_count(); i++) {
@@ -2546,15 +2552,15 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
library.instantiate(); // Will be empty
}
- print_verbose("Saving animation to: " + p_save_path + ".scn");
- err = ResourceSaver::save(library, p_save_path + ".res"); //do not take over, let the changed files reload themselves
+ print_verbose("Saving animation to: " + p_save_path + ".res");
+ err = ResourceSaver::save(library, p_save_path + ".res", flags); //do not take over, let the changed files reload themselves
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save animation to file '" + p_save_path + ".res'.");
} else {
Ref<PackedScene> packer = memnew(PackedScene);
packer->pack(scene);
print_verbose("Saving scene to: " + p_save_path + ".scn");
- err = ResourceSaver::save(packer, p_save_path + ".scn"); //do not take over, let the changed files reload themselves
+ err = ResourceSaver::save(packer, p_save_path + ".scn", flags); //do not take over, let the changed files reload themselves
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index c3e011b812..7fad4061b1 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2817,7 +2817,7 @@ void Node3DEditorViewport::_notification(int p_what) {
text += "\n";
text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME));
- text += vformat(TTR("Primitive Indices: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
+ text += vformat(TTR("Primitives: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
text += vformat(TTR("Draw Calls: %d"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME));
info_label->set_text(text);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index a2549c7376..d2b3efcd65 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -298,6 +298,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
return;
}
+ uv_edit_draw->set_texture_filter(node->get_texture_filter_in_tree());
+
Vector<Vector2> points = node->get_polygon();
Vector<Vector2> uvs = node->get_uv();
if (uvs.size() != points.size()) {
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index cd700d953a..5fdfb21176 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -548,6 +548,7 @@ void ScriptTextEditor::_update_warnings() {
warnings_panel->push_cell();
warnings_panel->add_text(w.message);
+ warnings_panel->add_newline();
warnings_panel->pop(); // Cell.
}
warnings_panel->pop(); // Table.
@@ -569,6 +570,7 @@ void ScriptTextEditor::_update_errors() {
errors_panel->push_cell();
errors_panel->add_text(err.message);
+ errors_panel->add_newline();
errors_panel->pop(); // Cell.
}
errors_panel->pop(); // Table
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 283e906052..1a9e09f3b1 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -160,6 +160,8 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
if (texture.is_null()) {
Ref<Image> image(Object::cast_to<Image>(p_object));
texture = ImageTexture::create_from_image(image);
+
+ ERR_FAIL_COND_MSG(texture == nullptr, "Failed to create the texture from an invalid image.");
}
add_custom_control(memnew(TexturePreview(texture, true)));
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 74bf32d133..e9af697226 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -459,6 +459,8 @@ bool ProjectConverter3To4::convert() {
String &line = source_line.line;
if (line.contains("nodes/root_type=\"Spatial\"")) {
line = "nodes/root_type=\"Node3D\"";
+ } else if (line == "importer=\"ogg_vorbis\"") {
+ line = "importer=\"oggvorbisstr\"";
}
}
} else {
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index f42f34e110..39affdd9f8 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -588,7 +588,7 @@ void RenameDialog::rename() {
if (!to_rename.is_empty()) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Batch Rename"));
+ undo_redo->create_action(TTR("Batch Rename"), UndoRedo::MERGE_DISABLE, root_node, true);
// Make sure to iterate reversed so that child nodes will find parents.
for (int i = to_rename.size() - 1; i >= 0; --i) {
@@ -600,9 +600,7 @@ void RenameDialog::rename() {
continue;
}
- scene_tree_editor->emit_signal(SNAME("node_prerename"), n, new_name);
- undo_redo->add_do_method(scene_tree_editor, "_rename_node", n->get_instance_id(), new_name);
- undo_redo->add_undo_method(scene_tree_editor, "_rename_node", n->get_instance_id(), n->get_name());
+ scene_tree_editor->call("_rename_node", n, new_name);
}
undo_redo->commit_action();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 4c141b76d5..818f566708 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1949,8 +1949,9 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
undo_redo->add_do_method(new_parent, "add_child", node, true);
}
- if (p_position_in_parent >= 0 || same_parent) {
- undo_redo->add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
+ int new_position_in_parent = p_position_in_parent == -1 ? -1 : p_position_in_parent + inc;
+ if (new_position_in_parent >= 0 || same_parent) {
+ undo_redo->add_do_method(new_parent, "move_child", node, new_position_in_parent);
}
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
@@ -1980,7 +1981,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
}
}
- undo_redo->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
+ undo_redo->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, new_position_in_parent);
undo_redo->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
if (p_keep_global_xform) {
diff --git a/main/main.cpp b/main/main.cpp
index a9e2d357fa..0fb6813c6b 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1011,19 +1011,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--delta-smoothing") {
if (I->next()) {
String string = I->next()->get();
- bool recognised = false;
+ bool recognized = false;
if (string == "enable") {
OS::get_singleton()->set_delta_smoothing(true);
delta_smoothing_override = true;
- recognised = true;
+ recognized = true;
}
if (string == "disable") {
OS::get_singleton()->set_delta_smoothing(false);
delta_smoothing_override = false;
- recognised = true;
+ recognized = true;
}
- if (!recognised) {
- OS::get_singleton()->print("Delta-smoothing argument not recognised, aborting.\n");
+ if (!recognized) {
+ OS::get_singleton()->print("Delta-smoothing argument not recognized, aborting.\n");
goto error;
}
N = I->next()->next();
@@ -2965,19 +2965,14 @@ bool Main::start() {
}
if (debug_navigation) {
sml->set_debug_navigation_hint(true);
+ NavigationServer3D::get_singleton()->set_debug_navigation_enabled(true);
}
if (debug_avoidance) {
- sml->set_debug_avoidance_hint(true);
+ NavigationServer3D::get_singleton()->set_debug_avoidance_enabled(true);
}
if (debug_navigation || debug_avoidance) {
NavigationServer3D::get_singleton()->set_active(true);
NavigationServer3D::get_singleton()->set_debug_enabled(true);
- if (debug_navigation) {
- NavigationServer3D::get_singleton()->set_debug_navigation_enabled(true);
- }
- if (debug_avoidance) {
- NavigationServer3D::get_singleton()->set_debug_avoidance_enabled(true);
- }
}
#endif
diff --git a/misc/extension_api_validation/4.0-stable.expected b/misc/extension_api_validation/4.0-stable.expected
index 444560eb53..963c997aa0 100644
--- a/misc/extension_api_validation/4.0-stable.expected
+++ b/misc/extension_api_validation/4.0-stable.expected
@@ -6,6 +6,10 @@ should instead be used to justify these changes and describe how users should wo
========================================================================================================================
+GH-78237
+--------
+Validate extension JSON: Error: Field 'classes/WebRTCPeerConnectionExtension/methods/_create_data_channel/return_value': type changed value in new API, from "Object" to "WebRTCDataChannel".
+
GH-77757
--------
Validate extension JSON: Error: Field 'classes/Viewport/methods/gui_get_focus_owner': is_const changed value in new API, from false to true.
diff --git a/misc/scripts/codespell.sh b/misc/scripts/codespell.sh
index d15b6593f7..a55a39bf99 100755
--- a/misc/scripts/codespell.sh
+++ b/misc/scripts/codespell.sh
@@ -3,6 +3,6 @@ SKIP_LIST="./.*,./**/.*,./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./A
SKIP_LIST+="./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/renames_map_3_to_4.cpp,./misc/scripts/codespell.sh,"
SKIP_LIST+="./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json,"
-IGNORE_LIST="curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai"
+IGNORE_LIST="curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,vai"
codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" --builtin "clear,rare,en-GB_to_en-US"
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index f7bdaf389e..86f3385ae3 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -33,12 +33,12 @@
#include "core/os/os.h"
#include "servers/rendering_server.h"
+#include <transcoder/basisu_transcoder.h>
+
#ifdef TOOLS_ENABLED
#include <encoder/basisu_comp.h>
#endif
-#include <transcoder/basisu_transcoder.h>
-
enum BasisDecompressFormat {
BASIS_DECOMPRESS_RG,
BASIS_DECOMPRESS_RGB,
@@ -58,32 +58,7 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
if (image->get_format() != Image::FORMAT_RGBA8) {
image->convert(Image::FORMAT_RGBA8);
}
- if (!image->has_mipmaps()) {
- basisu::image buimg(image->get_width(), image->get_height());
- Vector<uint8_t> vec = image->get_data();
- const uint8_t *r = vec.ptr();
- memcpy(buimg.get_ptr(), r, vec.size());
- params.m_source_images.push_back(buimg);
- } else {
- {
- Ref<Image> base_image = image->get_image_from_mipmap(0);
- Vector<uint8_t> image_vec = base_image->get_data();
- basisu::image buimg_image(base_image->get_width(), base_image->get_height());
- const uint8_t *r = image_vec.ptr();
- memcpy(buimg_image.get_ptr(), r, image_vec.size());
- params.m_source_images.push_back(buimg_image);
- }
- basisu::vector<basisu::image> images;
- for (int32_t mip_map_i = 1; mip_map_i <= image->get_mipmap_count(); mip_map_i++) {
- Ref<Image> mip_map = image->get_image_from_mipmap(mip_map_i);
- Vector<uint8_t> mip_map_vec = mip_map->get_data();
- basisu::image buimg_mipmap(mip_map->get_width(), mip_map->get_height());
- const uint8_t *r = mip_map_vec.ptr();
- memcpy(buimg_mipmap.get_ptr(), r, mip_map_vec.size());
- images.push_back(buimg_mipmap);
- }
- params.m_source_mipmap_images.push_back(images);
- }
+
params.m_uastc = true;
params.m_quality_level = basisu::BASISU_QUALITY_MIN;
@@ -117,6 +92,7 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
} break;
case Image::USED_CHANNELS_RG: {
#ifdef USE_RG_AS_RGBA
+ params.m_force_alpha = true;
image->convert_rg_to_ra_rgba8();
decompress_format = BASIS_DECOMPRESS_RG_AS_RA;
#else
@@ -133,6 +109,33 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
} break;
}
+ if (!image->has_mipmaps()) {
+ basisu::image buimg(image->get_width(), image->get_height());
+ Vector<uint8_t> vec = image->get_data();
+ const uint8_t *r = vec.ptr();
+ memcpy(buimg.get_ptr(), r, vec.size());
+ params.m_source_images.push_back(buimg);
+ } else {
+ {
+ Ref<Image> base_image = image->get_image_from_mipmap(0);
+ Vector<uint8_t> image_vec = base_image->get_data();
+ basisu::image buimg_image(base_image->get_width(), base_image->get_height());
+ const uint8_t *r = image_vec.ptr();
+ memcpy(buimg_image.get_ptr(), r, image_vec.size());
+ params.m_source_images.push_back(buimg_image);
+ }
+ basisu::vector<basisu::image> images;
+ for (int32_t mip_map_i = 1; mip_map_i <= image->get_mipmap_count(); mip_map_i++) {
+ Ref<Image> mip_map = image->get_image_from_mipmap(mip_map_i);
+ Vector<uint8_t> mip_map_vec = mip_map->get_data();
+ basisu::image buimg_mipmap(mip_map->get_width(), mip_map->get_height());
+ const uint8_t *r = mip_map_vec.ptr();
+ memcpy(buimg_mipmap.get_ptr(), r, mip_map_vec.size());
+ images.push_back(buimg_mipmap);
+ }
+ params.m_source_mipmap_images.push_back(images);
+ }
+
basisu::basis_compressor c;
c.init(params);
diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_macos.mm
index eca8adbfcf..c0d8dc2cef 100644
--- a/modules/camera/camera_macos.mm
+++ b/modules/camera/camera_macos.mm
@@ -32,6 +32,7 @@
// If you fix something here, make sure you fix it there as well!
#include "camera_macos.h"
+
#include "servers/camera/camera_feed.h"
#import <AVFoundation/AVFoundation.h>
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index d0e4d0c8cd..6ac71b6946 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -31,12 +31,12 @@
#ifndef CSG_SHAPE_H
#define CSG_SHAPE_H
-#define CSGJS_HEADER_ONLY
-
#include "csg.h"
+
#include "scene/3d/path_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
+
#include "thirdparty/misc/mikktspace.h"
class CSGShape3D : public GeometryInstance3D {
diff --git a/modules/csg/editor/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h
index 89a4305683..deac1d428d 100644
--- a/modules/csg/editor/csg_gizmos.h
+++ b/modules/csg/editor/csg_gizmos.h
@@ -34,6 +34,7 @@
#ifdef TOOLS_ENABLED
#include "../csg_shape.h"
+
#include "editor/editor_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp
index c22aedb0fc..211d419349 100644
--- a/modules/cvtt/register_types.cpp
+++ b/modules/cvtt/register_types.cpp
@@ -49,4 +49,4 @@ void uninitialize_cvtt_module(ModuleInitializationLevel p_level) {
}
}
-#endif
+#endif // TOOLS_ENABLED
diff --git a/modules/denoise/denoise_wrapper.cpp b/modules/denoise/denoise_wrapper.cpp
index 9effb60202..87f02cb4c6 100644
--- a/modules/denoise/denoise_wrapper.cpp
+++ b/modules/denoise/denoise_wrapper.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "denoise_wrapper.h"
-#include "thirdparty/oidn/include/OpenImageDenoise/oidn.h"
+
+#include <OpenImageDenoise/oidn.h>
+
#include <stdio.h>
void *oidn_denoiser_init() {
diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp
index 8419b7e52a..72764036e1 100644
--- a/modules/denoise/lightmap_denoiser.cpp
+++ b/modules/denoise/lightmap_denoiser.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "lightmap_denoiser.h"
+
#include "denoise_wrapper.h"
#include "core/io/image.h"
diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp
index 9448776529..a4264b07c5 100644
--- a/modules/denoise/register_types.cpp
+++ b/modules/denoise/register_types.cpp
@@ -29,9 +29,11 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/config/engine.h"
+
#include "lightmap_denoiser.h"
+#include "core/config/engine.h"
+
void initialize_denoise_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h
index ee0cd831de..616402be20 100644
--- a/modules/enet/enet_connection.h
+++ b/modules/enet/enet_connection.h
@@ -31,10 +31,10 @@
#ifndef ENET_CONNECTION_H
#define ENET_CONNECTION_H
-#include "core/object/ref_counted.h"
+#include "enet_packet_peer.h"
#include "core/crypto/crypto.h"
-#include "enet_packet_peer.h"
+#include "core/object/ref_counted.h"
#include <enet/enet.h>
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index 93a20ab1f8..af5bd2929c 100644
--- a/modules/enet/enet_multiplayer_peer.cpp
+++ b/modules/enet/enet_multiplayer_peer.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "enet_multiplayer_peer.h"
+
#include "core/io/ip.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h
index f0d157cbf8..930af2d8cb 100644
--- a/modules/enet/enet_multiplayer_peer.h
+++ b/modules/enet/enet_multiplayer_peer.h
@@ -31,10 +31,11 @@
#ifndef ENET_MULTIPLAYER_PEER_H
#define ENET_MULTIPLAYER_PEER_H
+#include "enet_connection.h"
+
#include "core/crypto/crypto.h"
#include "scene/main/multiplayer_peer.h"
-#include "enet_connection.h"
#include <enet/enet.h>
class ENetMultiplayerPeer : public MultiplayerPeer {
diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp
index 9c287a4f40..5787f9c2da 100644
--- a/modules/enet/register_types.cpp
+++ b/modules/enet/register_types.cpp
@@ -29,11 +29,13 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/error/error_macros.h"
+
#include "enet_connection.h"
#include "enet_multiplayer_peer.h"
#include "enet_packet_peer.h"
+#include "core/error/error_macros.h"
+
static bool enet_ok = false;
void initialize_enet_module(ModuleInitializationLevel p_level) {
diff --git a/modules/etcpak/register_types.h b/modules/etcpak/register_types.h
index 2580ae2f97..4967f3c3f5 100644
--- a/modules/etcpak/register_types.h
+++ b/modules/etcpak/register_types.h
@@ -33,8 +33,6 @@
#include "modules/register_module_types.h"
-#include "modules/register_module_types.h"
-
void initialize_etcpak_module(ModuleInitializationLevel p_level);
void uninitialize_etcpak_module(ModuleInitializationLevel p_level);
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 5a28246555..f2a65451a7 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -612,7 +612,7 @@
[/codeblock]
</description>
</annotation>
- <annotation name="@rpc" qualifiers="vararg">
+ <annotation name="@rpc">
<return type="void" />
<param index="0" name="mode" type="String" default="&quot;authority&quot;" />
<param index="1" name="sync" type="String" default="&quot;call_remote&quot;" />
@@ -620,7 +620,11 @@
<param index="3" name="transfer_channel" type="int" default="0" />
<description>
Mark the following method for remote procedure calls. See [url=$DOCS_URL/tutorials/networking/high_level_multiplayer.html]High-level multiplayer[/url].
- The order of [param mode], [param sync] and [param transfer_mode] does not matter and all arguments can be omitted, but [param transfer_channel] always has to be the last argument. The accepted values for [param mode] are [code]"any_peer"[/code] or [code]"authority"[/code], for [param sync] are [code]"call_remote"[/code] or [code]"call_local"[/code] and for [param transfer_mode] are [code]"unreliable"[/code], [code]"unreliable_ordered"[/code] or [code]"reliable"[/code].
+ The accepted values:
+ - for [param mode] are [code]"any_peer"[/code] or [code]"authority"[/code];
+ - for [param sync] are [code]"call_remote"[/code] or [code]"call_local"[/code];
+ - and for [param transfer_mode] are [code]"unreliable"[/code], [code]"unreliable_ordered"[/code], or [code]"reliable"[/code].
+ The order of [param mode], [param sync] and [param transfer_mode] does not matter, but values related to the same argument must not be used more than once. [param transfer_channel] always has to be the 4th argument (you must specify 3 preceding arguments).
[codeblock]
@rpc
func fn(): pass
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index ce64d79747..df17581ad1 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "gdscript_docgen.h"
+
#include "../gdscript.h"
using GDP = GDScriptParser;
diff --git a/modules/gdscript/editor/gdscript_docgen.h b/modules/gdscript/editor/gdscript_docgen.h
index bb3647196a..3357fb680c 100644
--- a/modules/gdscript/editor/gdscript_docgen.h
+++ b/modules/gdscript/editor/gdscript_docgen.h
@@ -32,6 +32,7 @@
#define GDSCRIPT_DOCGEN_H
#include "../gdscript_parser.h"
+
#include "core/doc_data.h"
class GDScriptDocGen {
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index bba11363d5..b54dc502ae 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -29,8 +29,10 @@
/**************************************************************************/
#include "gdscript_highlighter.h"
+
#include "../gdscript.h"
#include "../gdscript_tokenizer.h"
+
#include "core/config/project_settings.h"
#include "editor/editor_settings.h"
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 3458eb43b5..e17e748d7b 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -30,8 +30,9 @@
#include "gdscript_translation_parser_plugin.h"
+#include "../gdscript.h"
+
#include "core/io/resource_loader.h"
-#include "modules/gdscript/gdscript.h"
void GDScriptEditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
GDScriptLanguage::get_singleton()->get_recognized_extensions(r_extensions);
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index 7e6e381e3f..421030e49a 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -31,9 +31,10 @@
#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
+#include "../gdscript_parser.h"
+
#include "core/templates/hash_set.h"
#include "editor/editor_translation_parser.h"
-#include "modules/gdscript/gdscript_parser.h"
class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlugin {
GDCLASS(GDScriptEditorTranslationParserPlugin, EditorTranslationParserPlugin);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 945dfc9862..7a3b9dc597 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -30,15 +30,6 @@
#include "gdscript.h"
-#include <stdint.h>
-
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
-#include "core/core_constants.h"
-#include "core/core_string_names.h"
-#include "core/io/file_access.h"
-#include "core/io/file_access_encrypted.h"
-#include "core/os/os.h"
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_compiler.h"
@@ -46,15 +37,28 @@
#include "gdscript_rpc_callable.h"
#include "gdscript_warning.h"
+#ifdef TOOLS_ENABLED
+#include "editor/gdscript_docgen.h"
+#endif
+
#ifdef TESTS_ENABLED
#include "tests/gdscript_test_runner.h"
#endif
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
+#include "core/core_string_names.h"
+#include "core/io/file_access.h"
+#include "core/io/file_access_encrypted.h"
+#include "core/os/os.h"
+
#ifdef TOOLS_ENABLED
#include "editor/editor_paths.h"
-#include "editor/gdscript_docgen.h"
#endif
+#include <stdint.h>
+
///////////////////////////
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
@@ -874,44 +878,55 @@ Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int
}
bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
- {
- const GDScript *top = this;
- while (top) {
- {
- HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
- if (E) {
- r_ret = E->value;
- return true;
- }
+ if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
+ r_ret = get_source_code();
+ return true;
+ }
+
+ const GDScript *top = this;
+ while (top) {
+ {
+ HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
+ if (E) {
+ r_ret = E->value;
+ return true;
}
+ }
- {
- HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name);
- if (E) {
- r_ret = E->value;
+ {
+ HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
+ if (E) {
+ if (E->value.getter) {
+ Callable::CallError ce;
+ r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
return true;
}
+ r_ret = top->static_variables[E->value.index];
+ return true;
}
+ }
- {
- HashMap<StringName, MemberInfo>::ConstIterator E = static_variables_indices.find(p_name);
- if (E) {
- if (E->value.getter) {
- Callable::CallError ce;
- r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
- return true;
- }
- r_ret = static_variables[E->value.index];
- return true;
+ {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name);
+ if (E && E->value->is_static()) {
+ if (top->rpc_config.has(p_name)) {
+ r_ret = Callable(memnew(GDScriptRPCCallable(const_cast<GDScript *>(top), E->key)));
+ } else {
+ r_ret = Callable(const_cast<GDScript *>(top), E->key);
}
+ return true;
}
- top = top->_base;
}
- if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
- r_ret = get_source_code();
- return true;
+ {
+ HashMap<StringName, Ref<GDScript>>::ConstIterator E = top->subclasses.find(p_name);
+ if (E) {
+ r_ret = E->value;
+ return true;
+ }
}
+
+ top = top->_base;
}
return false;
@@ -921,40 +936,60 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
set_source_code(p_value);
reload();
- } else {
- const GDScript *top = this;
- while (top) {
- HashMap<StringName, MemberInfo>::ConstIterator E = static_variables_indices.find(p_name);
- if (E) {
- const GDScript::MemberInfo *member = &E->value;
- Variant value = p_value;
- if (member->data_type.has_type && !member->data_type.is_type(value)) {
- const Variant *args = &p_value;
- Callable::CallError err;
- Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
- if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
- return false;
- }
- }
- if (member->setter) {
- const Variant *args = &value;
- Callable::CallError err;
- callp(member->setter, &args, 1, err);
- return err.error == Callable::CallError::CALL_OK;
- } else {
- static_variables.write[member->index] = value;
- return true;
+ return true;
+ }
+
+ GDScript *top = this;
+ while (top) {
+ HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
+ if (E) {
+ const MemberInfo *member = &E->value;
+ Variant value = p_value;
+ if (member->data_type.has_type && !member->data_type.is_type(value)) {
+ const Variant *args = &p_value;
+ Callable::CallError err;
+ Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
+ if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
+ return false;
}
}
- top = top->_base;
+ if (member->setter) {
+ const Variant *args = &value;
+ Callable::CallError err;
+ callp(member->setter, &args, 1, err);
+ return err.error == Callable::CallError::CALL_OK;
+ } else {
+ top->static_variables.write[member->index] = value;
+ return true;
+ }
}
+
+ top = top->_base;
}
- return true;
+ return false;
}
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
+
+ List<PropertyInfo> property_list;
+
+ const GDScript *top = this;
+ while (top) {
+ for (const KeyValue<StringName, MemberInfo> &E : top->static_variables_indices) {
+ PropertyInfo pi = PropertyInfo(E.value.data_type);
+ pi.name = E.key;
+ pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; // For the script (as a class) it is a non-static property.
+ property_list.push_back(pi);
+ }
+
+ top = top->_base;
+ }
+
+ for (const List<PropertyInfo>::Element *E = property_list.back(); E; E = E->prev()) {
+ p_properties->push_back(E->get());
+ }
}
void GDScript::_bind_methods() {
@@ -1033,6 +1068,16 @@ StringName GDScript::debug_get_member_by_index(int p_idx) const {
return "<error>";
}
+StringName GDScript::debug_get_static_var_by_index(int p_idx) const {
+ for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
+ if (E.value.index == p_idx) {
+ return E.key;
+ }
+ }
+
+ return "<error>";
+}
+
Ref<GDScript> GDScript::get_base() const {
return base;
}
@@ -1372,8 +1417,8 @@ void GDScript::clear(GDScript::ClearData *p_clear_data) {
}
clearing = true;
- GDScript::ClearData data;
- GDScript::ClearData *clear_data = p_clear_data;
+ ClearData data;
+ ClearData *clear_data = p_clear_data;
bool is_root = false;
// If `clear_data` is `nullptr`, it means that it's the root.
@@ -1394,12 +1439,12 @@ void GDScript::clear(GDScript::ClearData *p_clear_data) {
}
member_functions.clear();
- for (KeyValue<StringName, GDScript::MemberInfo> &E : member_indices) {
+ for (KeyValue<StringName, MemberInfo> &E : member_indices) {
clear_data->scripts.insert(E.value.data_type.script_type_ref);
E.value.data_type.script_type_ref = Ref<Script>();
}
- for (KeyValue<StringName, GDScript::MemberInfo> &E : static_variables_indices) {
+ for (KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
clear_data->scripts.insert(E.value.data_type.script_type_ref);
E.value.data_type.script_type_ref = Ref<Script>();
}
@@ -1482,7 +1527,6 @@ GDScript::~GDScript() {
//////////////////////////////
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
- //member
{
HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) {
@@ -1510,17 +1554,45 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
GDScript *sptr = script.ptr();
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
- if (E) {
- Variant name = p_name;
- const Variant *args[2] = { &name, &p_value };
+ {
+ HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
+ if (E) {
+ const GDScript::MemberInfo *member = &E->value;
+ Variant value = p_value;
+ if (member->data_type.has_type && !member->data_type.is_type(value)) {
+ const Variant *args = &p_value;
+ Callable::CallError err;
+ Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
+ if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
+ return false;
+ }
+ }
+ if (member->setter) {
+ const Variant *args = &value;
+ Callable::CallError err;
+ callp(member->setter, &args, 1, err);
+ return err.error == Callable::CallError::CALL_OK;
+ } else {
+ sptr->static_variables.write[member->index] = value;
+ return true;
+ }
+ }
+ }
- Callable::CallError err;
- Variant ret = E->value->call(this, (const Variant **)args, 2, err);
- if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
- return true;
+ {
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
+ if (E) {
+ Variant name = p_name;
+ const Variant *args[2] = { &name, &p_value };
+
+ Callable::CallError err;
+ Variant ret = E->value->call(this, (const Variant **)args, 2, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
+ return true;
+ }
}
}
+
sptr = sptr->_base;
}
@@ -1528,62 +1600,69 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
}
bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
+ {
+ HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
+ if (E) {
+ if (E->value.getter) {
+ Callable::CallError err;
+ r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
+ if (err.error == Callable::CallError::CALL_OK) {
+ return true;
+ }
+ }
+ r_ret = members[E->value.index];
+ return true;
+ }
+ }
+
const GDScript *sptr = script.ptr();
while (sptr) {
{
- HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
+ HashMap<StringName, Variant>::ConstIterator E = sptr->constants.find(p_name);
+ if (E) {
+ r_ret = E->value;
+ return true;
+ }
+ }
+
+ {
+ HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
if (E) {
if (E->value.getter) {
- Callable::CallError err;
- r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
- if (err.error == Callable::CallError::CALL_OK) {
- return true;
- }
+ Callable::CallError ce;
+ r_ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce);
+ return true;
}
- r_ret = members[E->value.index];
- return true; //index found
+ r_ret = sptr->static_variables[E->value.index];
+ return true;
}
}
{
- const GDScript *sl = sptr;
- while (sl) {
- HashMap<StringName, Variant>::ConstIterator E = sl->constants.find(p_name);
- if (E) {
- r_ret = E->value;
- return true; //index found
- }
- sl = sl->_base;
+ HashMap<StringName, Vector<StringName>>::ConstIterator E = sptr->_signals.find(p_name);
+ if (E) {
+ r_ret = Signal(this->owner, E->key);
+ return true;
}
}
{
- // Signals.
- const GDScript *sl = sptr;
- while (sl) {
- HashMap<StringName, Vector<StringName>>::ConstIterator E = sl->_signals.find(p_name);
- if (E) {
- r_ret = Signal(this->owner, E->key);
- return true; //index found
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name);
+ if (E) {
+ if (sptr->rpc_config.has(p_name)) {
+ r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
+ } else {
+ r_ret = Callable(this->owner, E->key);
}
- sl = sl->_base;
+ return true;
}
}
{
- // Methods.
- const GDScript *sl = sptr;
- while (sl) {
- HashMap<StringName, GDScriptFunction *>::ConstIterator E = sl->member_functions.find(p_name);
- if (E) {
- if (sptr->rpc_config.has(p_name)) {
- r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
- } else {
- r_ret = Callable(this->owner, E->key);
- }
- return true; //index found
- }
- sl = sl->_base;
+ HashMap<StringName, Ref<GDScript>>::ConstIterator E = sptr->subclasses.find(p_name);
+ if (E) {
+ r_ret = E->value;
+ return true;
}
}
@@ -2592,20 +2671,12 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
/*************** RESOURCE ***************/
Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- if (r_error) {
- *r_error = ERR_FILE_CANT_OPEN;
- }
-
Error err;
Ref<GDScript> scr = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
- if (scr.is_null()) {
- // Don't fail loading because of parsing error.
- scr.instantiate();
- }
-
if (r_error) {
- *r_error = OK;
+ // Don't fail loading because of parsing error.
+ *r_error = scr.is_valid() ? OK : err;
}
return scr;
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 60bd9eef53..9cf545c41d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -31,6 +31,8 @@
#ifndef GDSCRIPT_H
#define GDSCRIPT_H
+#include "gdscript_function.h"
+
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/doc_data.h"
@@ -38,7 +40,6 @@
#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 {
GDCLASS(GDScriptNativeClass, RefCounted);
@@ -226,6 +227,7 @@ public:
const HashMap<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; }
const HashMap<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only
StringName debug_get_member_by_index(int p_idx) const;
+ StringName debug_get_static_var_by_index(int p_idx) const;
Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual bool can_instantiate() const override;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 13fd115c43..e1033c2aab 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -30,6 +30,9 @@
#include "gdscript_analyzer.h"
+#include "gdscript.h"
+#include "gdscript_utility_functions.h"
+
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/core_constants.h"
@@ -39,8 +42,6 @@
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hash_map.h"
-#include "gdscript.h"
-#include "gdscript_utility_functions.h"
#include "scene/resources/packed_scene.h"
#if defined(TOOLS_ENABLED) && !defined(DISABLE_DEPRECATED)
@@ -1610,11 +1611,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
GDScriptParser::DataType parent_return_type;
List<GDScriptParser::DataType> parameters_types;
int default_par_count = 0;
- bool is_static = false;
- bool is_vararg = false;
+ BitField<MethodFlags> method_flags;
StringName native_base;
- if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, is_static, is_vararg, &native_base)) {
- bool valid = p_function->is_static == is_static;
+ if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
+ bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
valid = valid && parent_return_type == p_function->get_datatype();
int par_count_diff = p_function->parameters.size() - parameters_types.size();
@@ -2029,9 +2029,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
GDScriptParser::DataType return_type;
List<GDScriptParser::DataType> par_types;
int default_arg_count = 0;
- bool is_static = false;
- bool is_vararg = false;
- if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ BitField<MethodFlags> method_flags;
+ if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, method_flags)) {
variable_type = return_type;
variable_type.type_source = list_type.type_source;
} else if (!list_type.is_hard_type()) {
@@ -2470,9 +2469,15 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
- if (assignee_type.is_constant || (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->is_constant)) {
+ if (assignee_type.is_constant) {
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
return;
+ } else if (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->is_constant) {
+ const GDScriptParser::DataType &base_type = static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->datatype;
+ if (base_type.kind != GDScriptParser::DataType::SCRIPT && base_type.kind != GDScriptParser::DataType::CLASS) { // Static variables.
+ push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
+ return;
+ }
} else if (assignee_type.is_read_only) {
push_error("Cannot assign a new value to a read-only property.", p_assignment->assignee);
return;
@@ -3084,15 +3089,24 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
return;
}
- bool is_static = false;
- bool is_vararg = false;
int default_arg_count = 0;
+ BitField<MethodFlags> method_flags;
GDScriptParser::DataType return_type;
List<GDScriptParser::DataType> par_types;
bool is_constructor = (base_type.is_meta_type || (p_call->callee && p_call->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_call->function_name == SNAME("new");
- if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, method_flags)) {
+ // If the method is implemented in the class hierarchy, the virtual flag will not be set for that MethodInfo and the search stops there.
+ // MethodInfo's above the class that defines the method might still have the virtual flag set.
+ if (method_flags.has_flag(METHOD_FLAG_VIRTUAL)) {
+ if (p_call->is_super) {
+ push_error(vformat(R"*(Cannot call the parent class' virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call);
+ } else {
+ push_error(vformat(R"*(Cannot call virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call);
+ }
+ }
+
// If the function require typed arrays we must make literals be typed.
for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) {
int index = E.key;
@@ -3100,14 +3114,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
update_array_literal_element_type(E.value, par_types[index].get_container_element_type());
}
}
- validate_call_arg(par_types, default_arg_count, is_vararg, p_call);
+ validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call);
if (base_type.kind == GDScriptParser::DataType::ENUM && base_type.is_meta_type) {
// Enum type is treated as a dictionary value for function calls.
base_type.is_meta_type = false;
}
- if (is_self && static_context && !is_static) {
+ if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
if (parser->current_function) {
// Get the parent function above any lambda.
GDScriptParser::FunctionNode *parent_function = parser->current_function;
@@ -3118,10 +3132,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
push_error(vformat(R"*(Cannot call non-static function "%s()" for static variable initializer.)*", p_call->function_name), p_call);
}
- } else if (!is_self && base_type.is_meta_type && !is_static) {
+ } else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
base_type.is_meta_type = false; // For `to_string()`.
push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
- } else if (is_self && !is_static) {
+ } else if (is_self && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
mark_lambda_use_self();
}
@@ -3130,11 +3144,12 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
}
#ifdef DEBUG_ENABLED
- if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
+ if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL &&
+ !(p_call->is_super && p_call->function_name == GDScriptLanguage::get_singleton()->strings._init)) {
parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
}
- if (is_static && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) {
+ if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) {
String caller_type = String(base_type.native_type);
if (caller_type.is_empty()) {
@@ -3357,7 +3372,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
base = *p_base;
}
- const StringName &name = p_identifier->name;
+ StringName name = p_identifier->name;
if (base.kind == GDScriptParser::DataType::ENUM) {
if (base.is_meta_type) {
@@ -3452,12 +3467,18 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
get_class_node_current_scope_classes(base_class, &script_classes);
}
+ bool is_constructor = base.is_meta_type && p_identifier->name == SNAME("new");
+
for (GDScriptParser::ClassNode *script_class : script_classes) {
if (p_base == nullptr && script_class->identifier && script_class->identifier->name == name) {
reduce_identifier_from_base_set_class(p_identifier, script_class->get_datatype());
return;
}
+ if (is_constructor) {
+ name = "_init";
+ }
+
if (script_class->has_member(name)) {
resolve_class_member(script_class, name, p_identifier);
@@ -3507,7 +3528,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
} break;
case GDScriptParser::ClassNode::Member::FUNCTION: {
- if (is_base && !base.is_meta_type) {
+ if (is_base && (!base.is_meta_type || member.function->is_static)) {
p_identifier->set_datatype(make_callable_type(member.function->info));
return;
}
@@ -3536,6 +3557,10 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
const StringName &native = base.native_type;
if (class_exists(native)) {
+ if (is_constructor) {
+ name = "_init";
+ }
+
MethodInfo method_info;
if (ClassDB::has_property(native, name)) {
StringName getter_name = ClassDB::get_property_getter(native, name);
@@ -4650,9 +4675,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
return result;
}
-bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg, StringName *r_native_class) {
- r_static = false;
- r_vararg = false;
+bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags, StringName *r_native_class) {
+ r_method_flags = METHOD_FLAGS_DEFAULT;
r_default_arg_count = 0;
if (r_native_class) {
*r_native_class = StringName();
@@ -4685,10 +4709,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
for (const MethodInfo &E : methods) {
if (E.name == p_function) {
- function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
- r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name);
+ function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
// Cannot use non-const methods on enums.
- if (!r_static && was_enum && !(E.flags & METHOD_FLAG_CONST)) {
+ if (!r_method_flags.has_flag(METHOD_FLAG_STATIC) && was_enum && !(E.flags & METHOD_FLAG_CONST)) {
push_error(vformat(R"*(Cannot call non-const Dictionary function "%s()" on enum "%s".)*", p_function, p_base_type.enum_type), p_source);
}
return true;
@@ -4718,8 +4741,8 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
if (p_is_constructor) {
- function_name = "_init";
- r_static = true;
+ function_name = GDScriptLanguage::get_singleton()->strings._init;
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
}
GDScriptParser::ClassNode *base_class = p_base_type.class_type;
@@ -4742,7 +4765,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
if (found_function != nullptr) {
- r_static = p_is_constructor || found_function->is_static;
+ if (p_is_constructor || found_function->is_static) {
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
+ }
for (int i = 0; i < found_function->parameters.size(); i++) {
r_par_types.push_back(found_function->parameters[i]->get_datatype());
if (found_function->parameters[i]->initializer != nullptr) {
@@ -4762,7 +4787,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
MethodInfo info = base_script->get_method_info(function_name);
if (!(info == MethodInfo())) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
}
base_script = base_script->get_base_script();
}
@@ -4773,7 +4798,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
StringName script_class = p_base_type.kind == GDScriptParser::DataType::SCRIPT ? p_base_type.script_type->get_class_name() : StringName(GDScript::get_class_static());
if (ClassDB::get_method_info(script_class, function_name, &info)) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
}
}
@@ -4787,9 +4812,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
MethodInfo info;
if (ClassDB::get_method_info(base_native, function_name, &info)) {
- bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
if (valid && Engine::get_singleton()->has_singleton(base_native)) {
- r_static = true;
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
}
#ifdef DEBUG_ENABLED
MethodBind *native_method = ClassDB::get_method(base_native, function_name);
@@ -4803,11 +4828,10 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
return false;
}
-bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
+bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags) {
r_return_type = type_from_property(p_info.return_val);
r_default_arg_count = p_info.default_arguments.size();
- r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0;
- r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0;
+ r_method_flags = p_info.flags;
for (const PropertyInfo &E : p_info.arguments) {
r_par_types.push_back(type_from_property(E, true));
@@ -4937,6 +4961,17 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
}
GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
+ if (p_operation == Variant::OP_AND || p_operation == Variant::OP_OR) {
+ // Those work for any type of argument and always return a boolean.
+ // They don't use the Variant operator since they have short-circuit semantics.
+ r_valid = true;
+ GDScriptParser::DataType result;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::BOOL;
+ return result;
+ }
+
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 0c7bf4125b..195e23b503 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -31,11 +31,12 @@
#ifndef GDSCRIPT_ANALYZER_H
#define GDSCRIPT_ANALYZER_H
+#include "gdscript_cache.h"
+#include "gdscript_parser.h"
+
#include "core/object/object.h"
#include "core/object/ref_counted.h"
#include "core/templates/hash_set.h"
-#include "gdscript_cache.h"
-#include "gdscript_parser.h"
class GDScriptAnalyzer {
GDScriptParser *parser = nullptr;
@@ -115,8 +116,8 @@ class GDScriptAnalyzer {
static GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type);
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false, bool p_is_readonly = false) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
- bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg, StringName *r_native_class = nullptr);
- bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
+ bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags, StringName *r_native_class = nullptr);
+ bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags);
void validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
void validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 1414075ba8..47cd3f768b 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -30,9 +30,10 @@
#include "gdscript_byte_codegen.h"
-#include "core/debugger/engine_debugger.h"
#include "gdscript.h"
+#include "core/debugger/engine_debugger.h"
+
uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) {
#ifdef TOOLS_ENABLED
function->arg_names.push_back(p_name);
@@ -852,6 +853,20 @@ void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const
append(p_name);
}
+void GDScriptByteCodeGenerator::write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) {
+ append_opcode(GDScriptFunction::OPCODE_SET_STATIC_VARIABLE);
+ append(p_value);
+ append(p_class);
+ append(p_index);
+}
+
+void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) {
+ append_opcode(GDScriptFunction::OPCODE_GET_STATIC_VARIABLE);
+ append(p_target);
+ append(p_class);
+ append(p_index);
+}
+
void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) {
switch (p_target.type.kind) {
case GDScriptDataType::BUILTIN: {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index fc684e4d8f..bbcd252b13 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -32,7 +32,6 @@
#define GDSCRIPT_BYTE_CODEGEN_H
#include "gdscript_codegen.h"
-
#include "gdscript_function.h"
#include "gdscript_utility_functions.h"
@@ -366,8 +365,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
case Address::CONSTANT:
return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
- case Address::STATIC_VARIABLE:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_STATIC_VAR << GDScriptFunction::ADDR_BITS);
case Address::LOCAL_VARIABLE:
case Address::FUNCTION_PARAMETER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
@@ -503,6 +500,8 @@ public:
virtual void write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) override;
virtual void write_set_member(const Address &p_value, const StringName &p_name) override;
virtual void write_get_member(const Address &p_target, const StringName &p_name) override;
+ virtual void write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) override;
+ virtual void write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) override;
virtual void write_assign(const Address &p_target, const Address &p_source) override;
virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override;
virtual void write_assign_true(const Address &p_target) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 126fccbbf0..e5bb93e3c8 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -30,12 +30,13 @@
#include "gdscript_cache.h"
-#include "core/io/file_access.h"
-#include "core/templates/vector.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
+
+#include "core/io/file_access.h"
+#include "core/templates/vector.h"
#include "scene/resources/packed_scene.h"
bool GDScriptParserRef::is_valid() const {
@@ -253,7 +254,11 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e
Ref<GDScript> script;
script.instantiate();
script->set_path(p_path, true);
- script->load_source_code(p_path);
+ r_error = script->load_source_code(p_path);
+
+ if (r_error) {
+ return Ref<GDScript>(); // Returns null and does not cache when the script fails to load.
+ }
Ref<GDScriptParserRef> parser_ref = get_parser(p_path, GDScriptParserRef::PARSED, r_error);
if (r_error == OK) {
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 28266a1c0b..0a0f403e44 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -31,11 +31,12 @@
#ifndef GDSCRIPT_CACHE_H
#define GDSCRIPT_CACHE_H
+#include "gdscript.h"
+
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/templates/hash_map.h"
#include "core/templates/hash_set.h"
-#include "gdscript.h"
#include "scene/resources/packed_scene.h"
class GDScriptAnalyzer;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index dbc2466393..9810f5395a 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -31,11 +31,12 @@
#ifndef GDSCRIPT_CODEGEN_H
#define GDSCRIPT_CODEGEN_H
-#include "core/string/string_name.h"
-#include "core/variant/variant.h"
#include "gdscript_function.h"
#include "gdscript_utility_functions.h"
+#include "core/string/string_name.h"
+#include "core/variant/variant.h"
+
class GDScriptCodeGenerator {
public:
struct Address {
@@ -44,7 +45,6 @@ public:
CLASS,
MEMBER,
CONSTANT,
- STATIC_VARIABLE,
LOCAL_VARIABLE,
FUNCTION_PARAMETER,
TEMPORARY,
@@ -110,6 +110,8 @@ public:
virtual void write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) = 0;
virtual void write_set_member(const Address &p_value, const StringName &p_name) = 0;
virtual void write_get_member(const Address &p_target, const StringName &p_name) = 0;
+ virtual void write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) = 0;
+ virtual void write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) = 0;
virtual void write_assign(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_true(const Address &p_target) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index ba859a9f9b..90ee56b9de 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -262,18 +262,27 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
// Try static variables.
- if (codegen.script->static_variables_indices.has(identifier)) {
- if (codegen.script->static_variables_indices[identifier].getter != StringName() && codegen.script->static_variables_indices[identifier].getter != codegen.function_name) {
- // Perform getter.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->static_variables_indices[identifier].data_type);
- GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
- Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
- gen->write_call(temp, class_addr, codegen.script->static_variables_indices[identifier].getter, args);
- return temp;
- } else {
- // No getter or inside getter: direct variable access.
- int idx = codegen.script->static_variables_indices[identifier].index;
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::STATIC_VARIABLE, idx, codegen.script->static_variables_indices[identifier].data_type);
+ {
+ GDScript *scr = codegen.script;
+ while (scr) {
+ if (scr->static_variables_indices.has(identifier)) {
+ if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
+ // Perform getter.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
+ GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
+ Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
+ gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
+ return temp;
+ } else {
+ // No getter or inside getter: direct variable access.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
+ GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
+ int index = scr->static_variables_indices[identifier].index;
+ gen->write_get_static_variable(temp, _class, index);
+ return temp;
+ }
+ }
+ scr = scr->_base;
}
}
@@ -926,6 +935,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
bool member_property_has_setter = false;
bool member_property_is_in_setter = false;
bool is_static = false;
+ GDScriptCodeGenerator::Address static_var_class;
+ int static_var_index = 0;
+ GDScriptDataType static_var_data_type;
+ StringName var_name;
StringName member_property_setter_function;
List<const GDScriptParser::SubscriptNode *> chain;
@@ -939,19 +952,39 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Check for a property.
if (n->base->type == GDScriptParser::Node::IDENTIFIER) {
GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base);
- StringName var_name = identifier->name;
+ var_name = identifier->name;
if (_is_class_member_property(codegen, var_name)) {
assign_class_member_property = var_name;
- } else if (!_is_local_or_parameter(codegen, var_name) && (codegen.script->member_indices.has(var_name) || codegen.script->static_variables_indices.has(var_name))) {
- is_member_property = true;
- is_static = codegen.script->static_variables_indices.has(var_name);
- const GDScript::MemberInfo &minfo = is_static ? codegen.script->static_variables_indices[var_name] : codegen.script->member_indices[var_name];
- member_property_setter_function = minfo.setter;
- member_property_has_setter = member_property_setter_function != StringName();
- member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
- target_member_property.mode = is_static ? GDScriptCodeGenerator::Address::STATIC_VARIABLE : GDScriptCodeGenerator::Address::MEMBER;
- target_member_property.address = minfo.index;
- target_member_property.type = minfo.data_type;
+ } else if (!_is_local_or_parameter(codegen, var_name)) {
+ if (codegen.script->member_indices.has(var_name)) {
+ is_member_property = true;
+ is_static = false;
+ const GDScript::MemberInfo &minfo = codegen.script->member_indices[var_name];
+ member_property_setter_function = minfo.setter;
+ member_property_has_setter = member_property_setter_function != StringName();
+ member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
+ target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER;
+ target_member_property.address = minfo.index;
+ target_member_property.type = minfo.data_type;
+ } else {
+ // Try static variables.
+ GDScript *scr = codegen.script;
+ while (scr) {
+ if (scr->static_variables_indices.has(var_name)) {
+ is_member_property = true;
+ is_static = true;
+ const GDScript::MemberInfo &minfo = scr->static_variables_indices[var_name];
+ member_property_setter_function = minfo.setter;
+ member_property_has_setter = member_property_setter_function != StringName();
+ member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
+ static_var_class = codegen.add_constant(scr);
+ static_var_index = minfo.index;
+ static_var_data_type = minfo.data_type;
+ break;
+ }
+ scr = scr->_base;
+ }
+ }
}
}
break;
@@ -1104,8 +1137,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (member_property_has_setter && !member_property_is_in_setter) {
Vector<GDScriptCodeGenerator::Address> args;
args.push_back(assigned);
- GDScriptCodeGenerator::Address self = is_static ? GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS) : GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
- gen->write_call(GDScriptCodeGenerator::Address(), self, member_property_setter_function, args);
+ GDScriptCodeGenerator::Address call_base = is_static ? GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS) : GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
+ gen->write_call(GDScriptCodeGenerator::Address(), call_base, member_property_setter_function, args);
+ } else if (is_static) {
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(static_var_data_type);
+ gen->write_assign(temp, assigned);
+ gen->write_set_static_variable(temp, static_var_class, static_var_index);
+ gen->pop_temporary();
} else {
gen->write_assign(target_member_property, assigned);
}
@@ -1155,18 +1193,42 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
bool has_setter = false;
bool is_in_setter = false;
bool is_static = false;
+ GDScriptCodeGenerator::Address static_var_class;
+ int static_var_index = 0;
+ GDScriptDataType static_var_data_type;
+ StringName var_name;
StringName setter_function;
- StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (!_is_local_or_parameter(codegen, var_name) && (codegen.script->member_indices.has(var_name) || codegen.script->static_variables_indices.has(var_name))) {
- is_member = true;
- is_static = codegen.script->static_variables_indices.has(var_name);
- GDScript::MemberInfo &minfo = is_static ? codegen.script->static_variables_indices[var_name] : codegen.script->member_indices[var_name];
- setter_function = minfo.setter;
- has_setter = setter_function != StringName();
- is_in_setter = has_setter && setter_function == codegen.function_name;
- member.mode = is_static ? GDScriptCodeGenerator::Address::STATIC_VARIABLE : GDScriptCodeGenerator::Address::MEMBER;
- member.address = minfo.index;
- member.type = minfo.data_type;
+ var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
+ if (!_is_local_or_parameter(codegen, var_name)) {
+ if (codegen.script->member_indices.has(var_name)) {
+ is_member = true;
+ is_static = false;
+ GDScript::MemberInfo &minfo = codegen.script->member_indices[var_name];
+ setter_function = minfo.setter;
+ has_setter = setter_function != StringName();
+ is_in_setter = has_setter && setter_function == codegen.function_name;
+ member.mode = GDScriptCodeGenerator::Address::MEMBER;
+ member.address = minfo.index;
+ member.type = minfo.data_type;
+ } else {
+ // Try static variables.
+ GDScript *scr = codegen.script;
+ while (scr) {
+ if (scr->static_variables_indices.has(var_name)) {
+ is_member = true;
+ is_static = true;
+ GDScript::MemberInfo &minfo = scr->static_variables_indices[var_name];
+ setter_function = minfo.setter;
+ has_setter = setter_function != StringName();
+ is_in_setter = has_setter && setter_function == codegen.function_name;
+ static_var_class = codegen.add_constant(scr);
+ static_var_index = minfo.index;
+ static_var_data_type = minfo.data_type;
+ break;
+ }
+ scr = scr->_base;
+ }
+ }
}
GDScriptCodeGenerator::Address target;
@@ -1200,13 +1262,21 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
to_assign = assigned_value;
}
- GDScriptDataType assign_type = _gdtype_from_datatype(assignment->assignee->get_datatype(), codegen.script);
-
if (has_setter && !is_in_setter) {
// Call setter.
Vector<GDScriptCodeGenerator::Address> args;
args.push_back(to_assign);
- gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args);
+ GDScriptCodeGenerator::Address call_base = is_static ? GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS) : GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
+ gen->write_call(GDScriptCodeGenerator::Address(), call_base, setter_function, args);
+ } else if (is_static) {
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(static_var_data_type);
+ if (assignment->use_conversion_assign) {
+ gen->write_assign_with_conversion(temp, to_assign);
+ } else {
+ gen->write_assign(temp, to_assign);
+ }
+ gen->write_set_static_variable(temp, static_var_class, static_var_index);
+ gen->pop_temporary();
} else {
// Just assign.
if (assignment->use_conversion_assign) {
@@ -2095,11 +2165,11 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
}
GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
- GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
-
if (field_type.has_type) {
codegen.generator->write_newline(field->start_line);
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
+
if (field_type.has_container_element_type()) {
codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
@@ -2126,9 +2196,6 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
continue;
}
- GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
-
- GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
if (field->initializer) {
// Emit proper line change.
codegen.generator->write_newline(field->initializer->start_line);
@@ -2139,6 +2206,9 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
return nullptr;
}
+ GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
+
if (field->use_conversion_assign) {
codegen.generator->write_assign_with_conversion(dst_address, src_address);
} else {
@@ -2268,6 +2338,8 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
codegen.is_static = is_static;
codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
+ // The static initializer is always called on the same class where the static variables are defined,
+ // so the CLASS address (current class) can be used instead of `codegen.add_constant(p_script)`.
GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
// Initialize the default values for typed variables before anything.
@@ -2284,20 +2356,18 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
}
GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
-
if (field_type.has_type) {
codegen.generator->write_newline(field->start_line);
if (field_type.has_container_element_type()) {
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
- codegen.generator->write_set_named(class_addr, field->identifier->name, temp);
+ codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
codegen.generator->pop_temporary();
-
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
codegen.generator->write_construct(temp, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
- codegen.generator->write_set_named(class_addr, field->identifier->name, temp);
+ codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
codegen.generator->pop_temporary();
}
// The `else` branch is for objects, in such case we leave it as `null`.
@@ -2314,8 +2384,6 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
continue;
}
- GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
-
if (field->initializer) {
// Emit proper line change.
codegen.generator->write_newline(field->initializer->start_line);
@@ -2326,7 +2394,9 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
return nullptr;
}
+ GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
+
if (field->use_conversion_assign) {
codegen.generator->write_assign_with_conversion(temp, src_address);
} else {
@@ -2336,7 +2406,7 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
codegen.generator->pop_temporary();
}
- codegen.generator->write_set_named(class_addr, field->identifier->name, temp);
+ codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
codegen.generator->pop_temporary();
}
}
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 2d15d461fb..494eef41d9 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -31,12 +31,13 @@
#ifndef GDSCRIPT_COMPILER_H
#define GDSCRIPT_COMPILER_H
-#include "core/templates/hash_set.h"
#include "gdscript.h"
#include "gdscript_codegen.h"
#include "gdscript_function.h"
#include "gdscript_parser.h"
+#include "core/templates/hash_set.h"
+
class GDScriptCompiler {
const GDScriptParser *parser = nullptr;
HashSet<GDScript *> parsed_classes;
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 45ad8792d9..0438bd8903 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -30,10 +30,10 @@
#ifdef DEBUG_ENABLED
+#include "gdscript.h"
#include "gdscript_function.h"
#include "core/string/string_builder.h"
-#include "gdscript.h"
static String _get_variant_string(const Variant &p_variant) {
String txt;
@@ -312,6 +312,36 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 3;
} break;
+ case OPCODE_SET_STATIC_VARIABLE: {
+ text += "set_static_variable script(";
+ Ref<GDScript> gdscript = get_constant(_code_ptr[ip + 2] & GDScriptFunction::ADDR_MASK);
+ text += gdscript.is_valid() ? gdscript->get_fully_qualified_name().get_file() : "<unknown script>";
+ text += ")";
+ if (gdscript.is_valid()) {
+ text += "[\"" + gdscript->debug_get_static_var_by_index(_code_ptr[ip + 3]) + "\"]";
+ } else {
+ text += "[<index " + itos(_code_ptr[ip + 3]) + ">]";
+ }
+ text += " = ";
+ text += DADDR(1);
+
+ incr += 4;
+ } break;
+ case OPCODE_GET_STATIC_VARIABLE: {
+ text += "get_static_variable ";
+ text += DADDR(1);
+ text += " = script(";
+ Ref<GDScript> gdscript = get_constant(_code_ptr[ip + 2] & GDScriptFunction::ADDR_MASK);
+ text += gdscript.is_valid() ? gdscript->get_fully_qualified_name().get_file() : "<unknown script>";
+ text += ")";
+ if (gdscript.is_valid()) {
+ text += "[\"" + gdscript->debug_get_static_var_by_index(_code_ptr[ip + 3]) + "\"]";
+ } else {
+ text += "[<index " + itos(_code_ptr[ip + 3]) + ">]";
+ }
+
+ incr += 4;
+ } break;
case OPCODE_ASSIGN: {
text += "assign ";
text += DADDR(1);
@@ -1130,4 +1160,4 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
}
}
-#endif
+#endif // DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 09af51656c..cd34feb8b3 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -30,9 +30,6 @@
#include "gdscript.h"
-#include "core/config/engine.h"
-#include "core/core_constants.h"
-#include "core/io/file_access.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
@@ -40,10 +37,17 @@
#include "gdscript_utility_functions.h"
#ifdef TOOLS_ENABLED
+#include "editor/script_templates/templates.gen.h"
+#endif
+
+#include "core/config/engine.h"
+#include "core/core_constants.h"
+#include "core/io/file_access.h"
+
+#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
#include "editor/editor_file_system.h"
#include "editor/editor_settings.h"
-#include "editor/script_templates/templates.gen.h"
#endif
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
@@ -3399,7 +3403,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
case GDScriptParser::COMPLETION_ASSIGN:
case GDScriptParser::COMPLETION_CALL_ARGUMENTS:
- case GDScriptParser::COMPLETION_IDENTIFIER: {
+ case GDScriptParser::COMPLETION_IDENTIFIER:
+ case GDScriptParser::COMPLETION_PROPERTY_METHOD: {
GDScriptParser::DataType base_type;
if (context.current_class) {
if (context.type != GDScriptParser::COMPLETION_SUPER_METHOD) {
@@ -3528,6 +3533,33 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
return OK;
}
} break;
+ case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
+ if (context.node == nullptr || context.node->type != GDScriptParser::Node::TYPE) {
+ break;
+ }
+ const GDScriptParser::TypeNode *type = static_cast<const GDScriptParser::TypeNode *>(context.node);
+
+ GDScriptParser::DataType base_type;
+ const GDScriptParser::IdentifierNode *prev = nullptr;
+ for (const GDScriptParser::IdentifierNode *E : type->type_chain) {
+ if (E->name == p_symbol && prev != nullptr) {
+ base_type = prev->get_datatype();
+ break;
+ }
+ prev = E;
+ }
+ if (base_type.kind != GDScriptParser::DataType::CLASS) {
+ GDScriptCompletionIdentifier base;
+ if (!_guess_expression_type(context, prev, base)) {
+ break;
+ }
+ base_type = base.type;
+ }
+
+ if (_lookup_symbol_from_base(base_type, p_symbol, is_function, r_result) == OK) {
+ return OK;
+ }
+ } break;
case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
GDScriptParser::DataType base_type = context.current_class->base_type;
@@ -3535,6 +3567,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
return OK;
}
} break;
+ case GDScriptParser::COMPLETION_PROPERTY_DECLARATION_OR_TYPE:
case GDScriptParser::COMPLETION_TYPE_NAME_OR_VOID:
case GDScriptParser::COMPLETION_TYPE_NAME: {
GDScriptParser::DataType base_type = context.current_class->get_datatype();
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 390e562e6f..9bbfb14f31 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -31,6 +31,8 @@
#ifndef GDSCRIPT_FUNCTION_H
#define GDSCRIPT_FUNCTION_H
+#include "gdscript_utility_functions.h"
+
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
#include "core/os/thread.h"
@@ -38,7 +40,6 @@
#include "core/templates/pair.h"
#include "core/templates/self_list.h"
#include "core/variant/variant.h"
-#include "gdscript_utility_functions.h"
class GDScriptInstance;
class GDScript;
@@ -148,6 +149,7 @@ public:
operator PropertyInfo() const {
PropertyInfo info;
+ info.usage = PROPERTY_USAGE_NONE;
if (has_type) {
switch (kind) {
case UNINITIALIZED:
@@ -237,6 +239,8 @@ public:
OPCODE_GET_NAMED_VALIDATED,
OPCODE_SET_MEMBER,
OPCODE_GET_MEMBER,
+ OPCODE_SET_STATIC_VARIABLE, // Only for GDScript.
+ OPCODE_GET_STATIC_VARIABLE, // Only for GDScript.
OPCODE_ASSIGN,
OPCODE_ASSIGN_TRUE,
OPCODE_ASSIGN_FALSE,
@@ -409,14 +413,14 @@ public:
ADDR_TYPE_STACK = 0,
ADDR_TYPE_CONSTANT = 1,
ADDR_TYPE_MEMBER = 2,
- ADDR_TYPE_STATIC_VAR = 3,
- ADDR_TYPE_MAX = 4,
+ ADDR_TYPE_MAX = 3,
};
enum FixedAddresses {
ADDR_STACK_SELF = 0,
ADDR_STACK_CLASS = 1,
ADDR_STACK_NIL = 2,
+ FIXED_ADDRESSES_MAX = 3,
ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS),
ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS),
ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS),
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index e9fe17bb17..9e14e43a58 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -30,9 +30,10 @@
#include "gdscript_lambda_callable.h"
-#include "core/templates/hashfuncs.h"
#include "gdscript.h"
+#include "core/templates/hashfuncs.h"
+
bool GDScriptLambdaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
// Lambda callables are only compared by reference.
return p_a == p_b;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d90503c658..cf750958ee 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -30,23 +30,27 @@
#include "gdscript_parser.h"
+#include "gdscript.h"
+
+#ifdef DEBUG_ENABLED
+#include "gdscript_warning.h"
+#endif
+
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
-#include "gdscript.h"
#include "scene/main/multiplayer_api.h"
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#include "core/string/string_builder.h"
-#include "gdscript_warning.h"
#include "servers/text_server.h"
-#endif // DEBUG_ENABLED
+#endif
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
-#endif // TOOLS_ENABLED
+#endif
static HashMap<StringName, Variant::Type> builtin_types;
Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
@@ -112,7 +116,7 @@ GDScriptParser::GDScriptParser() {
// Warning annotations.
register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true);
// Networking.
- register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("authority", "call_remote", "unreliable", 0), true);
+ register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("authority", "call_remote", "unreliable", 0));
#ifdef DEBUG_ENABLED
is_ignoring_warnings = !(bool)GLOBAL_GET("debug/gdscript/warnings/enable");
@@ -2760,12 +2764,12 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
switch (dictionary->style) {
case DictionaryNode::LUA_TABLE:
if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) {
- push_error("Expected identifier or string as LUA-style dictionary key.");
+ push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
advance();
break;
}
if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) {
- push_error("Expected identifier or string as LUA-style dictionary key.");
+ push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
advance();
break;
}
@@ -3823,8 +3827,12 @@ bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node
}
VariableNode *variable = static_cast<VariableNode *>(p_node);
+ if (variable->is_static) {
+ push_error(R"("@onready" annotation cannot be applied to a static variable.)", p_annotation);
+ return false;
+ }
if (variable->onready) {
- push_error(R"("@onready" annotation can only be used once per variable.)");
+ push_error(R"("@onready" annotation can only be used once per variable.)", p_annotation);
return false;
}
variable->onready = true;
@@ -3837,6 +3845,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
VariableNode *variable = static_cast<VariableNode *>(p_node);
+ if (variable->is_static) {
+ push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
+ return false;
+ }
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
return false;
@@ -4137,21 +4149,16 @@ bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_
Dictionary rpc_config;
rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY;
if (!p_annotation->resolved_arguments.is_empty()) {
- int last = p_annotation->resolved_arguments.size() - 1;
- if (p_annotation->resolved_arguments[last].get_type() == Variant::INT) {
- rpc_config["channel"] = p_annotation->resolved_arguments[last].operator int();
- last -= 1;
- }
- if (last > 3) {
- push_error(R"(Invalid RPC arguments. At most 4 arguments are allowed, where only the last argument can be an integer to specify the channel.')", p_annotation);
- return false;
- }
-
unsigned char locality_args = 0;
unsigned char permission_args = 0;
unsigned char transfer_mode_args = 0;
- for (int i = last; i >= 0; i--) {
+ for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
+ if (i == 3) {
+ rpc_config["channel"] = p_annotation->resolved_arguments[i].operator int();
+ continue;
+ }
+
String arg = p_annotation->resolved_arguments[i].operator String();
if (arg == "call_local") {
locality_args++;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 8f0265510f..ad08c3bfd6 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -31,6 +31,13 @@
#ifndef GDSCRIPT_PARSER_H
#define GDSCRIPT_PARSER_H
+#include "gdscript_cache.h"
+#include "gdscript_tokenizer.h"
+
+#ifdef DEBUG_ENABLED
+#include "gdscript_warning.h"
+#endif
+
#include "core/io/resource.h"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
@@ -41,13 +48,10 @@
#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
-#include "gdscript_cache.h"
-#include "gdscript_tokenizer.h"
#ifdef DEBUG_ENABLED
#include "core/string/string_builder.h"
-#include "gdscript_warning.h"
-#endif // DEBUG_ENABLED
+#endif
class GDScriptParser {
struct AnnotationInfo;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index a45a73a8d5..3927a4dd3e 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -33,13 +33,14 @@
#include "core/error/error_macros.h"
#include "core/string/char_utils.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
#ifdef DEBUG_ENABLED
#include "servers/text_server.h"
#endif
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
static const char *token_names[] = {
"Empty", // EMPTY,
// Basic
@@ -162,6 +163,24 @@ const char *GDScriptTokenizer::Token::get_name() const {
return token_names[type];
}
+bool GDScriptTokenizer::Token::can_precede_bin_op() const {
+ switch (type) {
+ case IDENTIFIER:
+ case LITERAL:
+ case SELF:
+ case BRACKET_CLOSE:
+ case BRACE_CLOSE:
+ case PARENTHESIS_CLOSE:
+ case CONST_PI:
+ case CONST_TAU:
+ case CONST_INF:
+ case CONST_NAN:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool GDScriptTokenizer::Token::is_identifier() const {
// Note: Most keywords should not be recognized as identifiers.
// These are only exceptions for stuff that already is on the engine's API.
@@ -382,6 +401,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::make_token(Token::Type p_type) {
}
}
+ last_token = token;
return token;
}
@@ -627,6 +647,7 @@ void GDScriptTokenizer::newline(bool p_make_token) {
newline.leftmost_column = newline.start_column;
newline.rightmost_column = newline.end_column;
pending_newline = true;
+ last_token = newline;
last_newline = newline;
}
@@ -643,6 +664,11 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
bool has_error = false;
bool (*digit_check_func)(char32_t) = is_digit;
+ // Sign before hexadecimal or binary.
+ if ((_peek(-1) == '+' || _peek(-1) == '-') && _peek() == '0') {
+ _advance();
+ }
+
if (_peek(-1) == '.') {
has_decimal = true;
} else if (_peek(-1) == '0') {
@@ -659,12 +685,20 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
}
}
- // Allow '_' to be used in a number, for readability.
- bool previous_was_underscore = false;
+ if (base != 10 && is_underscore(_peek())) { // Disallow `0x_` and `0b_`.
+ Token error = make_error(vformat(R"(Unexpected underscore after "0%c".)", _peek(-1)));
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ has_error = true;
+ }
+ bool previous_was_underscore = false; // Allow `_` to be used in a number, for readability.
while (digit_check_func(_peek()) || is_underscore(_peek())) {
if (is_underscore(_peek())) {
if (previous_was_underscore) {
- Token error = make_error(R"(Only one underscore can be used as a numeric separator.)");
+ Token error = make_error(R"(Multiple underscores cannot be adjacent in a numeric literal.)");
error.start_column = column;
error.leftmost_column = column;
error.end_column = column + 1;
@@ -711,7 +745,30 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
_advance();
// Consume decimal digits.
+ if (is_underscore(_peek())) { // Disallow `10._`, but allow `10.`.
+ Token error = make_error(R"(Unexpected underscore after decimal point.)");
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ has_error = true;
+ }
+ previous_was_underscore = false;
while (is_digit(_peek()) || is_underscore(_peek())) {
+ if (is_underscore(_peek())) {
+ if (previous_was_underscore) {
+ Token error = make_error(R"(Multiple underscores cannot be adjacent in a numeric literal.)");
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ }
+ previous_was_underscore = true;
+ } else {
+ previous_was_underscore = false;
+ }
_advance();
}
}
@@ -737,7 +794,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
while (is_digit(_peek()) || is_underscore(_peek())) {
if (is_underscore(_peek())) {
if (previous_was_underscore) {
- Token error = make_error(R"(Only one underscore can be used as a numeric separator.)");
+ Token error = make_error(R"(Multiple underscores cannot be adjacent in a numeric literal.)");
error.start_column = column;
error.leftmost_column = column;
error.end_column = column + 1;
@@ -1431,6 +1488,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (_peek() == '=') {
_advance();
return make_token(Token::PLUS_EQUAL);
+ } else if (is_digit(_peek()) && !last_token.can_precede_bin_op()) {
+ // Number starting with '+'.
+ return number();
} else {
return make_token(Token::PLUS);
}
@@ -1438,6 +1498,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (_peek() == '=') {
_advance();
return make_token(Token::MINUS_EQUAL);
+ } else if (is_digit(_peek()) && !last_token.can_precede_bin_op()) {
+ // Number starting with '-'.
+ return number();
} else if (_peek() == '>') {
_advance();
return make_token(Token::FORWARD_ARROW);
@@ -1547,9 +1610,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
default:
if (is_whitespace(c)) {
- return make_error(vformat(R"(Invalid white space character "\\u%X".)", static_cast<int32_t>(c)));
+ return make_error(vformat(R"(Invalid white space character U+%04X.)", static_cast<int32_t>(c)));
} else {
- return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1)));
+ return make_error(vformat(R"(Invalid character "%c" (U+%04X).)", c, static_cast<int32_t>(c)));
}
}
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 608840d3f1..068393cee9 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -171,6 +171,7 @@ public:
String source;
const char *get_name() const;
+ bool can_precede_bin_op() const;
bool is_identifier() const;
bool is_node_name() const;
StringName get_identifier() const { return source; }
@@ -216,6 +217,7 @@ private:
bool multiline_mode = false;
List<Token> error_stack;
bool pending_newline = false;
+ Token last_token;
Token last_newline;
int pending_indents = 0;
List<int> indent_stack;
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 8862450121..030950267d 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -30,6 +30,8 @@
#include "gdscript_utility_functions.h"
+#include "gdscript.h"
+
#include "core/io/resource_loader.h"
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
@@ -37,7 +39,6 @@
#include "core/templates/oa_hash_map.h"
#include "core/templates/vector.h"
#include "core/variant/typed_array.h"
-#include "gdscript.h"
#ifdef DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index bebf34cbb3..4545689bd9 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
+#include "gdscript.h"
#include "gdscript_function.h"
+#include "gdscript_lambda_callable.h"
#include "core/core_string_names.h"
#include "core/os/os.h"
-#include "gdscript.h"
-#include "gdscript_lambda_callable.h"
#ifdef DEBUG_ENABLED
static String _get_script_name(const Ref<Script> p_script) {
@@ -217,6 +217,8 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_GET_NAMED_VALIDATED, \
&&OPCODE_SET_MEMBER, \
&&OPCODE_GET_MEMBER, \
+ &&OPCODE_SET_STATIC_VARIABLE, \
+ &&OPCODE_GET_STATIC_VARIABLE, \
&&OPCODE_ASSIGN, \
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
@@ -666,7 +668,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Variant *m_v = instruction_args[m_idx]
#ifdef DEBUG_ENABLED
-
uint64_t function_start_time = 0;
uint64_t function_call_time = 0;
@@ -679,11 +680,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
bool exit_ok = false;
bool awaited = false;
#endif
+
#ifdef DEBUG_ENABLED
- int variant_address_limits[ADDR_TYPE_MAX] = { _stack_size, _constant_count, p_instance ? p_instance->members.size() : 0, script->static_variables.size() };
+ int variant_address_limits[ADDR_TYPE_MAX] = { _stack_size, _constant_count, p_instance ? p_instance->members.size() : 0 };
#endif
- Variant *variant_addresses[ADDR_TYPE_MAX] = { stack, _constants_ptr, p_instance ? p_instance->members.ptrw() : nullptr, script->static_variables.ptrw() };
+ Variant *variant_addresses[ADDR_TYPE_MAX] = { stack, _constants_ptr, p_instance ? p_instance->members.ptrw() : nullptr };
#ifdef DEBUG_ENABLED
OPCODE_WHILE(ip < _code_size) {
@@ -1171,6 +1173,42 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_SET_STATIC_VARIABLE) {
+ CHECK_SPACE(4);
+
+ GET_VARIANT_PTR(value, 0);
+
+ GET_VARIANT_PTR(_class, 1);
+ GDScript *gdscript = Object::cast_to<GDScript>(_class->operator Object *());
+ GD_ERR_BREAK(!gdscript);
+
+ int index = _code_ptr[ip + 3];
+ GD_ERR_BREAK(index < 0 || index >= gdscript->static_variables.size());
+
+ gdscript->static_variables.write[index] = *value;
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_STATIC_VARIABLE) {
+ CHECK_SPACE(4);
+
+ GET_VARIANT_PTR(target, 0);
+
+ GET_VARIANT_PTR(_class, 1);
+ GDScript *gdscript = Object::cast_to<GDScript>(_class->operator Object *());
+ GD_ERR_BREAK(!gdscript);
+
+ int index = _code_ptr[ip + 3];
+ GD_ERR_BREAK(index < 0 || index >= gdscript->static_variables.size());
+
+ *target = gdscript->static_variables[index];
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN) {
CHECK_SPACE(3);
GET_VARIANT_PTR(dst, 0);
@@ -3620,7 +3658,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
// Free stack, except reserved addresses.
- for (int i = 3; i < _stack_size; i++) {
+ for (int i = FIXED_ADDRESSES_MAX; i < _stack_size; i++) {
stack[i].~Variant();
}
#ifdef DEBUG_ENABLED
@@ -3628,7 +3666,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
// Always free reserved addresses, since they are never copied.
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < FIXED_ADDRESSES_MAX; i++) {
stack[i].~Variant();
}
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 4500cb01f3..4fd27de081 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -32,9 +32,10 @@
#define GDSCRIPT_EXTEND_PARSER_H
#include "../gdscript_parser.h"
-#include "core/variant/variant.h"
#include "godot_lsp.h"
+#include "core/variant/variant.h"
+
#ifndef LINE_NUMBER_TO_INDEX
#define LINE_NUMBER_TO_INDEX(p_line) ((p_line)-1)
#endif
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index d25814f8aa..a4d9dc6b1d 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -31,13 +31,14 @@
#ifndef GDSCRIPT_LANGUAGE_PROTOCOL_H
#define GDSCRIPT_LANGUAGE_PROTOCOL_H
-#include "core/io/stream_peer.h"
-#include "core/io/stream_peer_tcp.h"
-#include "core/io/tcp_server.h"
#include "gdscript_text_document.h"
#include "gdscript_workspace.h"
#include "godot_lsp.h"
+#include "core/io/stream_peer.h"
+#include "core/io/stream_peer_tcp.h"
+#include "core/io/tcp_server.h"
+
#include "modules/modules_enabled.gen.h" // For jsonrpc.
#ifdef MODULE_JSONRPC_ENABLED
#include "modules/jsonrpc/jsonrpc.h"
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index a130dc3ac8..75f9403a74 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -32,9 +32,10 @@
#define GDSCRIPT_LANGUAGE_SERVER_H
#include "../gdscript_parser.h"
-#include "editor/editor_plugin.h"
#include "gdscript_language_protocol.h"
+#include "editor/editor_plugin.h"
+
class GDScriptLanguageServer : public EditorPlugin {
GDCLASS(GDScriptLanguageServer, EditorPlugin);
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 35fbdca949..92a5f55978 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -31,11 +31,12 @@
#include "gdscript_text_document.h"
#include "../gdscript.h"
+#include "gdscript_extend_parser.h"
+#include "gdscript_language_protocol.h"
+
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/plugins/script_text_editor.h"
-#include "gdscript_extend_parser.h"
-#include "gdscript_language_protocol.h"
#include "servers/display_server.h"
void GDScriptTextDocument::_bind_methods() {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index aeda10de89..0121101db2 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -31,9 +31,10 @@
#ifndef GDSCRIPT_TEXT_DOCUMENT_H
#define GDSCRIPT_TEXT_DOCUMENT_H
+#include "godot_lsp.h"
+
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
-#include "godot_lsp.h"
class GDScriptTextDocument : public RefCounted {
GDCLASS(GDScriptTextDocument, RefCounted)
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 7fc2962341..9f848b02f5 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -32,6 +32,8 @@
#include "../gdscript.h"
#include "../gdscript_parser.h"
+#include "gdscript_language_protocol.h"
+
#include "core/config/project_settings.h"
#include "core/object/script_language.h"
#include "editor/doc_tools.h"
@@ -39,7 +41,6 @@
#include "editor/editor_help.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
-#include "gdscript_language_protocol.h"
#include "scene/resources/packed_scene.h"
void GDScriptWorkspace::_bind_methods() {
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index a849ef8a8d..80653778fb 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -32,11 +32,12 @@
#define GDSCRIPT_WORKSPACE_H
#include "../gdscript_parser.h"
-#include "core/variant/variant.h"
-#include "editor/editor_file_system.h"
#include "gdscript_extend_parser.h"
#include "godot_lsp.h"
+#include "core/variant/variant.h"
+#include "editor/editor_file_system.h"
+
class GDScriptWorkspace : public RefCounted {
GDCLASS(GDScriptWorkspace, RefCounted);
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index b6feaadccf..e23bd50b8b 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -30,39 +30,51 @@
#include "register_types.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/file_access_encrypted.h"
-#include "core/io/resource_loader.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
#include "gdscript_utility_functions.h"
+#ifdef TOOLS_ENABLED
+#include "editor/gdscript_highlighter.h"
+#include "editor/gdscript_translation_parser_plugin.h"
+
+#ifndef GDSCRIPT_NO_LSP
+#include "language_server/gdscript_language_server.h"
+#endif
+#endif // TOOLS_ENABLED
+
#ifdef TESTS_ENABLED
#include "tests/test_gdscript.h"
-#include "tests/test_macros.h"
#endif
-GDScriptLanguage *script_language_gd = nullptr;
-Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
-Ref<ResourceFormatSaverGDScript> resource_saver_gd;
-GDScriptCache *gdscript_cache = nullptr;
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/io/file_access_encrypted.h"
+#include "core/io/resource_loader.h"
#ifdef TOOLS_ENABLED
-
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_translation_parser.h"
#include "editor/export/editor_export.h"
-#include "editor/gdscript_highlighter.h"
-#include "editor/gdscript_translation_parser_plugin.h"
#ifndef GDSCRIPT_NO_LSP
#include "core/config/engine.h"
-#include "language_server/gdscript_language_server.h"
-#endif // !GDSCRIPT_NO_LSP
+#endif
+#endif // TOOLS_ENABLED
+
+#ifdef TESTS_ENABLED
+#include "tests/test_macros.h"
+#endif
+
+GDScriptLanguage *script_language_gd = nullptr;
+Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
+Ref<ResourceFormatSaverGDScript> resource_saver_gd;
+GDScriptCache *gdscript_cache = nullptr;
+
+#ifdef TOOLS_ENABLED
Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin;
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
index 60b48c6a57..b1190604ad 100644
--- a/modules/gdscript/tests/gdscript_test_runner.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -32,6 +32,7 @@
#define GDSCRIPT_TEST_RUNNER_H
#include "../gdscript.h"
+
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index e27b6218f1..5fd7d942d2 100644
--- a/modules/gdscript/tests/gdscript_test_runner_suite.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -32,6 +32,7 @@
#define GDSCRIPT_TEST_RUNNER_SUITE_H
#include "gdscript_test_runner.h"
+
#include "tests/test_macros.h"
namespace GDScriptTests {
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.gd
new file mode 100644
index 0000000000..66697cbb29
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.gd
@@ -0,0 +1,8 @@
+# GH-77098 p.3
+
+@static_unload
+
+@export static var a: int
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.out b/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.out
new file mode 100644
index 0000000000..4111aa07af
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_export_annotation.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Annotation "@export" cannot be applied to a static variable.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.gd b/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.gd
new file mode 100644
index 0000000000..c34d927035
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.gd
@@ -0,0 +1,2 @@
+func test():
+ _get_property_list()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.out b/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.out
new file mode 100644
index 0000000000..ce2f49a5e5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_method_not_implemented.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call virtual function "_get_property_list()" because it hasn't been defined.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd
new file mode 100644
index 0000000000..57dfffdbee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd
@@ -0,0 +1,5 @@
+func _init():
+ super()
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out
new file mode 100644
index 0000000000..e68759223c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call the parent class' virtual function "_init()" because it hasn't been defined.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd
new file mode 100644
index 0000000000..73d0f9096c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd
@@ -0,0 +1,347 @@
+extends Resource
+
+signal foo
+
+func test():
+ var x
+ # TYPE_NIL
+ x = null
+ prints("TYPE_NIL")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_BOOL
+ x = true
+ prints("TYPE_BOOL")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_INT
+ x = 1
+ prints("TYPE_INT")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_FLOAT
+ x = 1.1
+ prints("TYPE_FLOAT")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_STRING
+ x = "foo"
+ prints("TYPE_STRING")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR2
+ x = Vector2(1, 1)
+ prints("TYPE_VECTOR2")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR2I
+ x = Vector2i(1, 1)
+ prints("TYPE_VECTOR2I")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_RECT2
+ x = Rect2(1, 1, 1, 1)
+ prints("TYPE_RECT2")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_RECT2I
+ x = Rect2i(1, 1, 1, 1)
+ prints("TYPE_RECT2I")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR3
+ x = Vector3(1, 1, 1)
+ prints("TYPE_VECTOR3")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR3I
+ x = Vector3i(1, 1, 1)
+ prints("TYPE_VECTOR3I")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_TRANSFORM2D
+ x = Transform2D.IDENTITY
+ prints("TYPE_TRANSFORM2D")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR4
+ x = Vector4(1, 1, 1, 1)
+ prints("TYPE_VECTOR4")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_VECTOR4I
+ x = Vector4i(1, 1, 1, 1)
+ prints("TYPE_VECTOR4I")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PLANE
+ x = Plane.PLANE_XY
+ prints("TYPE_PLANE")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_QUATERNION
+ x = Quaternion.IDENTITY
+ prints("TYPE_QUATERNION")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_AABB
+ x = AABB(Vector3.ONE, Vector3.ONE)
+ prints("TYPE_AABB")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_BASIS
+ x = Basis.IDENTITY
+ prints("TYPE_BASIS")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_TRANSFORM3D
+ x = Transform3D.IDENTITY
+ prints("TYPE_TRANSFORM3D")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PROJECTION
+ x = Projection.IDENTITY
+ prints("TYPE_PROJECTION")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_COLOR
+ x = Color.WHITE
+ prints("TYPE_COLOR")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_STRING_NAME
+ x = &"name"
+ prints("TYPE_STRING_NAME")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_NODE_PATH
+ x = ^"path"
+ prints("TYPE_NODE_PATH")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_RID
+ x = get_rid()
+ prints("TYPE_RID")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_OBJECT
+ x = self
+ prints("TYPE_OBJECT")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_CALLABLE
+ x = test
+ prints("TYPE_CALLABLE")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_SIGNAL
+ x = foo
+ prints("TYPE_SIGNAL")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_DICTIONARY
+ x = { a = 1}
+ prints("TYPE_DICTIONARY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_ARRAY
+ x = [1]
+ prints("TYPE_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_BYTE_ARRAY
+ x = PackedByteArray([1])
+ prints("TYPE_PACKED_BYTE_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_INT32_ARRAY
+ x = PackedInt32Array([1])
+ prints("TYPE_PACKED_INT32_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_INT64_ARRAY
+ x = PackedInt64Array([1])
+ prints("TYPE_PACKED_INT64_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_FLOAT32_ARRAY
+ x = PackedFloat32Array([1])
+ prints("TYPE_PACKED_FLOAT32_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_FLOAT64_ARRAY
+ x = PackedFloat64Array([1])
+ prints("TYPE_PACKED_FLOAT64_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_STRING_ARRAY
+ x = PackedStringArray(["1"])
+ prints("TYPE_PACKED_STRING_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_VECTOR2_ARRAY
+ x = PackedVector2Array([Vector2.ONE])
+ prints("TYPE_PACKED_VECTOR2_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_VECTOR3_ARRAY
+ x = PackedVector3Array([Vector3.ONE])
+ prints("TYPE_PACKED_VECTOR3_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
+
+ # TYPE_PACKED_COLOR_ARRAY
+ x = PackedColorArray([Color.WHITE])
+ prints("TYPE_PACKED_COLOR_ARRAY")
+ prints(not x)
+ prints(x and false)
+ prints(x and true)
+ prints(x or false)
+ prints(x or true)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out
new file mode 100644
index 0000000000..e2945c910a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out
@@ -0,0 +1,229 @@
+GDTEST_OK
+TYPE_NIL
+true
+false
+false
+false
+true
+TYPE_BOOL
+false
+false
+true
+true
+true
+TYPE_INT
+false
+false
+true
+true
+true
+TYPE_FLOAT
+false
+false
+true
+true
+true
+TYPE_STRING
+false
+false
+true
+true
+true
+TYPE_VECTOR2
+false
+false
+true
+true
+true
+TYPE_VECTOR2I
+false
+false
+true
+true
+true
+TYPE_RECT2
+false
+false
+true
+true
+true
+TYPE_RECT2I
+false
+false
+true
+true
+true
+TYPE_VECTOR3
+false
+false
+true
+true
+true
+TYPE_VECTOR3I
+false
+false
+true
+true
+true
+TYPE_TRANSFORM2D
+true
+false
+false
+false
+true
+TYPE_VECTOR4
+false
+false
+true
+true
+true
+TYPE_VECTOR4I
+false
+false
+true
+true
+true
+TYPE_PLANE
+false
+false
+true
+true
+true
+TYPE_QUATERNION
+true
+false
+false
+false
+true
+TYPE_AABB
+false
+false
+true
+true
+true
+TYPE_BASIS
+true
+false
+false
+false
+true
+TYPE_TRANSFORM3D
+true
+false
+false
+false
+true
+TYPE_PROJECTION
+true
+false
+false
+false
+true
+TYPE_COLOR
+false
+false
+true
+true
+true
+TYPE_STRING_NAME
+false
+false
+true
+true
+true
+TYPE_NODE_PATH
+false
+false
+true
+true
+true
+TYPE_RID
+true
+false
+false
+false
+true
+TYPE_OBJECT
+false
+false
+true
+true
+true
+TYPE_CALLABLE
+false
+false
+true
+true
+true
+TYPE_SIGNAL
+false
+false
+true
+true
+true
+TYPE_DICTIONARY
+false
+false
+true
+true
+true
+TYPE_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_BYTE_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_INT32_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_INT64_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_FLOAT32_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_FLOAT64_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_STRING_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_VECTOR2_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_VECTOR3_ARRAY
+false
+false
+true
+true
+true
+TYPE_PACKED_COLOR_ARRAY
+false
+false
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd
new file mode 100644
index 0000000000..1aacd1d11c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd
@@ -0,0 +1,11 @@
+class TestOne:
+ func _get_property_list():
+ return {}
+
+class TestTwo extends TestOne:
+ func _init():
+ var _x = _get_property_list()
+
+func test():
+ var x = TestTwo.new()
+ var _x = x._get_property_list()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.gd b/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.gd
new file mode 100644
index 0000000000..c447003619
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.gd
@@ -0,0 +1,10 @@
+class TestOne:
+ func _init():
+ pass
+
+class TestTwo extends TestOne:
+ func _init():
+ super()
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.out b/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_super_implemented.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd
index 71a03fbc0d..f322783776 100644
--- a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd
@@ -1,3 +1,3 @@
func test():
# Number separators may not be placed right next to each other.
- var __ = 1__23
+ var _num = 1__23
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out
index 71a3c2fd6a..b308994ae2 100644
--- a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Only one underscore can be used as a numeric separator.
+Multiple underscores cannot be adjacent in a numeric literal.
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.gd b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.gd
new file mode 100644
index 0000000000..3140999aa9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.gd
@@ -0,0 +1,3 @@
+func test():
+ # Number separators may not be placed right next to each other.
+ var _num = 123.45__67
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.out b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.out
new file mode 100644
index 0000000000..b308994ae2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators_after_decimal.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Multiple underscores cannot be adjacent in a numeric literal.
diff --git a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd
new file mode 100644
index 0000000000..cf7fb1518c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd
@@ -0,0 +1,17 @@
+func test():
+ print(-9223372036854775808 == (1 << 63))
+ print(-2)
+ print(- 2)
+ print(---2)
+ print(3 - 2)
+ print(3-2)
+ print(3---2)
+ print(-3 - 2)
+ print(-3 - -2)
+ print(-(3 - 2)-2)
+ print([1, 2, 3][0]-1)
+ var t = 1
+ print(t-1)
+ print(-0xFF)
+ print(1--0xFF)
+ print(floor(PI-1))
diff --git a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out
new file mode 100644
index 0000000000..c5958365ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out
@@ -0,0 +1,16 @@
+GDTEST_OK
+true
+-2
+-2
+-2
+1
+1
+1
+-5
+-1
+-3
+0
+0
+-255
+256
+2
diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.gd b/modules/gdscript/tests/scripts/parser/features/number_separators.gd
index f5f5661cae..a534c4fde1 100644
--- a/modules/gdscript/tests/scripts/parser/features/number_separators.gd
+++ b/modules/gdscript/tests/scripts/parser/features/number_separators.gd
@@ -1,12 +1,26 @@
func test():
# `_` can be used as a separator for numbers in GDScript.
# It can be placed anywhere in the number, except at the beginning.
- # Currently, GDScript in the `master` branch only allows using one separator
- # per number.
- # Results are assigned to variables to avoid warnings.
- var __ = 1_23
- __ = 123_ # Trailing number separators are OK.
- __ = 12_3
- __ = 123_456
- __ = 0x1234_5678
- __ = 0b1001_0101
+ print(1_23)
+ print(12_3)
+ print(1_2_3)
+ print(123_) # Trailing number separators are OK.
+ print(123_456)
+ print(123_45_6_)
+ print("---")
+ print(0x1234_00ff)
+ print(0x1234_00_f_f_)
+ print(0b1001_0101)
+ print(0b1001_01_0_1_)
+ print("---")
+ print(-1_234.456_7)
+ print(-1_23_4_.4_56_7_)
+ print(-1_234.)
+ print(-1_23_4_.)
+ print(.456_7)
+ print(.4_56_7_)
+ print("---")
+ print(-1_234.5e000_3)
+ print(-1_23_4_.5e0_00_3_)
+ print(-1_234.5e+000_3)
+ print(-1_23_4_.5e+0_00_3_)
diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.out b/modules/gdscript/tests/scripts/parser/features/number_separators.out
index d73c5eb7cd..b0d2fd94fe 100644
--- a/modules/gdscript/tests/scripts/parser/features/number_separators.out
+++ b/modules/gdscript/tests/scripts/parser/features/number_separators.out
@@ -1 +1,24 @@
GDTEST_OK
+123
+123
+123
+123
+123456
+123456
+---
+305398015
+305398015
+149
+149
+---
+-1234.4567
+-1234.4567
+-1234
+-1234
+0.4567
+0.4567
+---
+-1234500
+-1234500
+-1234500
+-1234500
diff --git a/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.gd
new file mode 100644
index 0000000000..515efbc9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.gd
@@ -0,0 +1,10 @@
+# https://github.com/godotengine/godot/issues/70319
+
+class InnerClass:
+ pass
+
+func test():
+ var inner_ctor : Callable = InnerClass.new
+ print(inner_ctor)
+ var native_ctor : Callable = Node.new
+ print(native_ctor)
diff --git a/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.out
new file mode 100644
index 0000000000..527e3e8f84
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/ctor_as_callable.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+GDScript::new
+GDScriptNativeClass::new
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.gd b/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.gd
new file mode 100644
index 0000000000..77d01cf00c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.gd
@@ -0,0 +1,58 @@
+# GH-77098 p.4
+
+@static_unload
+
+class A:
+ class InnerClass:
+ pass
+
+ enum NamedEnum { VALUE = 111 }
+ enum { UNNAMED_ENUM_VALUE = 222 }
+ const CONSTANT = 333
+ static var static_var := 1
+
+ static func static_func() -> int:
+ return 444
+
+class B extends A:
+ func test_self():
+ print(self.InnerClass is GDScript)
+ print(self.NamedEnum)
+ print(self.NamedEnum.VALUE)
+ print(self.UNNAMED_ENUM_VALUE)
+ print(self.CONSTANT)
+ @warning_ignore("static_called_on_instance")
+ print(self.static_func())
+
+ prints("test_self before:", self.static_var)
+ self.static_var = 2
+ prints("test_self after:", self.static_var)
+
+func test():
+ var hard := B.new()
+ hard.test_self()
+
+ print(hard.InnerClass is GDScript)
+ print(hard.NamedEnum)
+ print(hard.NamedEnum.VALUE)
+ print(hard.UNNAMED_ENUM_VALUE)
+ print(hard.CONSTANT)
+ @warning_ignore("static_called_on_instance")
+ print(hard.static_func())
+
+ prints("hard before:", hard.static_var)
+ hard.static_var = 3
+ prints("hard after:", hard.static_var)
+
+ var weak: Variant = B.new()
+ print(weak.InnerClass is GDScript)
+ print(weak.NamedEnum)
+ print(weak.NamedEnum.VALUE)
+ print(weak.UNNAMED_ENUM_VALUE)
+ print(weak.CONSTANT)
+ @warning_ignore("unsafe_method_access")
+ print(weak.static_func())
+
+ prints("weak before:", weak.static_var)
+ weak.static_var = 4
+ prints("weak after:", weak.static_var)
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.out b/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.out
new file mode 100644
index 0000000000..7d7ad04df4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_access_via_instance.out
@@ -0,0 +1,25 @@
+GDTEST_OK
+true
+{ "VALUE": 111 }
+111
+222
+333
+444
+test_self before: 1
+test_self after: 2
+true
+{ "VALUE": 111 }
+111
+222
+333
+444
+hard before: 2
+hard after: 3
+true
+{ "VALUE": 111 }
+111
+222
+333
+444
+weak before: 3
+weak after: 4
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.gd
new file mode 100644
index 0000000000..65635daa36
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.gd
@@ -0,0 +1,17 @@
+# GH-41919
+
+class_name TestStaticFuncAsCallable
+
+class InnerClass:
+ static func inner_my_func():
+ print("inner_my_func")
+
+static func my_func():
+ print("my_func")
+
+var a: Callable = TestStaticFuncAsCallable.my_func
+var b: Callable = InnerClass.inner_my_func
+
+func test():
+ a.call()
+ b.call()
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.out
new file mode 100644
index 0000000000..360bb9f322
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_func_as_callable.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+my_func
+inner_my_func
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_variables.gd b/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
index e193312381..8da8bb7e53 100644
--- a/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
@@ -33,24 +33,24 @@ func test():
prints("perm:", perm)
prints("prop:", prop)
- print("other.perm:", StaticVariablesOther.perm)
- print("other.prop:", StaticVariablesOther.prop)
+ prints("other.perm:", StaticVariablesOther.perm)
+ prints("other.prop:", StaticVariablesOther.prop)
StaticVariablesOther.perm = 2
StaticVariablesOther.prop = "foo"
- print("other.perm:", StaticVariablesOther.perm)
- print("other.prop:", StaticVariablesOther.prop)
+ prints("other.perm:", StaticVariablesOther.perm)
+ prints("other.prop:", StaticVariablesOther.prop)
@warning_ignore("unsafe_method_access")
var path = get_script().get_path().get_base_dir()
- var other = load(path + "/static_variables_load.gd")
+ var other = load(path + "/static_variables_load.gd")
- print("load.perm:", other.perm)
- print("load.prop:", other.prop)
+ prints("load.perm:", other.perm)
+ prints("load.prop:", other.prop)
other.perm = 3
other.prop = "bar"
- print("load.perm:", other.perm)
- print("load.prop:", other.prop)
+ prints("load.perm:", other.perm)
+ prints("load.prop:", other.prop)
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_variables.out b/modules/gdscript/tests/scripts/runtime/features/static_variables.out
index d2491aef5e..650e1d9578 100644
--- a/modules/gdscript/tests/scripts/runtime/features/static_variables.out
+++ b/modules/gdscript/tests/scripts/runtime/features/static_variables.out
@@ -3,14 +3,14 @@ Inner._static_init inner
InnerInner._static_init inner inner
data: data
perm: 0
-prop: prefix Hello! suffix
+prop: Hello! suffix
perm: 1
prop: prefix World! suffix
-other.perm:0
-other.prop:prefix Hello! suffix
-other.perm:2
-other.prop:prefix foo suffix
-load.perm:0
-load.prop:prefix Hello! suffix
-load.perm:3
-load.prop:prefix bar suffix
+other.perm: 0
+other.prop: Hello! suffix
+other.perm: 2
+other.prop: prefix foo suffix
+load.perm: 0
+load.prop: Hello! suffix
+load.perm: 3
+load.prop: prefix bar suffix
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_variables_2.gd b/modules/gdscript/tests/scripts/runtime/features/static_variables_2.gd
new file mode 100644
index 0000000000..7a75d119ed
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_variables_2.gd
@@ -0,0 +1,56 @@
+@static_unload
+
+class A:
+ static var x: int = 1
+
+ static var y: int = 42:
+ set(_value):
+ print("The setter is NOT called on initialization.") # GH-77098 p.1
+
+ static func _static_init() -> void:
+ prints("A _static_init begin:", x)
+ x = -1
+ prints("A _static_init end:", x)
+
+ static func sf(p_x: int) -> void:
+ x = p_x
+ prints("sf:", x)
+
+ # GH-77331
+ func f(p_x: int) -> void:
+ x = p_x
+ prints("f:", x)
+
+class B extends A:
+ static func _static_init() -> void:
+ prints("B _static_init begin:", x)
+ x = -2
+ prints("B _static_init end:", x)
+
+ static func sg(p_x: int) -> void:
+ x = p_x
+ prints("sg:", x)
+
+ func g(p_x: int) -> void:
+ x = p_x
+ prints("g:", x)
+
+ func h(p_x: int) -> void:
+ print("h: call f(%d)" % p_x)
+ f(p_x)
+
+func test():
+ prints(A.x, B.x)
+ A.x = 1 # GH-77098 p.2
+ prints(A.x, B.x)
+ B.x = 2
+ prints(A.x, B.x)
+
+ A.sf(3)
+ B.sf(4)
+ B.sg(5)
+
+ var b := B.new()
+ b.f(6)
+ b.g(7)
+ b.h(8)
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_variables_2.out b/modules/gdscript/tests/scripts/runtime/features/static_variables_2.out
new file mode 100644
index 0000000000..b833911d95
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/static_variables_2.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+A _static_init begin: 1
+A _static_init end: -1
+B _static_init begin: -1
+B _static_init end: -2
+-2 -2
+1 1
+2 2
+sf: 3
+sf: 4
+sg: 5
+f: 6
+g: 7
+h: call f(8)
+f: 8
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index ad38312abe..0446a7aad6 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -30,6 +30,11 @@
#include "test_gdscript.h"
+#include "../gdscript_analyzer.h"
+#include "../gdscript_compiler.h"
+#include "../gdscript_parser.h"
+#include "../gdscript_tokenizer.h"
+
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/file_access_pack.h"
@@ -38,11 +43,6 @@
#include "core/string/string_builder.h"
#include "scene/resources/packed_scene.h"
-#include "modules/gdscript/gdscript_analyzer.h"
-#include "modules/gdscript/gdscript_compiler.h"
-#include "modules/gdscript/gdscript_parser.h"
-#include "modules/gdscript/gdscript_tokenizer.h"
-
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif
diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index d719e3d94a..b39dfe2b5a 100644
--- a/modules/gdscript/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -32,6 +32,7 @@
#define TEST_GDSCRIPT_H
#include "gdscript_test_runner.h"
+
#include "tests/test_macros.h"
namespace GDScriptTests {
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index f96d2c50b7..622910761d 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -30,10 +30,10 @@
#include "register_types.h"
-#include "servers/rendering/rendering_device.h"
-
#include "glslang_resource_limits.h"
+#include "servers/rendering/rendering_device.h"
+
#include <glslang/Include/Types.h>
#include <glslang/Public/ShaderLang.h>
#include <glslang/SPIRV/GlslangToSpv.h>
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index 36cf053aa1..f8de431fae 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -15,7 +15,6 @@ def get_doc_classes():
"GLTFAnimation",
"GLTFBufferView",
"GLTFCamera",
- "GLTFCollider",
"GLTFDocument",
"GLTFDocumentExtension",
"GLTFDocumentExtensionConvertImporterMesh",
@@ -23,6 +22,7 @@ def get_doc_classes():
"GLTFMesh",
"GLTFNode",
"GLTFPhysicsBody",
+ "GLTFPhysicsShape",
"GLTFSkeleton",
"GLTFSkin",
"GLTFSpecGloss",
diff --git a/modules/gltf/doc_classes/GLTFCollider.xml b/modules/gltf/doc_classes/GLTFCollider.xml
deleted file mode 100644
index cd397df398..0000000000
--- a/modules/gltf/doc_classes/GLTFCollider.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFCollider" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Represents a GLTF collider.
- </brief_description>
- <description>
- Represents a collider as defined by the [code]OMI_collider[/code] GLTF extension. This class is an intermediary between the GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future.
- </description>
- <tutorials>
- <link title="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider</link>
- </tutorials>
- <methods>
- <method name="from_dictionary" qualifiers="static">
- <return type="GLTFCollider" />
- <param index="0" name="dictionary" type="Dictionary" />
- <description>
- Creates a new GLTFCollider instance by parsing the given [Dictionary].
- </description>
- </method>
- <method name="from_node" qualifiers="static">
- <return type="GLTFCollider" />
- <param index="0" name="collider_node" type="CollisionShape3D" />
- <description>
- Create a new GLTFCollider instance from the given Godot [CollisionShape3D] node.
- </description>
- </method>
- <method name="to_dictionary" qualifiers="const">
- <return type="Dictionary" />
- <description>
- Serializes this GLTFCollider instance into a [Dictionary].
- </description>
- </method>
- <method name="to_node">
- <return type="CollisionShape3D" />
- <param index="0" name="cache_shapes" type="bool" default="false" />
- <description>
- Converts this GLTFCollider instance into a Godot [CollisionShape3D] node.
- </description>
- </method>
- </methods>
- <members>
- <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
- The height of the collider, in meters. This is only used when the collider type is "capsule" or "cylinder". This value should not be negative, and for "capsule" it should be at least twice the radius.
- </member>
- <member name="importer_mesh" type="ImporterMesh" setter="set_importer_mesh" getter="get_importer_mesh">
- The [ImporterMesh] resource of the collider. This is only used when the collider type is "hull" (convex hull) or "trimesh" (concave trimesh).
- </member>
- <member name="is_trigger" type="bool" setter="set_is_trigger" getter="get_is_trigger" default="false">
- If [code]true[/code], indicates that this collider is a trigger. For Godot, this means that the collider should be a child of an Area3D node.
- This is the only variable not used in the [method to_node] method, it's intended to be used alongside when deciding where to add the generated node as a child.
- </member>
- <member name="mesh_index" type="int" setter="set_mesh_index" getter="get_mesh_index" default="-1">
- The index of the collider's mesh in the GLTF file. This is only used when the collider type is "hull" (convex hull) or "trimesh" (concave trimesh).
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
- The radius of the collider, in meters. This is only used when the collider type is "capsule", "cylinder", or "sphere". This value should not be negative.
- </member>
- <member name="shape_type" type="String" setter="set_shape_type" getter="get_shape_type" default="&quot;&quot;">
- The type of shape this collider represents. Valid values are "box", "capsule", "cylinder", "sphere", "hull", and "trimesh".
- </member>
- <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(1, 1, 1)">
- The size of the collider, in meters. This is only used when the collider type is "box", and it represents the "diameter" of the box. This value should not be negative.
- </member>
- </members>
-</class>
diff --git a/modules/gltf/doc_classes/GLTFPhysicsShape.xml b/modules/gltf/doc_classes/GLTFPhysicsShape.xml
new file mode 100644
index 0000000000..4b673d6001
--- /dev/null
+++ b/modules/gltf/doc_classes/GLTFPhysicsShape.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFPhysicsShape" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Represents a GLTF physics shape.
+ </brief_description>
+ <description>
+ Represents a physics shape as defined by the [code]OMI_collider[/code] GLTF extension. This class is an intermediary between the GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future.
+ </description>
+ <tutorials>
+ <link title="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider</link>
+ </tutorials>
+ <methods>
+ <method name="from_dictionary" qualifiers="static">
+ <return type="GLTFPhysicsShape" />
+ <param index="0" name="dictionary" type="Dictionary" />
+ <description>
+ Creates a new GLTFPhysicsShape instance by parsing the given [Dictionary].
+ </description>
+ </method>
+ <method name="from_node" qualifiers="static">
+ <return type="GLTFPhysicsShape" />
+ <param index="0" name="shape_node" type="CollisionShape3D" />
+ <description>
+ Create a new GLTFPhysicsShape instance from the given Godot [CollisionShape3D] node.
+ </description>
+ </method>
+ <method name="to_dictionary" qualifiers="const">
+ <return type="Dictionary" />
+ <description>
+ Serializes this GLTFPhysicsShape instance into a [Dictionary].
+ </description>
+ </method>
+ <method name="to_node">
+ <return type="CollisionShape3D" />
+ <param index="0" name="cache_shapes" type="bool" default="false" />
+ <description>
+ Converts this GLTFPhysicsShape instance into a Godot [CollisionShape3D] node.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
+ The height of the shape, in meters. This is only used when the shape type is "capsule" or "cylinder". This value should not be negative, and for "capsule" it should be at least twice the radius.
+ </member>
+ <member name="importer_mesh" type="ImporterMesh" setter="set_importer_mesh" getter="get_importer_mesh">
+ The [ImporterMesh] resource of the shape. This is only used when the shape type is "hull" (convex hull) or "trimesh" (concave trimesh).
+ </member>
+ <member name="is_trigger" type="bool" setter="set_is_trigger" getter="get_is_trigger" default="false">
+ If [code]true[/code], indicates that this shape is a trigger. For Godot, this means that the shape should be a child of an Area3D node.
+ This is the only variable not used in the [method to_node] method, it's intended to be used alongside when deciding where to add the generated node as a child.
+ </member>
+ <member name="mesh_index" type="int" setter="set_mesh_index" getter="get_mesh_index" default="-1">
+ The index of the shape's mesh in the GLTF file. This is only used when the shape type is "hull" (convex hull) or "trimesh" (concave trimesh).
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
+ The radius of the shape, in meters. This is only used when the shape type is "capsule", "cylinder", or "sphere". This value should not be negative.
+ </member>
+ <member name="shape_type" type="String" setter="set_shape_type" getter="get_shape_type" default="&quot;&quot;">
+ The type of shape this shape represents. Valid values are "box", "capsule", "cylinder", "sphere", "hull", and "trimesh".
+ </member>
+ <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(1, 1, 1)">
+ The size of the shape, in meters. This is only used when the shape type is "box", and it represents the "diameter" of the box. This value should not be negative.
+ </member>
+ </members>
+</class>
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
index af870ed13c..83c7f463df 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef TOOLS_ENABLED
-
#include "editor_scene_exporter_gltf_plugin.h"
+#ifdef TOOLS_ENABLED
+
#include "../gltf_document.h"
#include "editor/editor_file_system.h"
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
index 0da010ec4b..f92b3c5180 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
@@ -33,9 +33,10 @@
#ifdef TOOLS_ENABLED
-#include "editor/editor_plugin.h"
#include "editor_scene_importer_gltf.h"
+#include "editor/editor_plugin.h"
+
class EditorFileDialog;
class SceneExporterGLTFPlugin : public EditorPlugin {
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index 5339275439..b63a938e64 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef TOOLS_ENABLED
-
#include "editor_scene_importer_gltf.h"
+#ifdef TOOLS_ENABLED
+
#include "../gltf_defines.h"
#include "../gltf_document.h"
diff --git a/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp b/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp
index e36a9fbb95..2ba5123c31 100644
--- a/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp
+++ b/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp
@@ -47,9 +47,9 @@ Error GLTFDocumentExtensionPhysics::import_preflight(Ref<GLTFState> p_state, Vec
if (state_collider_dicts.size() > 0) {
Array state_colliders;
for (int i = 0; i < state_collider_dicts.size(); i++) {
- state_colliders.push_back(GLTFCollider::from_dictionary(state_collider_dicts[i]));
+ state_colliders.push_back(GLTFPhysicsShape::from_dictionary(state_collider_dicts[i]));
}
- p_state->set_additional_data("GLTFColliders", state_colliders);
+ p_state->set_additional_data("GLTFPhysicsShapes", state_colliders);
}
}
}
@@ -70,11 +70,11 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
if (node_collider_ext.has("collider")) {
// "collider" is the index of the collider in the state colliders array.
int node_collider_index = node_collider_ext["collider"];
- Array state_colliders = p_state->get_additional_data("GLTFColliders");
+ Array state_colliders = p_state->get_additional_data("GLTFPhysicsShapes");
ERR_FAIL_INDEX_V_MSG(node_collider_index, state_colliders.size(), Error::ERR_FILE_CORRUPT, "GLTF Physics: On node " + p_gltf_node->get_name() + ", the collider index " + itos(node_collider_index) + " is not in the state colliders (size: " + itos(state_colliders.size()) + ").");
- p_gltf_node->set_additional_data(StringName("GLTFCollider"), state_colliders[node_collider_index]);
+ p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), state_colliders[node_collider_index]);
} else {
- p_gltf_node->set_additional_data(StringName("GLTFCollider"), GLTFCollider::from_dictionary(p_extensions["OMI_collider"]));
+ p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), GLTFPhysicsShape::from_dictionary(p_extensions["OMI_collider"]));
}
}
if (p_extensions.has("OMI_physics_body")) {
@@ -83,7 +83,7 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
return OK;
}
-void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref<GLTFCollider> p_collider) {
+void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref<GLTFPhysicsShape> p_collider) {
GLTFMeshIndex collider_mesh_index = p_collider->get_mesh_index();
if (collider_mesh_index == -1) {
return; // No mesh for this collider.
@@ -101,7 +101,7 @@ void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state,
p_collider->set_importer_mesh(importer_mesh);
}
-CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Ref<GLTFCollider> p_collider, Ref<GLTFPhysicsBody> p_physics_body) {
+CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Ref<GLTFPhysicsShape> p_collider, Ref<GLTFPhysicsBody> p_physics_body) {
print_verbose("glTF: Creating collision for: " + p_gltf_node->get_name());
bool is_trigger = p_collider->get_is_trigger();
// This method is used for the case where we must generate a parent body.
@@ -134,7 +134,7 @@ CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLT
Node3D *GLTFDocumentExtensionPhysics::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
Ref<GLTFPhysicsBody> physics_body = p_gltf_node->get_additional_data(StringName("GLTFPhysicsBody"));
- Ref<GLTFCollider> collider = p_gltf_node->get_additional_data(StringName("GLTFCollider"));
+ Ref<GLTFPhysicsShape> collider = p_gltf_node->get_additional_data(StringName("GLTFPhysicsShape"));
if (collider.is_valid()) {
_setup_collider_mesh_resource_from_index_if_needed(p_state, collider);
// If the collider has the correct type of parent, we just return one node.
@@ -203,14 +203,14 @@ GLTFMeshIndex _get_or_insert_mesh_in_state(Ref<GLTFState> p_state, Ref<ImporterM
void GLTFDocumentExtensionPhysics::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) {
if (cast_to<CollisionShape3D>(p_scene_node)) {
CollisionShape3D *shape = Object::cast_to<CollisionShape3D>(p_scene_node);
- Ref<GLTFCollider> collider = GLTFCollider::from_node(shape);
+ Ref<GLTFPhysicsShape> collider = GLTFPhysicsShape::from_node(shape);
{
Ref<ImporterMesh> importer_mesh = collider->get_importer_mesh();
if (importer_mesh.is_valid()) {
collider->set_mesh_index(_get_or_insert_mesh_in_state(p_state, importer_mesh));
}
}
- p_gltf_node->set_additional_data(StringName("GLTFCollider"), collider);
+ p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), collider);
} else if (cast_to<CollisionObject3D>(p_scene_node)) {
CollisionObject3D *body = Object::cast_to<CollisionObject3D>(p_scene_node);
p_gltf_node->set_additional_data(StringName("GLTFPhysicsBody"), GLTFPhysicsBody::from_node(body));
@@ -248,7 +248,7 @@ Error GLTFDocumentExtensionPhysics::export_node(Ref<GLTFState> p_state, Ref<GLTF
node_extensions["OMI_physics_body"] = physics_body->to_dictionary();
p_state->add_used_extension("OMI_physics_body");
}
- Ref<GLTFCollider> collider = p_gltf_node->get_additional_data(StringName("GLTFCollider"));
+ Ref<GLTFPhysicsShape> collider = p_gltf_node->get_additional_data(StringName("GLTFPhysicsShape"));
if (collider.is_valid()) {
Array state_colliders = _get_or_create_state_colliders_in_state(p_state);
int size = state_colliders.size();
diff --git a/modules/gltf/extensions/physics/gltf_document_extension_physics.h b/modules/gltf/extensions/physics/gltf_document_extension_physics.h
index 5c4e739dba..3d5027c0df 100644
--- a/modules/gltf/extensions/physics/gltf_document_extension_physics.h
+++ b/modules/gltf/extensions/physics/gltf_document_extension_physics.h
@@ -32,9 +32,8 @@
#define GLTF_DOCUMENT_EXTENSION_PHYSICS_H
#include "../gltf_document_extension.h"
-
-#include "gltf_collider.h"
#include "gltf_physics_body.h"
+#include "gltf_physics_shape.h"
class GLTFDocumentExtensionPhysics : public GLTFDocumentExtension {
GDCLASS(GLTFDocumentExtensionPhysics, GLTFDocumentExtension);
diff --git a/modules/gltf/extensions/physics/gltf_collider.cpp b/modules/gltf/extensions/physics/gltf_physics_shape.cpp
index 1a42a84874..d3c56c0da9 100644
--- a/modules/gltf/extensions/physics/gltf_collider.cpp
+++ b/modules/gltf/extensions/physics/gltf_physics_shape.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gltf_collider.cpp */
+/* gltf_physics_shape.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "gltf_collider.h"
+#include "gltf_physics_shape.h"
#include "../../gltf_state.h"
+
#include "core/math/convex_hull.h"
#include "scene/3d/area_3d.h"
#include "scene/resources/box_shape_3d.h"
@@ -41,27 +42,27 @@
#include "scene/resources/importer_mesh.h"
#include "scene/resources/sphere_shape_3d.h"
-void GLTFCollider::_bind_methods() {
- ClassDB::bind_static_method("GLTFCollider", D_METHOD("from_node", "collider_node"), &GLTFCollider::from_node);
- ClassDB::bind_method(D_METHOD("to_node", "cache_shapes"), &GLTFCollider::to_node, DEFVAL(false));
+void GLTFPhysicsShape::_bind_methods() {
+ ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_node", "shape_node"), &GLTFPhysicsShape::from_node);
+ ClassDB::bind_method(D_METHOD("to_node", "cache_shapes"), &GLTFPhysicsShape::to_node, DEFVAL(false));
- ClassDB::bind_static_method("GLTFCollider", D_METHOD("from_dictionary", "dictionary"), &GLTFCollider::from_dictionary);
- ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFCollider::to_dictionary);
+ ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_dictionary", "dictionary"), &GLTFPhysicsShape::from_dictionary);
+ ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFPhysicsShape::to_dictionary);
- ClassDB::bind_method(D_METHOD("get_shape_type"), &GLTFCollider::get_shape_type);
- ClassDB::bind_method(D_METHOD("set_shape_type", "shape_type"), &GLTFCollider::set_shape_type);
- ClassDB::bind_method(D_METHOD("get_size"), &GLTFCollider::get_size);
- ClassDB::bind_method(D_METHOD("set_size", "size"), &GLTFCollider::set_size);
- ClassDB::bind_method(D_METHOD("get_radius"), &GLTFCollider::get_radius);
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GLTFCollider::set_radius);
- ClassDB::bind_method(D_METHOD("get_height"), &GLTFCollider::get_height);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &GLTFCollider::set_height);
- ClassDB::bind_method(D_METHOD("get_is_trigger"), &GLTFCollider::get_is_trigger);
- ClassDB::bind_method(D_METHOD("set_is_trigger", "is_trigger"), &GLTFCollider::set_is_trigger);
- ClassDB::bind_method(D_METHOD("get_mesh_index"), &GLTFCollider::get_mesh_index);
- ClassDB::bind_method(D_METHOD("set_mesh_index", "mesh_index"), &GLTFCollider::set_mesh_index);
- ClassDB::bind_method(D_METHOD("get_importer_mesh"), &GLTFCollider::get_importer_mesh);
- ClassDB::bind_method(D_METHOD("set_importer_mesh", "importer_mesh"), &GLTFCollider::set_importer_mesh);
+ ClassDB::bind_method(D_METHOD("get_shape_type"), &GLTFPhysicsShape::get_shape_type);
+ ClassDB::bind_method(D_METHOD("set_shape_type", "shape_type"), &GLTFPhysicsShape::set_shape_type);
+ ClassDB::bind_method(D_METHOD("get_size"), &GLTFPhysicsShape::get_size);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GLTFPhysicsShape::set_size);
+ ClassDB::bind_method(D_METHOD("get_radius"), &GLTFPhysicsShape::get_radius);
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GLTFPhysicsShape::set_radius);
+ ClassDB::bind_method(D_METHOD("get_height"), &GLTFPhysicsShape::get_height);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &GLTFPhysicsShape::set_height);
+ ClassDB::bind_method(D_METHOD("get_is_trigger"), &GLTFPhysicsShape::get_is_trigger);
+ ClassDB::bind_method(D_METHOD("set_is_trigger", "is_trigger"), &GLTFPhysicsShape::set_is_trigger);
+ ClassDB::bind_method(D_METHOD("get_mesh_index"), &GLTFPhysicsShape::get_mesh_index);
+ ClassDB::bind_method(D_METHOD("set_mesh_index", "mesh_index"), &GLTFPhysicsShape::set_mesh_index);
+ ClassDB::bind_method(D_METHOD("get_importer_mesh"), &GLTFPhysicsShape::get_importer_mesh);
+ ClassDB::bind_method(D_METHOD("set_importer_mesh", "importer_mesh"), &GLTFPhysicsShape::set_importer_mesh);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "shape_type"), "set_shape_type", "get_shape_type");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
@@ -72,104 +73,104 @@ void GLTFCollider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "importer_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ImporterMesh"), "set_importer_mesh", "get_importer_mesh");
}
-String GLTFCollider::get_shape_type() const {
+String GLTFPhysicsShape::get_shape_type() const {
return shape_type;
}
-void GLTFCollider::set_shape_type(String p_shape_type) {
+void GLTFPhysicsShape::set_shape_type(String p_shape_type) {
shape_type = p_shape_type;
}
-Vector3 GLTFCollider::get_size() const {
+Vector3 GLTFPhysicsShape::get_size() const {
return size;
}
-void GLTFCollider::set_size(Vector3 p_size) {
+void GLTFPhysicsShape::set_size(Vector3 p_size) {
size = p_size;
}
-real_t GLTFCollider::get_radius() const {
+real_t GLTFPhysicsShape::get_radius() const {
return radius;
}
-void GLTFCollider::set_radius(real_t p_radius) {
+void GLTFPhysicsShape::set_radius(real_t p_radius) {
radius = p_radius;
}
-real_t GLTFCollider::get_height() const {
+real_t GLTFPhysicsShape::get_height() const {
return height;
}
-void GLTFCollider::set_height(real_t p_height) {
+void GLTFPhysicsShape::set_height(real_t p_height) {
height = p_height;
}
-bool GLTFCollider::get_is_trigger() const {
+bool GLTFPhysicsShape::get_is_trigger() const {
return is_trigger;
}
-void GLTFCollider::set_is_trigger(bool p_is_trigger) {
+void GLTFPhysicsShape::set_is_trigger(bool p_is_trigger) {
is_trigger = p_is_trigger;
}
-GLTFMeshIndex GLTFCollider::get_mesh_index() const {
+GLTFMeshIndex GLTFPhysicsShape::get_mesh_index() const {
return mesh_index;
}
-void GLTFCollider::set_mesh_index(GLTFMeshIndex p_mesh_index) {
+void GLTFPhysicsShape::set_mesh_index(GLTFMeshIndex p_mesh_index) {
mesh_index = p_mesh_index;
}
-Ref<ImporterMesh> GLTFCollider::get_importer_mesh() const {
+Ref<ImporterMesh> GLTFPhysicsShape::get_importer_mesh() const {
return importer_mesh;
}
-void GLTFCollider::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) {
+void GLTFPhysicsShape::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) {
importer_mesh = p_importer_mesh;
}
-Ref<GLTFCollider> GLTFCollider::from_node(const CollisionShape3D *p_collider_node) {
- Ref<GLTFCollider> collider;
- collider.instantiate();
- ERR_FAIL_NULL_V_MSG(p_collider_node, collider, "Tried to create a GLTFCollider from a CollisionShape3D node, but the given node was null.");
+Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_collider_node) {
+ Ref<GLTFPhysicsShape> gltf_shape;
+ gltf_shape.instantiate();
+ ERR_FAIL_NULL_V_MSG(p_collider_node, gltf_shape, "Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node was null.");
Node *parent = p_collider_node->get_parent();
if (cast_to<const Area3D>(parent)) {
- collider->set_is_trigger(true);
+ gltf_shape->set_is_trigger(true);
}
// All the code for working with the shape is below this comment.
- Ref<Shape3D> shape = p_collider_node->get_shape();
- ERR_FAIL_COND_V_MSG(shape.is_null(), collider, "Tried to create a GLTFCollider from a CollisionShape3D node, but the given node had a null shape.");
- collider->_shape_cache = shape;
- if (cast_to<BoxShape3D>(shape.ptr())) {
- collider->shape_type = "box";
- Ref<BoxShape3D> box = shape;
- collider->set_size(box->get_size());
- } else if (cast_to<const CapsuleShape3D>(shape.ptr())) {
- collider->shape_type = "capsule";
- Ref<CapsuleShape3D> capsule = shape;
- collider->set_radius(capsule->get_radius());
- collider->set_height(capsule->get_height());
- } else if (cast_to<const CylinderShape3D>(shape.ptr())) {
- collider->shape_type = "cylinder";
- Ref<CylinderShape3D> cylinder = shape;
- collider->set_radius(cylinder->get_radius());
- collider->set_height(cylinder->get_height());
- } else if (cast_to<const SphereShape3D>(shape.ptr())) {
- collider->shape_type = "sphere";
- Ref<SphereShape3D> sphere = shape;
- collider->set_radius(sphere->get_radius());
- } else if (cast_to<const ConvexPolygonShape3D>(shape.ptr())) {
- collider->shape_type = "hull";
- Ref<ConvexPolygonShape3D> convex = shape;
+ Ref<Shape3D> shape_resource = p_collider_node->get_shape();
+ ERR_FAIL_COND_V_MSG(shape_resource.is_null(), gltf_shape, "Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node had a null shape.");
+ gltf_shape->_shape_cache = shape_resource;
+ if (cast_to<BoxShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "box";
+ Ref<BoxShape3D> box = shape_resource;
+ gltf_shape->set_size(box->get_size());
+ } else if (cast_to<const CapsuleShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "capsule";
+ Ref<CapsuleShape3D> capsule = shape_resource;
+ gltf_shape->set_radius(capsule->get_radius());
+ gltf_shape->set_height(capsule->get_height());
+ } else if (cast_to<const CylinderShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "cylinder";
+ Ref<CylinderShape3D> cylinder = shape_resource;
+ gltf_shape->set_radius(cylinder->get_radius());
+ gltf_shape->set_height(cylinder->get_height());
+ } else if (cast_to<const SphereShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "sphere";
+ Ref<SphereShape3D> sphere = shape_resource;
+ gltf_shape->set_radius(sphere->get_radius());
+ } else if (cast_to<const ConvexPolygonShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "hull";
+ Ref<ConvexPolygonShape3D> convex = shape_resource;
Vector<Vector3> hull_points = convex->get_points();
- ERR_FAIL_COND_V_MSG(hull_points.size() < 3, collider, "GLTFCollider: Convex hull has fewer points (" + itos(hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to GLTF, since it uses a mesh to represent convex hulls.");
+ ERR_FAIL_COND_V_MSG(hull_points.size() < 3, gltf_shape, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to GLTF, since it uses a mesh to represent convex hulls.");
if (hull_points.size() > 255) {
- WARN_PRINT("GLTFCollider: Convex hull has more points (" + itos(hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines.");
+ WARN_PRINT("GLTFPhysicsShape: Convex hull has more points (" + itos(hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines.");
}
// Convert the convex hull points into an array of faces.
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(hull_points, md);
- ERR_FAIL_COND_V_MSG(err != OK, collider, "GLTFCollider: Failed to compute convex hull.");
+ ERR_FAIL_COND_V_MSG(err != OK, gltf_shape, "GLTFPhysicsShape: Failed to compute convex hull.");
Vector<Vector3> face_vertices;
for (uint32_t i = 0; i < md.faces.size(); i++) {
uint32_t index_count = md.faces[i].indices.size();
@@ -186,26 +187,26 @@ Ref<GLTFCollider> GLTFCollider::from_node(const CollisionShape3D *p_collider_nod
surface_array.resize(Mesh::ArrayType::ARRAY_MAX);
surface_array[Mesh::ArrayType::ARRAY_VERTEX] = face_vertices;
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
- collider->set_importer_mesh(importer_mesh);
- } else if (cast_to<const ConcavePolygonShape3D>(shape.ptr())) {
- collider->shape_type = "trimesh";
- Ref<ConcavePolygonShape3D> concave = shape;
+ gltf_shape->set_importer_mesh(importer_mesh);
+ } else if (cast_to<const ConcavePolygonShape3D>(shape_resource.ptr())) {
+ gltf_shape->shape_type = "trimesh";
+ Ref<ConcavePolygonShape3D> concave = shape_resource;
Ref<ImporterMesh> importer_mesh;
importer_mesh.instantiate();
Array surface_array;
surface_array.resize(Mesh::ArrayType::ARRAY_MAX);
surface_array[Mesh::ArrayType::ARRAY_VERTEX] = concave->get_faces();
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
- collider->set_importer_mesh(importer_mesh);
+ gltf_shape->set_importer_mesh(importer_mesh);
} else {
- ERR_PRINT("Tried to create a GLTFCollider from a CollisionShape3D node, but the given node's shape '" + String(Variant(shape)) +
+ ERR_PRINT("Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node's shape '" + String(Variant(shape_resource)) +
"' had an unsupported shape type. Only BoxShape3D, CapsuleShape3D, CylinderShape3D, SphereShape3D, ConcavePolygonShape3D, and ConvexPolygonShape3D are supported.");
}
- return collider;
+ return gltf_shape;
}
-CollisionShape3D *GLTFCollider::to_node(bool p_cache_shapes) {
- CollisionShape3D *collider = memnew(CollisionShape3D);
+CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
+ CollisionShape3D *gltf_shape = memnew(CollisionShape3D);
if (!p_cache_shapes || _shape_cache == nullptr) {
if (shape_type == "box") {
Ref<BoxShape3D> box;
@@ -230,57 +231,57 @@ CollisionShape3D *GLTFCollider::to_node(bool p_cache_shapes) {
sphere->set_radius(radius);
_shape_cache = sphere;
} else if (shape_type == "hull") {
- ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), collider, "GLTFCollider: Error converting convex hull collider to a node: The mesh resource is null.");
+ ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Error converting convex hull shape to a node: The mesh resource is null.");
Ref<ConvexPolygonShape3D> convex = importer_mesh->get_mesh()->create_convex_shape();
_shape_cache = convex;
} else if (shape_type == "trimesh") {
- ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), collider, "GLTFCollider: Error converting concave mesh collider to a node: The mesh resource is null.");
+ ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Error converting concave mesh shape to a node: The mesh resource is null.");
Ref<ConcavePolygonShape3D> concave = importer_mesh->create_trimesh_shape();
_shape_cache = concave;
} else {
- ERR_PRINT("GLTFCollider: Error converting to a node: Shape type '" + shape_type + "' is unknown.");
+ ERR_PRINT("GLTFPhysicsShape: Error converting to a node: Shape type '" + shape_type + "' is unknown.");
}
}
- collider->set_shape(_shape_cache);
- return collider;
+ gltf_shape->set_shape(_shape_cache);
+ return gltf_shape;
}
-Ref<GLTFCollider> GLTFCollider::from_dictionary(const Dictionary p_dictionary) {
- ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCollider>(), "Failed to parse GLTF collider, missing required field 'type'.");
- Ref<GLTFCollider> collider;
- collider.instantiate();
+Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_dictionary(const Dictionary p_dictionary) {
+ ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFPhysicsShape>(), "Failed to parse GLTFPhysicsShape, missing required field 'type'.");
+ Ref<GLTFPhysicsShape> gltf_shape;
+ gltf_shape.instantiate();
const String &shape_type = p_dictionary["type"];
- collider->shape_type = shape_type;
+ gltf_shape->shape_type = shape_type;
if (shape_type != "box" && shape_type != "capsule" && shape_type != "cylinder" && shape_type != "sphere" && shape_type != "hull" && shape_type != "trimesh") {
- ERR_PRINT("Error parsing GLTF collider: Shape type '" + shape_type + "' is unknown. Only box, capsule, cylinder, sphere, hull, and trimesh are supported.");
+ ERR_PRINT("GLTFPhysicsShape: Error parsing unknown shape type '" + shape_type + "'. Only box, capsule, cylinder, sphere, hull, and trimesh are supported.");
}
if (p_dictionary.has("radius")) {
- collider->set_radius(p_dictionary["radius"]);
+ gltf_shape->set_radius(p_dictionary["radius"]);
}
if (p_dictionary.has("height")) {
- collider->set_height(p_dictionary["height"]);
+ gltf_shape->set_height(p_dictionary["height"]);
}
if (p_dictionary.has("size")) {
const Array &arr = p_dictionary["size"];
if (arr.size() == 3) {
- collider->set_size(Vector3(arr[0], arr[1], arr[2]));
+ gltf_shape->set_size(Vector3(arr[0], arr[1], arr[2]));
} else {
- ERR_PRINT("Error parsing GLTF collider: The size must have exactly 3 numbers.");
+ ERR_PRINT("GLTFPhysicsShape: Error parsing the size, it must have exactly 3 numbers.");
}
}
if (p_dictionary.has("isTrigger")) {
- collider->set_is_trigger(p_dictionary["isTrigger"]);
+ gltf_shape->set_is_trigger(p_dictionary["isTrigger"]);
}
if (p_dictionary.has("mesh")) {
- collider->set_mesh_index(p_dictionary["mesh"]);
+ gltf_shape->set_mesh_index(p_dictionary["mesh"]);
}
- if (unlikely(collider->get_mesh_index() < 0 && (shape_type == "hull" || shape_type == "trimesh"))) {
- ERR_PRINT("Error parsing GLTF collider: The mesh-based shape type '" + shape_type + "' does not have a valid mesh index.");
+ if (unlikely(gltf_shape->get_mesh_index() < 0 && (shape_type == "hull" || shape_type == "trimesh"))) {
+ ERR_PRINT("Error parsing GLTFPhysicsShape: The mesh-based shape type '" + shape_type + "' does not have a valid mesh index.");
}
- return collider;
+ return gltf_shape;
}
-Dictionary GLTFCollider::to_dictionary() const {
+Dictionary GLTFPhysicsShape::to_dictionary() const {
Dictionary d;
d["type"] = shape_type;
if (shape_type == "box") {
diff --git a/modules/gltf/extensions/physics/gltf_collider.h b/modules/gltf/extensions/physics/gltf_physics_shape.h
index 94c7011618..efecf27e1b 100644
--- a/modules/gltf/extensions/physics/gltf_collider.h
+++ b/modules/gltf/extensions/physics/gltf_physics_shape.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gltf_collider.h */
+/* gltf_physics_shape.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef GLTF_COLLIDER_H
-#define GLTF_COLLIDER_H
+#ifndef GLTF_PHYSICS_SHAPE_H
+#define GLTF_PHYSICS_SHAPE_H
#include "../../gltf_defines.h"
+
#include "scene/3d/collision_shape_3d.h"
class ImporterMesh;
-// GLTFCollider is an intermediary between OMI_collider and Godot's collision shape nodes.
+// GLTFPhysicsShape is an intermediary between OMI_collider and Godot's collision shape nodes.
// https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider
-class GLTFCollider : public Resource {
- GDCLASS(GLTFCollider, Resource)
+class GLTFPhysicsShape : public Resource {
+ GDCLASS(GLTFPhysicsShape, Resource)
protected:
static void _bind_methods();
@@ -78,11 +79,11 @@ public:
Ref<ImporterMesh> get_importer_mesh() const;
void set_importer_mesh(Ref<ImporterMesh> p_importer_mesh);
- static Ref<GLTFCollider> from_node(const CollisionShape3D *p_collider_node);
+ static Ref<GLTFPhysicsShape> from_node(const CollisionShape3D *p_shape_node);
CollisionShape3D *to_node(bool p_cache_shapes = false);
- static Ref<GLTFCollider> from_dictionary(const Dictionary p_dictionary);
+ static Ref<GLTFPhysicsShape> from_dictionary(const Dictionary p_dictionary);
Dictionary to_dictionary() const;
};
-#endif // GLTF_COLLIDER_H
+#endif // GLTF_PHYSICS_SHAPE_H
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 42e3476ff3..87149fa11d 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -37,13 +37,14 @@
#include "gltf_document.h"
#ifdef TOOLS_ENABLED
-#include "core/config/project_settings.h"
#include "editor/editor_import_blend_runner.h"
-#include "editor/editor_node.h"
#include "editor/editor_scene_exporter_gltf_plugin.h"
#include "editor/editor_scene_importer_blend.h"
#include "editor/editor_scene_importer_fbx.h"
#include "editor/editor_scene_importer_gltf.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
static void _editor_init() {
@@ -116,7 +117,6 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(GLTFAnimation);
GDREGISTER_CLASS(GLTFBufferView);
GDREGISTER_CLASS(GLTFCamera);
- GDREGISTER_CLASS(GLTFCollider);
GDREGISTER_CLASS(GLTFDocument);
GDREGISTER_CLASS(GLTFDocumentExtension);
GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
@@ -124,6 +124,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(GLTFMesh);
GDREGISTER_CLASS(GLTFNode);
GDREGISTER_CLASS(GLTFPhysicsBody);
+ GDREGISTER_CLASS(GLTFPhysicsShape);
GDREGISTER_CLASS(GLTFSkeleton);
GDREGISTER_CLASS(GLTFSkin);
GDREGISTER_CLASS(GLTFSpecGloss);
diff --git a/modules/gltf/structures/gltf_accessor.h b/modules/gltf/structures/gltf_accessor.h
index 1a5a910048..6b1734601a 100644
--- a/modules/gltf/structures/gltf_accessor.h
+++ b/modules/gltf/structures/gltf_accessor.h
@@ -32,6 +32,7 @@
#define GLTF_ACCESSOR_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
struct GLTFAccessor : public Resource {
diff --git a/modules/gltf/structures/gltf_buffer_view.h b/modules/gltf/structures/gltf_buffer_view.h
index 93626a182b..6d138dbf11 100644
--- a/modules/gltf/structures/gltf_buffer_view.h
+++ b/modules/gltf/structures/gltf_buffer_view.h
@@ -32,6 +32,7 @@
#define GLTF_BUFFER_VIEW_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
class GLTFBufferView : public Resource {
diff --git a/modules/gltf/structures/gltf_mesh.h b/modules/gltf/structures/gltf_mesh.h
index 1e14c1ac7f..639f28980e 100644
--- a/modules/gltf/structures/gltf_mesh.h
+++ b/modules/gltf/structures/gltf_mesh.h
@@ -32,6 +32,7 @@
#define GLTF_MESH_H
#include "../gltf_defines.h"
+
#include "scene/resources/importer_mesh.h"
class GLTFMesh : public Resource {
diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h
index 95c80861de..c2d2f64495 100644
--- a/modules/gltf/structures/gltf_node.h
+++ b/modules/gltf/structures/gltf_node.h
@@ -32,6 +32,7 @@
#define GLTF_NODE_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
class GLTFNode : public Resource {
diff --git a/modules/gltf/structures/gltf_skeleton.cpp b/modules/gltf/structures/gltf_skeleton.cpp
index d7a7315062..b18aa759a5 100644
--- a/modules/gltf/structures/gltf_skeleton.cpp
+++ b/modules/gltf/structures/gltf_skeleton.cpp
@@ -31,6 +31,7 @@
#include "gltf_skeleton.h"
#include "../gltf_template_convert.h"
+
#include "scene/3d/bone_attachment_3d.h"
void GLTFSkeleton::_bind_methods() {
diff --git a/modules/gltf/structures/gltf_skeleton.h b/modules/gltf/structures/gltf_skeleton.h
index 044d67d299..72a4a06e5c 100644
--- a/modules/gltf/structures/gltf_skeleton.h
+++ b/modules/gltf/structures/gltf_skeleton.h
@@ -32,6 +32,7 @@
#define GLTF_SKELETON_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
class GLTFSkeleton : public Resource {
diff --git a/modules/gltf/structures/gltf_skin.cpp b/modules/gltf/structures/gltf_skin.cpp
index f0fb71c75d..2827bc3e78 100644
--- a/modules/gltf/structures/gltf_skin.cpp
+++ b/modules/gltf/structures/gltf_skin.cpp
@@ -31,6 +31,7 @@
#include "gltf_skin.h"
#include "../gltf_template_convert.h"
+
#include "core/variant/typed_array.h"
#include "scene/resources/skin.h"
diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h
index c943c42083..164cabfe12 100644
--- a/modules/gltf/structures/gltf_skin.h
+++ b/modules/gltf/structures/gltf_skin.h
@@ -32,6 +32,7 @@
#define GLTF_SKIN_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
template <typename T>
diff --git a/modules/gltf/structures/gltf_texture.h b/modules/gltf/structures/gltf_texture.h
index a9e19e65ea..03d07b3b56 100644
--- a/modules/gltf/structures/gltf_texture.h
+++ b/modules/gltf/structures/gltf_texture.h
@@ -32,6 +32,7 @@
#define GLTF_TEXTURE_H
#include "../gltf_defines.h"
+
#include "core/io/resource.h"
class GLTFTexture : public Resource {
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index 6fedcd9c99..fd9daa7c29 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -34,6 +34,7 @@
#ifdef TOOLS_ENABLED
#include "../grid_map.h"
+
#include "editor/editor_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/gui/item_list.h"
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index bc486bbdc2..76d24310e9 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -32,13 +32,14 @@
#include "register_types.h"
-#include "core/object/class_db.h"
#include "grid_map.h"
#ifdef TOOLS_ENABLED
#include "editor/grid_map_editor_plugin.h"
#endif
+#include "core/object/class_db.h"
+
void initialize_gridmap_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
GDREGISTER_CLASS(GridMap);
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index c6a1ca6630..0b9fcf4455 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -35,6 +35,7 @@
#include <jpgd.h>
#include <jpge.h>
+
#include <string.h>
Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) {
diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp
index 2a0457d5a3..d3a7cdaf27 100644
--- a/modules/jsonrpc/register_types.cpp
+++ b/modules/jsonrpc/register_types.cpp
@@ -29,9 +29,11 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/object/class_db.h"
+
#include "jsonrpc.h"
+#include "core/object/class_db.h"
+
void initialize_jsonrpc_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index bcb32d77c3..748e8ae50c 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -30,11 +30,12 @@
#include "lightmapper_rd.h"
-#include "core/config/project_settings.h"
-#include "core/math/geometry_2d.h"
#include "lm_blendseams.glsl.gen.h"
#include "lm_compute.glsl.gen.h"
#include "lm_raster.glsl.gen.h"
+
+#include "core/config/project_settings.h"
+#include "core/math/geometry_2d.h"
#include "servers/rendering/rendering_device_binds.h"
//uncomment this if you want to see textures from all the process saved
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index af89aa167c..7ec4a40766 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -30,8 +30,9 @@
#include "register_types.h"
-#include "core/config/project_settings.h"
#include "lightmapper_rd.h"
+
+#include "core/config/project_settings.h"
#include "scene/3d/lightmapper.h"
#ifndef _3D_DISABLED
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index 68b213d79e..50a6909d1a 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -30,25 +30,25 @@
#include "crypto_mbedtls.h"
-#include "core/io/file_access.h"
-
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif
-#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
-#define PEM_END_CRT "-----END CERTIFICATE-----\n"
-#define PEM_MIN_SIZE 54
#include <mbedtls/debug.h>
#include <mbedtls/md.h>
#include <mbedtls/pem.h>
+#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
+#define PEM_END_CRT "-----END CERTIFICATE-----\n"
+#define PEM_MIN_SIZE 54
+
CryptoKey *CryptoKeyMbedTLS::create() {
return memnew(CryptoKeyMbedTLS);
}
diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp
index 62513929ea..e466fe15d6 100644
--- a/modules/mbedtls/dtls_server_mbedtls.cpp
+++ b/modules/mbedtls/dtls_server_mbedtls.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "dtls_server_mbedtls.h"
+
#include "packet_peer_mbed_dtls.h"
Error DTLSServerMbedTLS::setup(Ref<TLSOptions> p_options) {
diff --git a/modules/mbedtls/dtls_server_mbedtls.h b/modules/mbedtls/dtls_server_mbedtls.h
index d5841a45fa..59befecf43 100644
--- a/modules/mbedtls/dtls_server_mbedtls.h
+++ b/modules/mbedtls/dtls_server_mbedtls.h
@@ -31,9 +31,10 @@
#ifndef DTLS_SERVER_MBEDTLS_H
#define DTLS_SERVER_MBEDTLS_H
-#include "core/io/dtls_server.h"
#include "tls_context_mbedtls.h"
+#include "core/io/dtls_server.h"
+
class DTLSServerMbedTLS : public DTLSServer {
private:
static DTLSServer *_create_func();
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h
index 05decec783..2cff7a3589 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.h
+++ b/modules/mbedtls/packet_peer_mbed_dtls.h
@@ -31,9 +31,10 @@
#ifndef PACKET_PEER_MBED_DTLS_H
#define PACKET_PEER_MBED_DTLS_H
-#include "core/io/packet_peer_dtls.h"
#include "tls_context_mbedtls.h"
+#include "core/io/packet_peer_dtls.h"
+
#include <mbedtls/timing.h>
class PacketPeerMbedDTLS : public PacketPeerDTLS {
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index ec0446c380..a8080f0960 100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -31,9 +31,10 @@
#ifndef STREAM_PEER_MBEDTLS_H
#define STREAM_PEER_MBEDTLS_H
-#include "core/io/stream_peer_tls.h"
#include "tls_context_mbedtls.h"
+#include "core/io/stream_peer_tls.h"
+
class StreamPeerMbedTLS : public StreamPeerTLS {
private:
Status status = STATUS_DISCONNECTED;
diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
index 598e1d972e..22d79b79f9 100644
--- a/modules/mbedtls/tests/test_crypto_mbedtls.cpp
+++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
@@ -30,7 +30,8 @@
#include "test_crypto_mbedtls.h"
-#include "modules/mbedtls/crypto_mbedtls.h"
+#include "../crypto_mbedtls.h"
+
#include "tests/test_macros.h"
namespace TestCryptoMbedTLS {
diff --git a/modules/mbedtls/tls_context_mbedtls.h b/modules/mbedtls/tls_context_mbedtls.h
index f1bad6a40c..29323688fb 100644
--- a/modules/mbedtls/tls_context_mbedtls.h
+++ b/modules/mbedtls/tls_context_mbedtls.h
@@ -34,7 +34,6 @@
#include "crypto_mbedtls.h"
#include "core/io/file_access.h"
-
#include "core/object/ref_counted.h"
#include <mbedtls/config.h>
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
index d807fd9517..781f928f66 100644
--- a/modules/meshoptimizer/register_types.cpp
+++ b/modules/meshoptimizer/register_types.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "register_types.h"
+
#include "scene/resources/surface_tool.h"
+
#include "thirdparty/meshoptimizer/meshoptimizer.h"
void initialize_meshoptimizer_module(ModuleInitializationLevel p_level) {
diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h
index c14db28460..30760703e3 100644
--- a/modules/minimp3/audio_stream_mp3.h
+++ b/modules/minimp3/audio_stream_mp3.h
@@ -34,7 +34,7 @@
#include "core/io/resource_loader.h"
#include "servers/audio/audio_stream.h"
-#include "minimp3_ex.h"
+#include <minimp3_ex.h>
class AudioStreamMP3;
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
index c9e05c44e1..da89321018 100644
--- a/modules/minimp3/register_types.cpp
+++ b/modules/minimp3/register_types.cpp
@@ -33,10 +33,13 @@
#include "audio_stream_mp3.h"
#ifdef TOOLS_ENABLED
-#include "core/config/engine.h"
#include "resource_importer_mp3.h"
#endif
+#ifdef TOOLS_ENABLED
+#include "core/config/engine.h"
+#endif
+
void initialize_minimp3_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h
index b887963050..2df44deaea 100644
--- a/modules/minimp3/resource_importer_mp3.h
+++ b/modules/minimp3/resource_importer_mp3.h
@@ -32,6 +32,7 @@
#define RESOURCE_IMPORTER_MP3_H
#include "audio_stream_mp3.h"
+
#include "core/io/resource_importer.h"
class ResourceImporterMP3 : public ResourceImporter {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 05595e7e45..bc26352e9c 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -30,7 +30,23 @@
#include "csharp_script.h"
-#include <stdint.h>
+#include "godotsharp_dirs.h"
+#include "managed_callable.h"
+#include "mono_gd/gd_mono_cache.h"
+#include "signal_awaiter_utils.h"
+#include "utils/macros.h"
+#include "utils/naming_utils.h"
+#include "utils/path_utils.h"
+#include "utils/string_utils.h"
+
+#ifdef DEBUG_METHODS_ENABLED
+#include "class_db_api_json.h"
+#endif
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_internal_calls.h"
+#include "editor/script_templates/templates.gen.h"
+#endif
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
@@ -39,30 +55,18 @@
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/thread.h"
+#include "servers/text_server.h"
#ifdef TOOLS_ENABLED
#include "core/os/keyboard.h"
#include "editor/editor_file_system.h"
-#include "editor/editor_internal_calls.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/inspector_dock.h"
#include "editor/node_dock.h"
-#include "editor/script_templates/templates.gen.h"
-#endif
-
-#ifdef DEBUG_METHODS_ENABLED
-#include "class_db_api_json.h"
#endif
-#include "godotsharp_dirs.h"
-#include "managed_callable.h"
-#include "mono_gd/gd_mono_cache.h"
-#include "servers/text_server.h"
-#include "signal_awaiter_utils.h"
-#include "utils/macros.h"
-#include "utils/naming_utils.h"
-#include "utils/string_utils.h"
+#include <stdint.h>
#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var)
@@ -740,11 +744,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
return false; // Already up to date
}
} else {
- String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
-
- if (assembly_name.is_empty()) {
- assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
- }
+ String assembly_name = path::get_csharp_project_name();
assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
.path_join(assembly_name + ".dll");
@@ -2320,6 +2320,9 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
Variant::Type param_type = (Variant::Type)(int)param["type"];
PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
arg_info.usage = (uint32_t)param["usage"];
+ if (param.has("class_name")) {
+ arg_info.class_name = (StringName)param["class_name"];
+ }
mi.arguments.push_back(arg_info);
}
@@ -2350,6 +2353,9 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
Variant::Type param_type = (Variant::Type)(int)param["type"];
PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
arg_info.usage = (uint32_t)param["usage"];
+ if (param.has("class_name")) {
+ arg_info.class_name = (StringName)param["class_name"];
+ }
mi.arguments.push_back(arg_info);
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 13c7c4b412..cfdf8ae6f8 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -31,15 +31,15 @@
#ifndef CSHARP_SCRIPT_H
#define CSHARP_SCRIPT_H
+#include "mono_gc_handle.h"
+#include "mono_gd/gd_mono.h"
+
#include "core/doc_data.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
#include "core/templates/self_list.h"
-#include "mono_gc_handle.h"
-#include "mono_gd/gd_mono.h"
-
#ifdef TOOLS_ENABLED
#include "editor/editor_plugin.h"
#endif
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 894053c5de..1cabccb357 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -74,8 +74,13 @@
<!-- Godot DefineConstants. -->
<PropertyGroup>
- <!-- Define constant to identify Godot builds. -->
- <GodotDefineConstants>GODOT</GodotDefineConstants>
+ <!-- Define constants to identify Godot builds and versions. -->
+ <GodotDefineConstants>
+ GODOT;
+ GODOT4;GODOT4_OR_GREATER;
+ GODOT4_1;GODOT4_1_OR_GREATER;GODOT4_0_OR_GREATER;
+ GODOT4_1_0;GODOT4_1_0_OR_GREATER;
+ </GodotDefineConstants>
<!--
Define constant to determine the target Godot platform. This includes the
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
index 2b89633ef6..e22cc951b1 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
@@ -4,12 +4,17 @@ namespace Godot.SourceGenerators
{
public PropertyInfo(VariantType type, string name, PropertyHint hint,
string? hintString, PropertyUsageFlags usage, bool exported)
+ : this(type, name, hint, hintString, usage, className: null, exported) { }
+
+ public PropertyInfo(VariantType type, string name, PropertyHint hint,
+ string? hintString, PropertyUsageFlags usage, string? className, bool exported)
{
Type = type;
Name = name;
Hint = hint;
HintString = hintString;
Usage = usage;
+ ClassName = className;
Exported = exported;
}
@@ -18,6 +23,7 @@ namespace Godot.SourceGenerators
public PropertyHint Hint { get; }
public string? HintString { get; }
public PropertyUsageFlags Usage { get; }
+ public string? ClassName { get; }
public bool Exported { get; }
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 8b75530380..1affe692d0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -288,8 +288,14 @@ namespace Godot.SourceGenerators
.Append("\", usage: (global::Godot.PropertyUsageFlags)")
.Append((int)propertyInfo.Usage)
.Append(", exported: ")
- .Append(propertyInfo.Exported ? "true" : "false")
- .Append(")");
+ .Append(propertyInfo.Exported ? "true" : "false");
+ if (propertyInfo.ClassName != null)
+ {
+ source.Append(", className: new global::Godot.StringName(\"")
+ .Append(propertyInfo.ClassName)
+ .Append("\")");
+ }
+ source.Append(")");
}
private static MethodInfo DetermineMethodInfo(GodotMethodData method)
@@ -298,7 +304,9 @@ namespace Godot.SourceGenerators
if (method.RetType != null)
{
- returnVal = DeterminePropertyInfo(method.RetType.Value.MarshalType, name: string.Empty);
+ returnVal = DeterminePropertyInfo(method.RetType.Value.MarshalType,
+ method.RetType.Value.TypeSymbol,
+ name: string.Empty);
}
else
{
@@ -317,6 +325,7 @@ namespace Godot.SourceGenerators
for (int i = 0; i < paramCount; i++)
{
arguments.Add(DeterminePropertyInfo(method.ParamTypes[i],
+ method.Method.Parameters[i].Type,
name: method.Method.Parameters[i].Name));
}
}
@@ -329,7 +338,7 @@ namespace Godot.SourceGenerators
defaultArguments: null);
}
- private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
+ private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, ITypeSymbol typeSymbol, string name)
{
var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
@@ -338,8 +347,14 @@ namespace Godot.SourceGenerators
if (memberVariantType == VariantType.Nil)
propUsage |= PropertyUsageFlags.NilIsVariant;
+ string? className = null;
+ if (memberVariantType == VariantType.Object && typeSymbol is INamedTypeSymbol namedTypeSymbol)
+ {
+ className = namedTypeSymbol.GetGodotScriptNativeClassName();
+ }
+
return new PropertyInfo(memberVariantType, name,
- PropertyHint.None, string.Empty, propUsage, exported: false);
+ PropertyHint.None, string.Empty, propUsage, className, exported: false);
}
private static void GenerateHasMethodEntry(
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index f40322bd89..7e3323f588 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -360,8 +360,14 @@ namespace Godot.SourceGenerators
.Append("\", usage: (global::Godot.PropertyUsageFlags)")
.Append((int)propertyInfo.Usage)
.Append(", exported: ")
- .Append(propertyInfo.Exported ? "true" : "false")
- .Append(")");
+ .Append(propertyInfo.Exported ? "true" : "false");
+ if (propertyInfo.ClassName != null)
+ {
+ source.Append(", className: new global::Godot.StringName(\"")
+ .Append(propertyInfo.ClassName)
+ .Append("\")");
+ }
+ source.Append(")");
}
private static MethodInfo DetermineMethodInfo(GodotSignalDelegateData signalDelegateData)
@@ -372,7 +378,9 @@ namespace Godot.SourceGenerators
if (invokeMethodData.RetType != null)
{
- returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value.MarshalType, name: string.Empty);
+ returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value.MarshalType,
+ invokeMethodData.RetType.Value.TypeSymbol,
+ name: string.Empty);
}
else
{
@@ -391,6 +399,7 @@ namespace Godot.SourceGenerators
for (int i = 0; i < paramCount; i++)
{
arguments.Add(DeterminePropertyInfo(invokeMethodData.ParamTypes[i],
+ invokeMethodData.Method.Parameters[i].Type,
name: invokeMethodData.Method.Parameters[i].Name));
}
}
@@ -403,7 +412,7 @@ namespace Godot.SourceGenerators
defaultArguments: null);
}
- private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
+ private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, ITypeSymbol typeSymbol, string name)
{
var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
@@ -412,8 +421,14 @@ namespace Godot.SourceGenerators
if (memberVariantType == VariantType.Nil)
propUsage |= PropertyUsageFlags.NilIsVariant;
+ string? className = null;
+ if (memberVariantType == VariantType.Object && typeSymbol is INamedTypeSymbol namedTypeSymbol)
+ {
+ className = namedTypeSymbol.GetGodotScriptNativeClassName();
+ }
+
return new PropertyInfo(memberVariantType, name,
- PropertyHint.None, string.Empty, propUsage, exported: false);
+ PropertyHint.None, string.Empty, propUsage, className, exported: false);
}
private static void GenerateHasSignalEntry(
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index 7c5502814f..d86a77d222 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -57,27 +57,5 @@ namespace GodotTools.Core
path.StartsWith("\\", StringComparison.Ordinal) ||
path.StartsWith(_driveRoot, StringComparison.Ordinal);
}
-
- public static string ToSafeDirName(this string dirName, bool allowDirSeparator = false)
- {
- var invalidChars = new List<string> { ":", "*", "?", "\"", "<", ">", "|" };
-
- if (allowDirSeparator)
- {
- // Directory separators are allowed, but disallow ".." to avoid going up the filesystem
- invalidChars.Add("..");
- }
- else
- {
- invalidChars.Add("/");
- }
-
- string safeDirName = dirName.Replace("\\", "/").Trim();
-
- foreach (string invalidChar in invalidChars)
- safeDirName = safeDirName.Replace(invalidChar, "-");
-
- return safeDirName;
- }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 27c2676dd0..ea2d14958b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -151,7 +151,7 @@ namespace GodotTools.Export
string ridOS = DetermineRuntimeIdentifierOS(platform);
string ridArch = DetermineRuntimeIdentifierArch(arch);
string runtimeIdentifier = $"{ridOS}-{ridArch}";
- string projectDataDirName = $"{DetermineDataDirNameForProject()}_{arch}";
+ string projectDataDirName = $"data_{GodotSharpDirs.CSharpProjectName}_{arch}";
if (platform == OS.Platforms.MacOS)
{
projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
@@ -258,12 +258,5 @@ namespace GodotTools.Export
platform = null;
return false;
}
-
- private static string DetermineDataDirNameForProject()
- {
- string appName = (string)ProjectSettings.GetSetting("application/config/name");
- string appNameSafe = appName.ToSafeDirName();
- return $"data_{appNameSafe}";
- }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index fb68fcbae6..55b413453d 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -48,21 +48,23 @@ namespace GodotTools.Internals
}
}
- public static void DetermineProjectLocation()
+
+ public static string CSharpProjectName
{
- static string DetermineProjectName()
+ get
{
- string projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name");
- projectAssemblyName = projectAssemblyName.ToSafeDirName();
- if (string.IsNullOrEmpty(projectAssemblyName))
- projectAssemblyName = "UnnamedProject";
- return projectAssemblyName;
+ Internal.godot_icall_GodotSharpDirs_CSharpProjectName(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
}
+ }
+ public static void DetermineProjectLocation()
+ {
_projectAssemblyName = (string)ProjectSettings.GetSetting("dotnet/project/assembly_name");
if (string.IsNullOrEmpty(_projectAssemblyName))
{
- _projectAssemblyName = DetermineProjectName();
+ _projectAssemblyName = CSharpProjectName;
ProjectSettings.SetSetting("dotnet/project/assembly_name", _projectAssemblyName);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index fd810996f7..3ea11750b7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -101,6 +101,8 @@ namespace GodotTools.Internals
public static partial void godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string r_dest);
+ public static partial void godot_icall_GodotSharpDirs_CSharpProjectName(out godot_string r_dest);
+
public static partial void godot_icall_EditorProgress_Create(in godot_string task, in godot_string label,
int amount, bool canCancel);
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index d4472f4722..15bb574f4d 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -32,6 +32,11 @@
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
+#include "../godotsharp_defs.h"
+#include "../utils/naming_utils.h"
+#include "../utils/path_utils.h"
+#include "../utils/string_utils.h"
+
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/compression.h"
@@ -40,11 +45,6 @@
#include "core/os/os.h"
#include "main/main.h"
-#include "../godotsharp_defs.h"
-#include "../utils/naming_utils.h"
-#include "../utils/path_utils.h"
-#include "../utils/string_utils.h"
-
StringBuilder &operator<<(StringBuilder &r_sb, const String &p_string) {
r_sb.append(p_string);
return r_sb;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index eac281ddb4..38347a5181 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -31,16 +31,17 @@
#ifndef BINDINGS_GENERATOR_H
#define BINDINGS_GENERATOR_H
+#include "core/typedefs.h" // DEBUG_METHODS_ENABLED
+
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
+
#include "core/doc_data.h"
#include "core/object/class_db.h"
#include "core/string/string_builder.h"
+#include "core/string/ustring.h"
#include "editor/doc_tools.h"
#include "editor/editor_help.h"
-#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
-
-#include "core/string/ustring.h"
-
class BindingsGenerator {
struct ConstantInterface {
String name;
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 34b9974d10..ba6b91b704 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -30,9 +30,12 @@
#include "editor_internal_calls.h"
-#ifdef UNIX_ENABLED
-#include <unistd.h> // access
-#endif
+#include "../csharp_script.h"
+#include "../godotsharp_dirs.h"
+#include "../interop_types.h"
+#include "../utils/macos_utils.h"
+#include "../utils/path_utils.h"
+#include "code_completion.h"
#include "core/config/project_settings.h"
#include "core/os/os.h"
@@ -46,12 +49,9 @@
#include "editor/plugins/script_editor_plugin.h"
#include "main/main.h"
-#include "../csharp_script.h"
-#include "../godotsharp_dirs.h"
-#include "../utils/macos_utils.h"
-#include "code_completion.h"
-
-#include "../interop_types.h"
+#ifdef UNIX_ENABLED
+#include <unistd.h> // access
+#endif
#ifdef __cplusplus
extern "C" {
@@ -81,6 +81,10 @@ void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
#endif
}
+void godot_icall_GodotSharpDirs_CSharpProjectName(godot_string *r_dest) {
+ memnew_placement(r_dest, String(path::get_csharp_project_name()));
+}
+
void godot_icall_EditorProgress_Create(const godot_string *p_task, const godot_string *p_label, int32_t p_amount, bool p_can_cancel) {
String task = *reinterpret_cast<const String *>(p_task);
String label = *reinterpret_cast<const String *>(p_label);
@@ -231,6 +235,7 @@ static const void *unmanaged_callbacks[]{
(void *)godot_icall_GodotSharpDirs_MonoUserDir,
(void *)godot_icall_GodotSharpDirs_BuildLogsDirs,
(void *)godot_icall_GodotSharpDirs_DataEditorToolsDir,
+ (void *)godot_icall_GodotSharpDirs_CSharpProjectName,
(void *)godot_icall_EditorProgress_Create,
(void *)godot_icall_EditorProgress_Dispose,
(void *)godot_icall_EditorProgress_Step,
diff --git a/modules/mono/editor/hostfxr_resolver.cpp b/modules/mono/editor/hostfxr_resolver.cpp
index 786272b28c..e08823bbf7 100644
--- a/modules/mono/editor/hostfxr_resolver.cpp
+++ b/modules/mono/editor/hostfxr_resolver.cpp
@@ -60,6 +60,9 @@ SOFTWARE.
#include "hostfxr_resolver.h"
+#include "../utils/path_utils.h"
+#include "semver.h"
+
#include "core/config/engine.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
@@ -70,9 +73,6 @@ SOFTWARE.
#include <windows.h>
#endif
-#include "../utils/path_utils.h"
-#include "semver.h"
-
// We don't use libnethost as it gives us issues with some compilers.
// This file tries to mimic libnethost's hostfxr_resolver search logic. We try to use the
// same function names for easier comparing in case we need to update this in the future.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
index 0f447b93c8..94734a6552 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
@@ -9,16 +9,22 @@ public readonly struct PropertyInfo
public PropertyHint Hint { get; init; }
public string HintString { get; init; }
public PropertyUsageFlags Usage { get; init; }
+ public StringName? ClassName { get; init; }
public bool Exported { get; init; }
public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
PropertyUsageFlags usage, bool exported)
+ : this(type, name, hint, hintString, usage, className: null, exported) { }
+
+ public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
+ PropertyUsageFlags usage, StringName? className, bool exported)
{
Type = type;
Name = name;
Hint = hint;
HintString = hintString;
Usage = usage;
+ ClassName = className;
Exported = exported;
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 98c9ed3f0e..dfae85b667 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -655,12 +655,18 @@ namespace Godot.Bridge
{
foreach (var param in method.Arguments)
{
- methodParams.Add(new Collections.Dictionary()
+ var pinfo = new Collections.Dictionary()
{
{ "name", param.Name },
{ "type", (int)param.Type },
{ "usage", (int)param.Usage }
- });
+ };
+ if (param.ClassName != null)
+ {
+ pinfo["class_name"] = param.ClassName;
+ }
+
+ methodParams.Add(pinfo);
}
}
@@ -743,12 +749,18 @@ namespace Godot.Bridge
{
foreach (var param in signal.Arguments)
{
- signalParams.Add(new Collections.Dictionary()
+ var pinfo = new Collections.Dictionary()
{
{ "name", param.Name },
{ "type", (int)param.Type },
{ "usage", (int)param.Usage }
- });
+ };
+ if (param.ClassName != null)
+ {
+ pinfo["class_name"] = param.ClassName;
+ }
+
+ signalParams.Add(pinfo);
}
}
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 56fc467b77..ee4de4e9f5 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -30,6 +30,13 @@
#include "runtime_interop.h"
+#include "../csharp_script.h"
+#include "../interop_types.h"
+#include "../managed_callable.h"
+#include "../mono_gd/gd_mono_cache.h"
+#include "../signal_awaiter_utils.h"
+#include "../utils/path_utils.h"
+
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
@@ -44,14 +51,6 @@
#include "editor/editor_file_system.h"
#endif
-#include "../interop_types.h"
-
-#include "modules/mono/csharp_script.h"
-#include "modules/mono/managed_callable.h"
-#include "modules/mono/mono_gd/gd_mono_cache.h"
-#include "modules/mono/signal_awaiter_utils.h"
-#include "modules/mono/utils/path_utils.h"
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index bff7d04b55..159cb91d1b 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -30,6 +30,13 @@
#include "godotsharp_dirs.h"
+#include "mono_gd/gd_mono.h"
+#include "utils/path_utils.h"
+
+#ifdef ANDROID_ENABLED
+#include "mono_gd/support/android_support.h"
+#endif
+
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
@@ -39,12 +46,6 @@
#include "editor/editor_paths.h"
#endif
-#ifdef ANDROID_ENABLED
-#include "mono_gd/support/android_support.h"
-#endif
-
-#include "mono_gd/gd_mono.h"
-
namespace GodotSharpDirs {
String _get_expected_build_config() {
@@ -139,8 +140,7 @@ private:
api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
#else // TOOLS_ENABLED
String arch = Engine::get_singleton()->get_architecture_name();
- String appname = GLOBAL_GET("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ String appname_safe = path::get_csharp_project_name();
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 4936e69323..290d49be14 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -31,12 +31,12 @@
#ifndef MANAGED_CALLABLE_H
#define MANAGED_CALLABLE_H
+#include "mono_gc_handle.h"
+
#include "core/os/mutex.h"
#include "core/templates/self_list.h"
#include "core/variant/callable.h"
-#include "mono_gc_handle.h"
-
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
GCHandleIntPtr delegate_handle;
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 97bf49271a..92fa30e5e8 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -30,26 +30,25 @@
#include "gd_mono.h"
-#include "core/config/project_settings.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/os/os.h"
-#include "core/os/thread.h"
-
#include "../csharp_script.h"
#include "../glue/runtime_interop.h"
#include "../godotsharp_dirs.h"
-#include "../utils/path_utils.h"
-#include "gd_mono_cache.h"
-
#include "../thirdparty/coreclr_delegates.h"
#include "../thirdparty/hostfxr.h"
+#include "../utils/path_utils.h"
+#include "gd_mono_cache.h"
#ifdef TOOLS_ENABLED
#include "../editor/hostfxr_resolver.h"
#endif
+#include "core/config/project_settings.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/os/os.h"
+#include "core/os/thread.h"
+
#ifdef UNIX_ENABLED
#include <dlfcn.h>
#endif
@@ -293,20 +292,10 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
return godot_plugins_initialize;
}
#else
-static String get_assembly_name() {
- String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
-
- if (assembly_name.is_empty()) {
- assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
- }
-
- return assembly_name;
-}
-
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
- String assembly_name = get_assembly_name();
+ String assembly_name = path::get_csharp_project_name();
HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
.path_join(assembly_name + ".dll"));
@@ -331,7 +320,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
}
godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle) {
- String assembly_name = get_assembly_name();
+ String assembly_name = path::get_csharp_project_name();
#if defined(WINDOWS_ENABLED)
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
@@ -476,11 +465,7 @@ void GDMono::_init_godot_api_hashes() {
#ifdef TOOLS_ENABLED
bool GDMono::_load_project_assembly() {
- String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
-
- if (assembly_name.is_empty()) {
- assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
- }
+ String assembly_name = path::get_csharp_project_name();
String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
.path_join(assembly_name + ".dll");
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 04c375059d..398f94d924 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -31,10 +31,10 @@
#ifndef GD_MONO_H
#define GD_MONO_H
-#include "core/io/config_file.h"
-
#include "../godotsharp_defs.h"
+#include "core/io/config_file.h"
+
#ifndef GD_CLR_STDCALL
#ifdef WIN32
#define GD_CLR_STDCALL __stdcall
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index e4cddce1d2..9201da7cae 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -31,11 +31,10 @@
#ifndef GD_MONO_CACHE_H
#define GD_MONO_CACHE_H
-#include <stdint.h>
-
#include "../csharp_script.h"
#include "../interop_types.h"
#include "../mono_gc_handle.h"
+
#include "core/object/object.h"
#include "core/string/string_name.h"
#include "core/string/ustring.h"
@@ -43,6 +42,8 @@
#include "core/variant/dictionary.h"
#include "core/variant/variant.h"
+#include <stdint.h>
+
class CSharpScript;
namespace GDMonoCache {
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 6e8a5ce5c1..14b442516e 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -32,8 +32,21 @@
#if defined(ANDROID_ENABLED)
-#include <dlfcn.h> // dlopen, dlsym
+#include "../../utils/path_utils.h"
+#include "../../utils/string_utils.h"
+#include "../gd_mono_cache.h"
+#include "../gd_mono_marshal.h"
+
+#include "core/os/os.h"
+#include "core/string/ustring.h"
+
+#include "java_godot_wrapper.h"
+#include "os_android.h"
+#include "thread_jandroid.h"
+
#include <mono/utils/mono-dl-fallback.h>
+
+#include <dlfcn.h> // dlopen, dlsym
#include <sys/system_properties.h>
#include <cstddef>
@@ -43,17 +56,6 @@
#include <ifaddrs.h>
#endif
-#include "core/os/os.h"
-#include "core/string/ustring.h"
-#include "platform/android/java_godot_wrapper.h"
-#include "platform/android/os_android.h"
-#include "platform/android/thread_jandroid.h"
-
-#include "../../utils/path_utils.h"
-#include "../../utils/string_utils.h"
-#include "../gd_mono_cache.h"
-#include "../gd_mono_marshal.h"
-
// Warning: JNI boilerplate ahead... continue at your own risk
namespace gdmono {
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
index f4abf636b1..df8b3e2626 100644
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -32,12 +32,12 @@
#if defined(IOS_ENABLED)
-#import <Foundation/Foundation.h>
-#include <os/log.h>
+#include "../gd_mono_marshal.h"
#include "core/ustring.h"
-#include "../gd_mono_marshal.h"
+#import <Foundation/Foundation.h>
+#include <os/log.h>
// Implemented mostly following: https://github.com/mono/mono/blob/master/sdks/ios/app/runtime.m
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 7dab4b037f..beaa50ecb2 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -30,10 +30,10 @@
#include "register_types.h"
-#include "core/config/engine.h"
-
#include "csharp_script.h"
+#include "core/config/engine.h"
+
CSharpLanguage *script_language_cs = nullptr;
Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs;
Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 635771f3dc..ed1907afa0 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -31,11 +31,11 @@
#ifndef SIGNAL_AWAITER_UTILS_H
#define SIGNAL_AWAITER_UTILS_H
-#include "core/object/ref_counted.h"
-
#include "csharp_script.h"
#include "mono_gc_handle.h"
+#include "core/object/ref_counted.h"
+
Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr);
class BaseSignalCallable : public CallableCustom {
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index b5a3816ed7..aa97534675 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -35,6 +35,8 @@
#include "core/io/file_access.h"
#include "core/os/os.h"
+#include <stdlib.h>
+
#ifdef WINDOWS_ENABLED
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -47,8 +49,6 @@
#define ENV_PATH_SEP ":"
#endif
-#include <stdlib.h>
-
namespace path {
String find_executable(const String &p_name) {
@@ -231,4 +231,36 @@ String relative_to(const String &p_path, const String &p_relative_to) {
return relative_to_impl(path_abs_norm, relative_to_abs_norm);
}
+
+const Vector<String> reserved_assembly_names = { "GodotSharp", "GodotSharpEditor", "Godot.SourceGenerators" };
+
+String get_csharp_project_name() {
+ String name = GLOBAL_GET("dotnet/project/assembly_name");
+ if (name.is_empty()) {
+ name = GLOBAL_GET("application/config/name");
+ Vector<String> invalid_chars = Vector<String>({ //
+ // Windows reserved filename chars.
+ ":", "*", "?", "\"", "<", ">", "|",
+ // Directory separators.
+ "/", "\\",
+ // Other chars that have been found to break assembly loading.
+ ";", "'", "=", "," });
+ name = name.strip_edges();
+ for (int i = 0; i < invalid_chars.size(); i++) {
+ name = name.replace(invalid_chars[i], "-");
+ }
+ }
+
+ if (name.is_empty()) {
+ name = "UnnamedProject";
+ }
+
+ // Avoid reserved names that conflict with Godot assemblies.
+ if (reserved_assembly_names.has(name)) {
+ name += "_";
+ }
+
+ return name;
+}
+
} // namespace path
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
index 25d130fc58..fc043c3f15 100644
--- a/modules/mono/utils/path_utils.h
+++ b/modules/mono/utils/path_utils.h
@@ -31,7 +31,6 @@
#ifndef MONO_PATH_UTILS_H
#define MONO_PATH_UTILS_H
-#include "core/string/string_builder.h"
#include "core/string/ustring.h"
namespace path {
@@ -58,6 +57,8 @@ String abspath(const String &p_path);
String realpath(const String &p_path);
String relative_to(const String &p_path, const String &p_relative_to);
+
+String get_csharp_project_name();
} // namespace path
#endif // MONO_PATH_UTILS_H
diff --git a/modules/multiplayer/editor/editor_network_profiler.h b/modules/multiplayer/editor/editor_network_profiler.h
index 1a38890574..b4f8ffa724 100644
--- a/modules/multiplayer/editor/editor_network_profiler.h
+++ b/modules/multiplayer/editor/editor_network_profiler.h
@@ -31,6 +31,8 @@
#ifndef EDITOR_NETWORK_PROFILER_H
#define EDITOR_NETWORK_PROFILER_H
+#include "../multiplayer_debugger.h"
+
#include "scene/debugger/scene_debugger.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -38,8 +40,6 @@
#include "scene/gui/split_container.h"
#include "scene/gui/tree.h"
-#include "../multiplayer_debugger.h"
-
class EditorNetworkProfiler : public VBoxContainer {
GDCLASS(EditorNetworkProfiler, VBoxContainer)
diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.h b/modules/multiplayer/editor/multiplayer_editor_plugin.h
index 310653585a..a22144cdcf 100644
--- a/modules/multiplayer/editor/multiplayer_editor_plugin.h
+++ b/modules/multiplayer/editor/multiplayer_editor_plugin.h
@@ -32,7 +32,6 @@
#define MULTIPLAYER_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-
#include "editor/plugins/editor_debugger_plugin.h"
class EditorNetworkProfiler;
diff --git a/modules/multiplayer/editor/replication_editor.h b/modules/multiplayer/editor/replication_editor.h
index 262c10ea81..208eaabff5 100644
--- a/modules/multiplayer/editor/replication_editor.h
+++ b/modules/multiplayer/editor/replication_editor.h
@@ -31,8 +31,9 @@
#ifndef REPLICATION_EDITOR_H
#define REPLICATION_EDITOR_H
+#include "../scene_replication_config.h"
+
#include "editor/editor_plugin.h"
-#include "modules/multiplayer/scene_replication_config.h"
#include "scene/gui/box_container.h"
class ConfirmationDialog;
diff --git a/modules/multiplayer/multiplayer_debugger.h b/modules/multiplayer/multiplayer_debugger.h
index 7d2eaa4584..96764ced06 100644
--- a/modules/multiplayer/multiplayer_debugger.h
+++ b/modules/multiplayer/multiplayer_debugger.h
@@ -32,7 +32,6 @@
#define MULTIPLAYER_DEBUGGER_H
#include "core/debugger/engine_profiler.h"
-
#include "core/os/os.h"
class MultiplayerSynchronizer;
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index 8a54140e32..0e94b781ea 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -31,14 +31,13 @@
#ifndef MULTIPLAYER_SPAWNER_H
#define MULTIPLAYER_SPAWNER_H
-#include "scene/main/node.h"
+#include "scene_replication_config.h"
#include "core/templates/local_vector.h"
#include "core/variant/typed_array.h"
+#include "scene/main/node.h"
#include "scene/resources/packed_scene.h"
-#include "scene_replication_config.h"
-
class MultiplayerSpawner : public Node {
GDCLASS(MultiplayerSpawner, Node);
diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h
index 6fb249d199..7b77e691d1 100644
--- a/modules/multiplayer/multiplayer_synchronizer.h
+++ b/modules/multiplayer/multiplayer_synchronizer.h
@@ -31,10 +31,10 @@
#ifndef MULTIPLAYER_SYNCHRONIZER_H
#define MULTIPLAYER_SYNCHRONIZER_H
-#include "scene/main/node.h"
-
#include "scene_replication_config.h"
+#include "scene/main/node.h"
+
class MultiplayerSynchronizer : public Node {
GDCLASS(MultiplayerSynchronizer, Node);
diff --git a/modules/multiplayer/register_types.cpp b/modules/multiplayer/register_types.cpp
index ea562af43f..fe29b4bdd8 100644
--- a/modules/multiplayer/register_types.cpp
+++ b/modules/multiplayer/register_types.cpp
@@ -30,14 +30,13 @@
#include "register_types.h"
+#include "multiplayer_debugger.h"
#include "multiplayer_spawner.h"
#include "multiplayer_synchronizer.h"
#include "scene_multiplayer.h"
#include "scene_replication_interface.h"
#include "scene_rpc_interface.h"
-#include "multiplayer_debugger.h"
-
#ifdef TOOLS_ENABLED
#include "editor/multiplayer_editor_plugin.h"
#endif
diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp
index fed124c41a..90e6ac7c2c 100644
--- a/modules/multiplayer/scene_cache_interface.cpp
+++ b/modules/multiplayer/scene_cache_interface.cpp
@@ -30,12 +30,12 @@
#include "scene_cache_interface.h"
+#include "scene_multiplayer.h"
+
#include "core/io/marshalls.h"
#include "scene/main/node.h"
#include "scene/main/window.h"
-#include "scene_multiplayer.h"
-
void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) {
if (p_connected) {
path_get_cache.insert(p_id, PathGetCache());
diff --git a/modules/multiplayer/scene_multiplayer.cpp b/modules/multiplayer/scene_multiplayer.cpp
index 7a424e83f8..3e3118b1cd 100644
--- a/modules/multiplayer/scene_multiplayer.cpp
+++ b/modules/multiplayer/scene_multiplayer.cpp
@@ -33,12 +33,12 @@
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
-#include <stdint.h>
-
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#endif
+#include <stdint.h>
+
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ void SceneMultiplayer::_profile_bandwidth(const String &p_what, int p_value) {
if (EngineDebugger::is_profiling("multiplayer:bandwidth")) {
diff --git a/modules/multiplayer/scene_multiplayer.h b/modules/multiplayer/scene_multiplayer.h
index 678ae932f1..a61e505689 100644
--- a/modules/multiplayer/scene_multiplayer.h
+++ b/modules/multiplayer/scene_multiplayer.h
@@ -31,12 +31,12 @@
#ifndef SCENE_MULTIPLAYER_H
#define SCENE_MULTIPLAYER_H
-#include "scene/main/multiplayer_api.h"
-
#include "scene_cache_interface.h"
#include "scene_replication_interface.h"
#include "scene_rpc_interface.h"
+#include "scene/main/multiplayer_api.h"
+
class OfflineMultiplayerPeer : public MultiplayerPeer {
GDCLASS(OfflineMultiplayerPeer, MultiplayerPeer);
diff --git a/modules/multiplayer/scene_replication_config.h b/modules/multiplayer/scene_replication_config.h
index d4b0a611bc..44f8259904 100644
--- a/modules/multiplayer/scene_replication_config.h
+++ b/modules/multiplayer/scene_replication_config.h
@@ -32,7 +32,6 @@
#define SCENE_REPLICATION_CONFIG_H
#include "core/io/resource.h"
-
#include "core/variant/typed_array.h"
class SceneReplicationConfig : public Resource {
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index 0af45c16b4..267d329ca7 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -31,11 +31,11 @@
#ifndef SCENE_REPLICATION_INTERFACE_H
#define SCENE_REPLICATION_INTERFACE_H
-#include "core/object/ref_counted.h"
-
#include "multiplayer_spawner.h"
#include "multiplayer_synchronizer.h"
+#include "core/object/ref_counted.h"
+
class SceneMultiplayer;
class SceneReplicationInterface : public RefCounted {
diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp
index 4e20e8fd3a..da1a044c9d 100644
--- a/modules/multiplayer/scene_rpc_interface.cpp
+++ b/modules/multiplayer/scene_rpc_interface.cpp
@@ -30,14 +30,14 @@
#include "scene_rpc_interface.h"
+#include "scene_multiplayer.h"
+
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/node.h"
#include "scene/main/window.h"
-#include "scene_multiplayer.h"
-
// The RPC meta is composed by a single byte that contains (starting from the least significant bit):
// - `NetworkCommands` in the first four bits.
// - `NetworkNodeIdCompression` in the next 2 bits.
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index dd2c539c95..634d70d3bd 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -33,6 +33,7 @@
#ifdef TOOLS_ENABLED
#include "../navigation_mesh_generator.h"
+
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
@@ -41,6 +42,7 @@
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/label.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
void NavigationMeshEditor::_node_removed(Node *p_node) {
if (p_node == node) {
@@ -98,7 +100,10 @@ void NavigationMeshEditor::_bake_pressed() {
}
NavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
- NavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node);
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
+ source_geometry_data.instantiate();
+ NavigationMeshGenerator::get_singleton()->parse_source_geometry_data(node->get_navigation_mesh(), source_geometry_data, node);
+ NavigationMeshGenerator::get_singleton()->bake_from_source_geometry_data(node->get_navigation_mesh(), source_geometry_data);
node->update_gizmos();
}
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 5baae478c2..cfd0cc6d46 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -30,12 +30,12 @@
#include "godot_navigation_server.h"
-#include "core/os/mutex.h"
-
#ifndef _3D_DISABLED
#include "navigation_mesh_generator.h"
#endif
+#include "core/os/mutex.h"
+
using namespace NavigationUtilities;
/// Creates a struct for each function and a function that once called creates
@@ -465,7 +465,10 @@ void GodotNavigationServer::region_bake_navigation_mesh(Ref<NavigationMesh> p_na
#ifndef _3D_DISABLED
NavigationMeshGenerator::get_singleton()->clear(p_navigation_mesh);
- NavigationMeshGenerator::get_singleton()->bake(p_navigation_mesh, p_root_node);
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
+ source_geometry_data.instantiate();
+ NavigationMeshGenerator::get_singleton()->parse_source_geometry_data(p_navigation_mesh, source_geometry_data, p_root_node);
+ NavigationMeshGenerator::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, source_geometry_data);
#endif
}
@@ -693,6 +696,20 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
}
}
+COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused) {
+ NavAgent *agent = agent_owner.get_or_null(p_agent);
+ ERR_FAIL_COND(agent == nullptr);
+
+ agent->set_paused(p_paused);
+}
+
+bool GodotNavigationServer::agent_get_paused(RID p_agent) const {
+ NavAgent *agent = agent_owner.get_or_null(p_agent);
+ ERR_FAIL_COND_V(agent == nullptr, false);
+
+ return agent->get_paused();
+}
+
COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) {
NavAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
@@ -886,6 +903,20 @@ RID GodotNavigationServer::obstacle_get_map(RID p_obstacle) const {
return RID();
}
+COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused) {
+ NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle);
+ ERR_FAIL_COND(obstacle == nullptr);
+
+ obstacle->set_paused(p_paused);
+}
+
+bool GodotNavigationServer::obstacle_get_paused(RID p_obstacle) const {
+ NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle);
+ ERR_FAIL_COND_V(obstacle == nullptr, false);
+
+ return obstacle->get_paused();
+}
+
COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");
NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle);
@@ -925,6 +956,18 @@ COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers) {
obstacle->set_avoidance_layers(p_layers);
}
+void GodotNavigationServer::parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {
+#ifndef _3D_DISABLED
+ NavigationMeshGenerator::get_singleton()->parse_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_root_node, p_callback);
+#endif
+}
+
+void GodotNavigationServer::bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback) {
+#ifndef _3D_DISABLED
+ NavigationMeshGenerator::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_callback);
+#endif
+}
+
COMMAND_1(free, RID, p_object) {
if (map_owner.owns(p_object)) {
NavMap *map = map_owner.get_or_null(p_object);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 1f2096b61a..6b394157bc 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -31,17 +31,17 @@
#ifndef GODOT_NAVIGATION_SERVER_H
#define GODOT_NAVIGATION_SERVER_H
-#include "core/templates/local_vector.h"
-#include "core/templates/rid.h"
-#include "core/templates/rid_owner.h"
-#include "servers/navigation_server_3d.h"
-
#include "nav_agent.h"
#include "nav_link.h"
#include "nav_map.h"
#include "nav_obstacle.h"
#include "nav_region.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/rid.h"
+#include "core/templates/rid_owner.h"
+#include "servers/navigation_server_3d.h"
+
/// The commands are functions executed during the `sync` phase.
#define MERGE_INTERNAL(A, B) A##B
@@ -184,6 +184,8 @@ public:
virtual bool agent_get_use_3d_avoidance(RID p_agent) const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
virtual RID agent_get_map(RID p_agent) const override;
+ COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused);
+ virtual bool agent_get_paused(RID p_agent) const override;
COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance);
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count);
COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon);
@@ -207,6 +209,8 @@ public:
virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const override;
COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map);
virtual RID obstacle_get_map(RID p_obstacle) const override;
+ COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused);
+ virtual bool obstacle_get_paused(RID p_obstacle) const override;
COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius);
COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity);
COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position);
@@ -214,6 +218,9 @@ public:
virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) override;
COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers);
+ virtual void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override;
+ virtual void bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override;
+
COMMAND_1(free, RID, p_object);
virtual void set_active(bool p_active) override;
diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp
index a0efe4c74c..19b73dc633 100644
--- a/modules/navigation/nav_agent.cpp
+++ b/modules/navigation/nav_agent.cpp
@@ -342,3 +342,23 @@ const Dictionary NavAgent::get_avoidance_data() const {
}
return _avoidance_data;
}
+
+void NavAgent::set_paused(bool p_paused) {
+ if (paused == p_paused) {
+ return;
+ }
+
+ paused = p_paused;
+
+ if (map) {
+ if (paused) {
+ map->remove_agent_as_controlled(this);
+ } else {
+ map->set_agent_as_controlled(this);
+ }
+ }
+}
+
+bool NavAgent::get_paused() const {
+ return paused;
+}
diff --git a/modules/navigation/nav_agent.h b/modules/navigation/nav_agent.h
index 497b239f84..9ab6f55544 100644
--- a/modules/navigation/nav_agent.h
+++ b/modules/navigation/nav_agent.h
@@ -31,11 +31,12 @@
#ifndef NAV_AGENT_H
#define NAV_AGENT_H
-#include "core/object/class_db.h"
-#include "core/templates/local_vector.h"
#include "nav_agent.h"
#include "nav_rid.h"
+#include "core/object/class_db.h"
+#include "core/templates/local_vector.h"
+
#include <Agent2d.h>
#include <Agent3d.h>
@@ -72,6 +73,7 @@ class NavAgent : public NavRid {
bool agent_dirty = true;
uint32_t map_update_id = 0;
+ bool paused = false;
public:
NavAgent();
@@ -137,6 +139,9 @@ public:
void set_avoidance_priority(real_t p_priority);
real_t get_avoidance_priority() const { return avoidance_priority; };
+ void set_paused(bool p_paused);
+ bool get_paused() const;
+
bool check_dirty();
// Updates this agent with rvo data after the rvo simulation avoidance step.
diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h
index b5cdc117f2..c28392acf7 100644
--- a/modules/navigation/nav_base.h
+++ b/modules/navigation/nav_base.h
@@ -33,6 +33,7 @@
#include "nav_rid.h"
#include "nav_utils.h"
+
#include "servers/navigation/navigation_utilities.h"
class NavMap;
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 7fd8f3c073..2595a02a61 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -30,13 +30,14 @@
#include "nav_map.h"
-#include "core/config/project_settings.h"
-#include "core/object/worker_thread_pool.h"
#include "nav_agent.h"
#include "nav_link.h"
#include "nav_obstacle.h"
#include "nav_region.h"
+#include "core/config/project_settings.h"
+#include "core/object/worker_thread_pool.h"
+
#include <Obstacle2d.h>
#define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a)))
@@ -627,6 +628,11 @@ bool NavMap::has_obstacle(NavObstacle *obstacle) const {
}
void NavMap::add_obstacle(NavObstacle *obstacle) {
+ if (obstacle->get_paused()) {
+ // No point in adding a paused obstacle, it will add itself when unpaused again.
+ return;
+ }
+
if (!has_obstacle(obstacle)) {
obstacles.push_back(obstacle);
obstacles_dirty = true;
@@ -643,6 +649,12 @@ void NavMap::remove_obstacle(NavObstacle *obstacle) {
void NavMap::set_agent_as_controlled(NavAgent *agent) {
remove_agent_as_controlled(agent);
+
+ if (agent->get_paused()) {
+ // No point in adding a paused agent, it will add itself when unpaused again.
+ return;
+ }
+
if (agent->get_use_3d_avoidance()) {
int64_t agent_3d_index = active_3d_avoidance_agents.find(agent);
if (agent_3d_index < 0) {
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index 8d529f464e..5d78c14627 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -32,16 +32,14 @@
#define NAV_MAP_H
#include "nav_rid.h"
+#include "nav_utils.h"
#include "core/math/math_defs.h"
#include "core/object/worker_thread_pool.h"
-#include "core/templates/rb_map.h"
-#include "nav_utils.h"
#include <KdTree2d.h>
-#include <RVOSimulator2d.h>
-
#include <KdTree3d.h>
+#include <RVOSimulator2d.h>
#include <RVOSimulator3d.h>
class NavLink;
diff --git a/modules/navigation/nav_obstacle.cpp b/modules/navigation/nav_obstacle.cpp
index 4241ddcd79..34e5f7aa85 100644
--- a/modules/navigation/nav_obstacle.cpp
+++ b/modules/navigation/nav_obstacle.cpp
@@ -186,6 +186,7 @@ void NavObstacle::internal_update_agent() {
agent->set_neighbor_distance(0.0);
agent->set_avoidance_priority(1.0);
agent->set_map(map);
+ agent->set_paused(paused);
agent->set_radius(radius);
agent->set_height(height);
agent->set_position(position);
@@ -194,3 +195,24 @@ void NavObstacle::internal_update_agent() {
agent->set_use_3d_avoidance(use_3d_avoidance);
}
}
+
+void NavObstacle::set_paused(bool p_paused) {
+ if (paused == p_paused) {
+ return;
+ }
+
+ paused = p_paused;
+
+ if (map) {
+ if (paused) {
+ map->remove_obstacle(this);
+ } else {
+ map->add_obstacle(this);
+ }
+ }
+ internal_update_agent();
+}
+
+bool NavObstacle::get_paused() const {
+ return paused;
+}
diff --git a/modules/navigation/nav_obstacle.h b/modules/navigation/nav_obstacle.h
index 93910898e9..eb44f63d03 100644
--- a/modules/navigation/nav_obstacle.h
+++ b/modules/navigation/nav_obstacle.h
@@ -31,9 +31,10 @@
#ifndef NAV_OBSTACLE_H
#define NAV_OBSTACLE_H
+#include "nav_rid.h"
+
#include "core/object/class_db.h"
#include "core/templates/local_vector.h"
-#include "nav_rid.h"
class NavAgent;
class NavMap;
@@ -55,6 +56,7 @@ class NavObstacle : public NavRid {
bool obstacle_dirty = true;
uint32_t map_update_id = 0;
+ bool paused = false;
public:
NavObstacle();
@@ -92,6 +94,9 @@ public:
void set_avoidance_layers(uint32_t p_layers);
uint32_t get_avoidance_layers() const { return avoidance_layers; };
+ void set_paused(bool p_paused);
+ bool get_paused() const;
+
bool check_dirty();
private:
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 72299e8874..0c3c1b56b6 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -31,11 +31,11 @@
#ifndef NAV_REGION_H
#define NAV_REGION_H
-#include "scene/resources/navigation_mesh.h"
-
#include "nav_base.h"
#include "nav_utils.h"
+#include "scene/resources/navigation_mesh.h"
+
class NavRegion : public NavBase {
NavMap *map = nullptr;
Transform3D transform;
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index fe63d67aba..88965cd439 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -43,6 +43,7 @@
#include "scene/resources/convex_polygon_shape_3d.h"
#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/height_map_shape_3d.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
@@ -466,52 +467,102 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
}
}
-void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh) {
- Vector<Vector3> nav_vertices;
+NavigationMeshGenerator *NavigationMeshGenerator::get_singleton() {
+ return singleton;
+}
- for (int i = 0; i < p_detail_mesh->nverts; i++) {
- const float *v = &p_detail_mesh->verts[i * 3];
- nav_vertices.push_back(Vector3(v[0], v[1], v[2]));
+NavigationMeshGenerator::NavigationMeshGenerator() {
+ singleton = this;
+}
+
+NavigationMeshGenerator::~NavigationMeshGenerator() {
+}
+
+void NavigationMeshGenerator::bake(const Ref<NavigationMesh> &p_navigation_mesh, Node *p_root_node) {
+ WARN_PRINT_ONCE("NavigationMeshGenerator::bake() is deprecated due to core threading changes. To upgrade existing code, first create a NavigationMeshSourceGeometryData3D resource. Use this resource with method parse_source_geometry_data() to parse the SceneTree for nodes that should contribute to the navigation mesh baking. The SceneTree parsing needs to happen on the main thread. After the parsing is finished use the resource with method bake_from_source_geometry_data() to bake a navigation mesh..");
+}
+
+void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_navigation_mesh) {
+ if (p_navigation_mesh.is_valid()) {
+ p_navigation_mesh->clear_polygons();
+ p_navigation_mesh->set_vertices(Vector<Vector3>());
}
- p_navigation_mesh->set_vertices(nav_vertices);
+}
- for (int i = 0; i < p_detail_mesh->nmeshes; i++) {
- const unsigned int *m = &p_detail_mesh->meshes[i * 4];
- const unsigned int bverts = m[0];
- const unsigned int btris = m[2];
- const unsigned int ntris = m[3];
- const unsigned char *tris = &p_detail_mesh->tris[btris * 4];
- for (unsigned int j = 0; j < ntris; j++) {
- Vector<int> nav_indices;
- nav_indices.resize(3);
- // Polygon order in recast is opposite than godot's
- nav_indices.write[0] = ((int)(bverts + tris[j * 4 + 0]));
- nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 2]));
- nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 1]));
- p_navigation_mesh->add_polygon(nav_indices);
+void NavigationMeshGenerator::parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {
+ ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred().");
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh.");
+ ERR_FAIL_COND_MSG(p_root_node == nullptr, "No parsing root node specified.");
+ ERR_FAIL_COND_MSG(!p_root_node->is_inside_tree(), "The root node needs to be inside the SceneTree.");
+
+ Vector<float> vertices;
+ Vector<int> indices;
+
+ List<Node *> parse_nodes;
+
+ if (p_navigation_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
+ parse_nodes.push_back(p_root_node);
+ } else {
+ p_root_node->get_tree()->get_nodes_in_group(p_navigation_mesh->get_source_group_name(), &parse_nodes);
+ }
+
+ Transform3D navmesh_xform = Transform3D();
+ if (Object::cast_to<Node3D>(p_root_node)) {
+ navmesh_xform = Object::cast_to<Node3D>(p_root_node)->get_global_transform().affine_inverse();
+ }
+ for (Node *E : parse_nodes) {
+ NavigationMesh::ParsedGeometryType geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ uint32_t collision_mask = p_navigation_mesh->get_collision_mask();
+ bool recurse_children = p_navigation_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
+ _parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children);
+ }
+
+ p_source_geometry_data->set_vertices(vertices);
+ p_source_geometry_data->set_indices(indices);
+
+ if (p_callback.is_valid()) {
+ Callable::CallError ce;
+ Variant result;
+ p_callback.callp(nullptr, 0, result, ce);
+ if (ce.error == Callable::CallError::CALL_OK) {
+ //
}
}
}
-void NavigationMeshGenerator::_build_recast_navigation_mesh(
- Ref<NavigationMesh> p_navigation_mesh,
-#ifdef TOOLS_ENABLED
- EditorProgress *ep,
-#endif
- rcHeightfield *hf,
- rcCompactHeightfield *chf,
- rcContourSet *cset,
- rcPolyMesh *poly_mesh,
- rcPolyMeshDetail *detail_mesh,
- Vector<float> &vertices,
- Vector<int> &indices) {
- rcContext ctx;
+void NavigationMeshGenerator::bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback) {
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh.");
+ ERR_FAIL_COND_MSG(!p_source_geometry_data.is_valid(), "Invalid NavigationMeshSourceGeometryData3D.");
+ ERR_FAIL_COND_MSG(!p_source_geometry_data->has_data(), "NavigationMeshSourceGeometryData3D is empty. Parse source geometry first.");
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Setting up Configuration..."), 1);
+ generator_mutex.lock();
+ if (baking_navmeshes.has(p_navigation_mesh)) {
+ generator_mutex.unlock();
+ ERR_FAIL_MSG("NavigationMesh is already baking. Wait for current bake to finish.");
+ } else {
+ baking_navmeshes.insert(p_navigation_mesh);
+ generator_mutex.unlock();
}
-#endif
+
+#ifndef _3D_DISABLED
+ const Vector<float> vertices = p_source_geometry_data->get_vertices();
+ const Vector<int> indices = p_source_geometry_data->get_indices();
+
+ if (vertices.size() < 3 || indices.size() < 3) {
+ return;
+ }
+
+ rcHeightfield *hf = nullptr;
+ rcCompactHeightfield *chf = nullptr;
+ rcContourSet *cset = nullptr;
+ rcPolyMesh *poly_mesh = nullptr;
+ rcPolyMeshDetail *detail_mesh = nullptr;
+ rcContext ctx;
+
+ // added to keep track of steps, no functionality right now
+ String bake_state = "";
+
+ bake_state = "Setting up Configuration..."; // step #1
const float *verts = vertices.ptr();
const int nverts = vertices.size() / 3;
@@ -581,11 +632,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.bmax[2] = cfg.bmin[2] + baking_aabb.size[2];
}
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Calculating grid size..."), 2);
- }
-#endif
+ bake_state = "Calculating grid size..."; // step #2
rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
// ~30000000 seems to be around sweetspot where Editor baking breaks
@@ -596,21 +643,13 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
"\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry.");
}
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Creating heightfield..."), 3);
- }
-#endif
+ bake_state = "Creating heightfield..."; // step #3
hf = rcAllocHeightfield();
ERR_FAIL_COND(!hf);
ERR_FAIL_COND(!rcCreateHeightfield(&ctx, *hf, cfg.width, cfg.height, cfg.bmin, cfg.bmax, cfg.cs, cfg.ch));
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Marking walkable triangles..."), 4);
- }
-#endif
+ bake_state = "Marking walkable triangles..."; // step #4
{
Vector<unsigned char> tri_areas;
tri_areas.resize(ntris);
@@ -633,11 +672,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
rcFilterWalkableLowHeightSpans(&ctx, cfg.walkableHeight, *hf);
}
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Constructing compact heightfield..."), 5);
- }
-#endif
+ bake_state = "Constructing compact heightfield..."; // step #5
chf = rcAllocCompactHeightfield();
@@ -647,19 +682,11 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
rcFreeHeightField(hf);
hf = nullptr;
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Eroding walkable area..."), 6);
- }
-#endif
+ bake_state = "Eroding walkable area..."; // step #6
ERR_FAIL_COND(!rcErodeWalkableArea(&ctx, cfg.walkableRadius, *chf));
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Partitioning..."), 7);
- }
-#endif
+ bake_state = "Partitioning..."; // step #7
if (p_navigation_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) {
ERR_FAIL_COND(!rcBuildDistanceField(&ctx, *chf));
@@ -670,22 +697,14 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
ERR_FAIL_COND(!rcBuildLayerRegions(&ctx, *chf, 0, cfg.minRegionArea));
}
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Creating contours..."), 8);
- }
-#endif
+ bake_state = "Creating contours..."; // step #8
cset = rcAllocContourSet();
ERR_FAIL_COND(!cset);
ERR_FAIL_COND(!rcBuildContours(&ctx, *chf, cfg.maxSimplificationError, cfg.maxEdgeLen, *cset));
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Creating polymesh..."), 9);
- }
-#endif
+ bake_state = "Creating polymesh..."; // step #9
poly_mesh = rcAllocPolyMesh();
ERR_FAIL_COND(!poly_mesh);
@@ -700,128 +719,63 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
rcFreeContourSet(cset);
cset = nullptr;
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Converting to native navigation mesh..."), 10);
- }
-#endif
-
- _convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_navigation_mesh);
-
- rcFreePolyMesh(poly_mesh);
- poly_mesh = nullptr;
- rcFreePolyMeshDetail(detail_mesh);
- detail_mesh = nullptr;
-}
-
-NavigationMeshGenerator *NavigationMeshGenerator::get_singleton() {
- return singleton;
-}
-
-NavigationMeshGenerator::NavigationMeshGenerator() {
- singleton = this;
-}
-
-NavigationMeshGenerator::~NavigationMeshGenerator() {
-}
-
-void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) {
- ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh.");
-
-#ifdef TOOLS_ENABLED
- EditorProgress *ep(nullptr);
- // FIXME
-#endif
-#if 0
- // After discussion on devchat disabled EditorProgress for now as it is not thread-safe and uses hacks and Main::iteration() for steps.
- // EditorProgress randomly crashes the Engine when the bake function is used with a thread e.g. inside Editor with a tool script and procedural navigation
- // This was not a problem in older versions as previously Godot was unable to (re)bake NavigationMesh at runtime.
- // If EditorProgress is fixed and made thread-safe this should be enabled again.
- if (Engine::get_singleton()->is_editor_hint()) {
- ep = memnew(EditorProgress("bake", TTR("Navigation Mesh Generator Setup:"), 11));
- }
-
- if (ep) {
- ep->step(TTR("Parsing Geometry..."), 0);
- }
-#endif
+ bake_state = "Converting to native navigation mesh..."; // step #10
- Vector<float> vertices;
- Vector<int> indices;
-
- List<Node *> parse_nodes;
+ Vector<Vector3> nav_vertices;
- if (p_navigation_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
- parse_nodes.push_back(p_root_node);
- } else {
- p_root_node->get_tree()->get_nodes_in_group(p_navigation_mesh->get_source_group_name(), &parse_nodes);
+ for (int i = 0; i < detail_mesh->nverts; i++) {
+ const float *v = &detail_mesh->verts[i * 3];
+ nav_vertices.push_back(Vector3(v[0], v[1], v[2]));
}
+ p_navigation_mesh->set_vertices(nav_vertices);
- Transform3D navmesh_xform = Object::cast_to<Node3D>(p_root_node)->get_global_transform().affine_inverse();
- for (Node *E : parse_nodes) {
- NavigationMesh::ParsedGeometryType geometry_type = p_navigation_mesh->get_parsed_geometry_type();
- uint32_t collision_mask = p_navigation_mesh->get_collision_mask();
- bool recurse_children = p_navigation_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
- _parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children);
+ for (int i = 0; i < detail_mesh->nmeshes; i++) {
+ const unsigned int *detail_mesh_m = &detail_mesh->meshes[i * 4];
+ const unsigned int detail_mesh_bverts = detail_mesh_m[0];
+ const unsigned int detail_mesh_m_btris = detail_mesh_m[2];
+ const unsigned int detail_mesh_ntris = detail_mesh_m[3];
+ const unsigned char *detail_mesh_tris = &detail_mesh->tris[detail_mesh_m_btris * 4];
+ for (unsigned int j = 0; j < detail_mesh_ntris; j++) {
+ Vector<int> nav_indices;
+ nav_indices.resize(3);
+ // Polygon order in recast is opposite than godot's
+ nav_indices.write[0] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 0]));
+ nav_indices.write[1] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 2]));
+ nav_indices.write[2] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 1]));
+ p_navigation_mesh->add_polygon(nav_indices);
+ }
}
- if (vertices.size() > 0 && indices.size() > 0) {
- rcHeightfield *hf = nullptr;
- rcCompactHeightfield *chf = nullptr;
- rcContourSet *cset = nullptr;
- rcPolyMesh *poly_mesh = nullptr;
- rcPolyMeshDetail *detail_mesh = nullptr;
-
- _build_recast_navigation_mesh(
- p_navigation_mesh,
-#ifdef TOOLS_ENABLED
- ep,
-#endif
- hf,
- chf,
- cset,
- poly_mesh,
- detail_mesh,
- vertices,
- indices);
-
- rcFreeHeightField(hf);
- hf = nullptr;
+ bake_state = "Cleanup..."; // step #11
- rcFreeCompactHeightfield(chf);
- chf = nullptr;
-
- rcFreeContourSet(cset);
- cset = nullptr;
-
- rcFreePolyMesh(poly_mesh);
- poly_mesh = nullptr;
+ rcFreePolyMesh(poly_mesh);
+ poly_mesh = nullptr;
+ rcFreePolyMeshDetail(detail_mesh);
+ detail_mesh = nullptr;
- rcFreePolyMeshDetail(detail_mesh);
- detail_mesh = nullptr;
- }
+ bake_state = "Baking finished."; // step #12
+#endif // _3D_DISABLED
-#ifdef TOOLS_ENABLED
- if (ep) {
- ep->step(TTR("Done!"), 11);
- }
+ generator_mutex.lock();
+ baking_navmeshes.erase(p_navigation_mesh);
+ generator_mutex.unlock();
- if (ep) {
- memdelete(ep);
- }
-#endif
-}
-
-void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_navigation_mesh) {
- if (p_navigation_mesh.is_valid()) {
- p_navigation_mesh->clear_polygons();
- p_navigation_mesh->set_vertices(Vector<Vector3>());
+ if (p_callback.is_valid()) {
+ Callable::CallError ce;
+ Variant result;
+ p_callback.callp(nullptr, 0, result, ce);
+ if (ce.error == Callable::CallError::CALL_OK) {
+ //
+ }
}
}
void NavigationMeshGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("bake", "navigation_mesh", "root_node"), &NavigationMeshGenerator::bake);
ClassDB::bind_method(D_METHOD("clear", "navigation_mesh"), &NavigationMeshGenerator::clear);
+
+ ClassDB::bind_method(D_METHOD("parse_source_geometry_data", "navigation_mesh", "source_geometry_data", "root_node", "callback"), &NavigationMeshGenerator::parse_source_geometry_data, DEFVAL(Callable()));
+ ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data", "navigation_mesh", "source_geometry_data", "callback"), &NavigationMeshGenerator::bake_from_source_geometry_data, DEFVAL(Callable()));
}
#endif
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 4399c422e2..4bf2b64f44 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -34,18 +34,20 @@
#ifndef _3D_DISABLED
#include "scene/3d/navigation_region_3d.h"
+#include "scene/resources/navigation_mesh.h"
#include <Recast.h>
-#ifdef TOOLS_ENABLED
-struct EditorProgress;
-#endif
+class NavigationMeshSourceGeometryData3D;
class NavigationMeshGenerator : public Object {
GDCLASS(NavigationMeshGenerator, Object);
+ Mutex generator_mutex;
static NavigationMeshGenerator *singleton;
+ HashSet<Ref<NavigationMesh>> baking_navmeshes;
+
protected:
static void _bind_methods();
@@ -55,28 +57,17 @@ protected:
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
- static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh);
- static void _build_recast_navigation_mesh(
- Ref<NavigationMesh> p_navigation_mesh,
-#ifdef TOOLS_ENABLED
- EditorProgress *ep,
-#endif
- rcHeightfield *hf,
- rcCompactHeightfield *chf,
- rcContourSet *cset,
- rcPolyMesh *poly_mesh,
- rcPolyMeshDetail *detail_mesh,
- Vector<float> &vertices,
- Vector<int> &indices);
-
public:
static NavigationMeshGenerator *get_singleton();
NavigationMeshGenerator();
~NavigationMeshGenerator();
- void bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node);
+ void bake(const Ref<NavigationMesh> &p_navigation_mesh, Node *p_root_node);
void clear(Ref<NavigationMesh> p_navigation_mesh);
+
+ void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable());
+ void bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable());
};
#endif
diff --git a/modules/navigation/register_types.cpp b/modules/navigation/register_types.cpp
index 6ba5e90c2e..1401833d0e 100644
--- a/modules/navigation/register_types.cpp
+++ b/modules/navigation/register_types.cpp
@@ -30,9 +30,6 @@
#include "register_types.h"
-#include "core/config/engine.h"
-#include "servers/navigation_server_3d.h"
-
#include "godot_navigation_server.h"
#ifndef _3D_DISABLED
@@ -43,6 +40,9 @@
#include "editor/navigation_mesh_editor_plugin.h"
#endif
+#include "core/config/engine.h"
+#include "servers/navigation_server_3d.h"
+
#ifndef _3D_DISABLED
NavigationMeshGenerator *_nav_mesh_generator = nullptr;
#endif
diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp
index 462cc50112..91e9f7d477 100644
--- a/modules/noise/editor/noise_editor_plugin.cpp
+++ b/modules/noise/editor/noise_editor_plugin.cpp
@@ -32,14 +32,14 @@
#ifdef TOOLS_ENABLED
+#include "../noise.h"
+#include "../noise_texture_2d.h"
+
#include "editor/editor_inspector.h"
#include "editor/editor_scale.h"
#include "scene/gui/button.h"
#include "scene/gui/texture_rect.h"
-#include "modules/noise/noise.h"
-#include "modules/noise/noise_texture_2d.h"
-
class NoisePreview : public Control {
GDCLASS(NoisePreview, Control)
diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h
index 0e6a4606ac..c63f7d7d29 100644
--- a/modules/noise/fastnoise_lite.h
+++ b/modules/noise/fastnoise_lite.h
@@ -31,9 +31,10 @@
#ifndef FASTNOISE_LITE_H
#define FASTNOISE_LITE_H
+#include "noise.h"
+
#include "core/io/image.h"
#include "core/object/ref_counted.h"
-#include "noise.h"
#include "scene/resources/gradient.h"
#include <thirdparty/noise/FastNoiseLite.h>
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index e4b2e0b4ac..a7176e0816 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -30,9 +30,10 @@
#include "noise_texture_2d.h"
-#include "core/core_string_names.h"
#include "noise.h"
+#include "core/core_string_names.h"
+
NoiseTexture2D::NoiseTexture2D() {
noise = Ref<Noise>();
diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp
index 25d75b8ffb..f6c67b0f2d 100644
--- a/modules/noise/noise_texture_3d.cpp
+++ b/modules/noise/noise_texture_3d.cpp
@@ -30,9 +30,10 @@
#include "noise_texture_3d.h"
-#include "core/core_string_names.h"
#include "noise.h"
+#include "core/core_string_names.h"
+
NoiseTexture3D::NoiseTexture3D() {
noise = Ref<Noise>();
diff --git a/modules/noise/register_types.cpp b/modules/noise/register_types.cpp
index f48d4e7e4d..29eb42522f 100644
--- a/modules/noise/register_types.cpp
+++ b/modules/noise/register_types.cpp
@@ -36,10 +36,13 @@
#include "noise_texture_3d.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_plugin.h"
#include "editor/noise_editor_plugin.h"
#endif
+#ifdef TOOLS_ENABLED
+#include "editor/editor_plugin.h"
+#endif
+
void initialize_noise_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
GDREGISTER_CLASS(NoiseTexture3D);
diff --git a/modules/noise/tests/test_fastnoise_lite.h b/modules/noise/tests/test_fastnoise_lite.h
index 0a435c6a5c..6e2e263e03 100644
--- a/modules/noise/tests/test_fastnoise_lite.h
+++ b/modules/noise/tests/test_fastnoise_lite.h
@@ -31,9 +31,9 @@
#ifndef TEST_FASTNOISE_LITE_H
#define TEST_FASTNOISE_LITE_H
-#include "tests/test_macros.h"
+#include "../fastnoise_lite.h"
-#include "modules/noise/fastnoise_lite.h"
+#include "tests/test_macros.h"
namespace TestFastNoiseLite {
diff --git a/modules/noise/tests/test_noise_texture_2d.h b/modules/noise/tests/test_noise_texture_2d.h
index 9e280b5d97..e2ec39ef48 100644
--- a/modules/noise/tests/test_noise_texture_2d.h
+++ b/modules/noise/tests/test_noise_texture_2d.h
@@ -31,9 +31,9 @@
#ifndef TEST_NOISE_TEXTURE_2D_H
#define TEST_NOISE_TEXTURE_2D_H
-#include "tests/test_macros.h"
+#include "../noise_texture_2d.h"
-#include "modules/noise/noise_texture_2d.h"
+#include "tests/test_macros.h"
namespace TestNoiseTexture2D {
diff --git a/modules/noise/tests/test_noise_texture_3d.h b/modules/noise/tests/test_noise_texture_3d.h
index b46d386296..a612f2920a 100644
--- a/modules/noise/tests/test_noise_texture_3d.h
+++ b/modules/noise/tests/test_noise_texture_3d.h
@@ -31,9 +31,9 @@
#ifndef TEST_NOISE_TEXTURE_3D_H
#define TEST_NOISE_TEXTURE_3D_H
-#include "tests/test_macros.h"
+#include "../noise_texture_3d.h"
-#include "modules/noise/noise_texture_3d.h"
+#include "tests/test_macros.h"
namespace TestNoiseTexture3D {
diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp
index d473f3b4a0..fb29493ca9 100644
--- a/modules/ogg/ogg_packet_sequence.cpp
+++ b/modules/ogg/ogg_packet_sequence.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "ogg_packet_sequence.h"
+
#include "core/variant/typed_array.h"
void OggPacketSequence::push_page(int64_t p_granule_pos, const Vector<PackedByteArray> &p_data) {
diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp
index a768eb2326..8a6b7a8b62 100644
--- a/modules/openxr/action_map/openxr_action.cpp
+++ b/modules/openxr/action_map/openxr_action.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_action.h"
+
#include "openxr_action_set.h"
void OpenXRAction::_bind_methods() {
diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h
index 0c88fac5ec..678b3d7fbc 100644
--- a/modules/openxr/action_map/openxr_action_map.h
+++ b/modules/openxr/action_map/openxr_action_map.h
@@ -31,12 +31,12 @@
#ifndef OPENXR_ACTION_MAP_H
#define OPENXR_ACTION_MAP_H
-#include "core/io/resource.h"
-
#include "openxr_action.h"
#include "openxr_action_set.h"
#include "openxr_interaction_profile.h"
+#include "core/io/resource.h"
+
class OpenXRActionMap : public Resource {
GDCLASS(OpenXRActionMap, Resource);
diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h
index 0cb342784a..c63d50bc19 100644
--- a/modules/openxr/action_map/openxr_action_set.h
+++ b/modules/openxr/action_map/openxr_action_set.h
@@ -31,10 +31,10 @@
#ifndef OPENXR_ACTION_SET_H
#define OPENXR_ACTION_SET_H
-#include "core/io/resource.h"
-
#include "openxr_action.h"
+#include "core/io/resource.h"
+
class OpenXRActionSet : public Resource {
GDCLASS(OpenXRActionSet, Resource);
diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h
index d7253af316..4a82785f14 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.h
+++ b/modules/openxr/action_map/openxr_interaction_profile.h
@@ -31,11 +31,11 @@
#ifndef OPENXR_INTERACTION_PROFILE_H
#define OPENXR_INTERACTION_PROFILE_H
-#include "core/io/resource.h"
-
#include "openxr_action.h"
#include "openxr_interaction_profile_meta_data.h"
+#include "core/io/resource.h"
+
class OpenXRIPBinding : public Resource {
GDCLASS(OpenXRIPBinding, Resource);
diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
index 70879c6b6b..11449bdfb4 100644
--- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_interaction_profile_meta_data.h"
+
#include "../openxr_api.h"
OpenXRInteractionProfileMetaData *OpenXRInteractionProfileMetaData::singleton = nullptr;
diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.h b/modules/openxr/action_map/openxr_interaction_profile_meta_data.h
index 16ee88bbf9..3eab2139ff 100644
--- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.h
+++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.h
@@ -31,8 +31,6 @@
#ifndef OPENXR_INTERACTION_PROFILE_META_DATA_H
#define OPENXR_INTERACTION_PROFILE_META_DATA_H
-#include "openxr_action.h"
-
///////////////////////////////////////////////////////////////////////////
// Stores available interaction profile meta data
//
@@ -53,6 +51,8 @@
// are supported but otherwise action types should match between action and
// input/output paths.
+#include "openxr_action.h"
+
#include "core/object/object.h"
#define XR_PATH_UNSUPPORTED_NAME "unsupported"
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
index 765b3ef378..11d1fd657a 100644
--- a/modules/openxr/editor/openxr_action_editor.h
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -32,6 +32,7 @@
#define OPENXR_ACTION_EDITOR_H
#include "../action_map/openxr_action.h"
+
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index a04bae4a6e..22e8853c8c 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -32,9 +32,9 @@
#define OPENXR_ACTION_MAP_EDITOR_H
#include "../action_map/openxr_action_map.h"
-#include "../editor/openxr_action_set_editor.h"
-#include "../editor/openxr_interaction_profile_editor.h"
-#include "../editor/openxr_select_interaction_profile_dialog.h"
+#include "openxr_action_set_editor.h"
+#include "openxr_interaction_profile_editor.h"
+#include "openxr_select_interaction_profile_dialog.h"
#include "editor/editor_plugin.h"
#include "editor/editor_undo_redo_manager.h"
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index bcb0f5f8b1..6a63720257 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_action_set_editor.h"
+
#include "openxr_action_editor.h"
void OpenXRActionSetEditor::_bind_methods() {
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
index 129f800abe..3261f3a29e 100644
--- a/modules/openxr/editor/openxr_action_set_editor.h
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -34,6 +34,7 @@
#include "../action_map/openxr_action_map.h"
#include "../action_map/openxr_action_set.h"
#include "openxr_action_editor.h"
+
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/line_edit.h"
diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp
index 75becf035a..51ebbcf44a 100644
--- a/modules/openxr/editor/openxr_editor_plugin.cpp
+++ b/modules/openxr/editor/openxr_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "openxr_editor_plugin.h"
#include "../action_map/openxr_action_map.h"
+
#include "editor/editor_node.h"
void OpenXREditorPlugin::edit(Object *p_node) {
diff --git a/modules/openxr/editor/openxr_editor_plugin.h b/modules/openxr/editor/openxr_editor_plugin.h
index ef75385233..9764f8fe21 100644
--- a/modules/openxr/editor/openxr_editor_plugin.h
+++ b/modules/openxr/editor/openxr_editor_plugin.h
@@ -31,9 +31,10 @@
#ifndef OPENXR_EDITOR_PLUGIN_H
#define OPENXR_EDITOR_PLUGIN_H
-#include "editor/editor_plugin.h"
#include "openxr_action_map_editor.h"
+#include "editor/editor_plugin.h"
+
class OpenXREditorPlugin : public EditorPlugin {
GDCLASS(OpenXREditorPlugin, EditorPlugin);
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index 6a848dd430..1f63399ee7 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_interaction_profile_editor.h"
+
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index fa25a000a9..b9b3fbd81d 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -34,11 +34,11 @@
#include "../action_map/openxr_action_map.h"
#include "../action_map/openxr_interaction_profile.h"
#include "../action_map/openxr_interaction_profile_meta_data.h"
+#include "openxr_select_action_dialog.h"
+
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/scroll_container.h"
-#include "openxr_select_action_dialog.h"
-
class OpenXRInteractionProfileEditorBase : public ScrollContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp
index b7dd7d5def..8eec54be63 100644
--- a/modules/openxr/editor/openxr_select_action_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_action_dialog.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_select_action_dialog.h"
-#include "editor/editor_node.h"
void OpenXRSelectActionDialog::_bind_methods() {
ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action")));
diff --git a/modules/openxr/editor/openxr_select_action_dialog.h b/modules/openxr/editor/openxr_select_action_dialog.h
index 4d8eddf3e5..cf7a7a1939 100644
--- a/modules/openxr/editor/openxr_select_action_dialog.h
+++ b/modules/openxr/editor/openxr_select_action_dialog.h
@@ -32,6 +32,7 @@
#define OPENXR_SELECT_ACTION_DIALOG_H
#include "../action_map/openxr_action_map.h"
+
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
index 4826a23a78..aae0368f67 100644
--- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
@@ -32,6 +32,7 @@
#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
#include "../action_map/openxr_interaction_profile_meta_data.h"
+
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp
index 4465daf22a..98687d5f20 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/openxr_android_extension.cpp
@@ -29,12 +29,14 @@
/**************************************************************************/
#include "openxr_android_extension.h"
+
+#include "../openxr_api.h"
+
#include "java_godot_wrapper.h"
#include "os_android.h"
#include "thread_jandroid.h"
#include <jni.h>
-#include <modules/openxr/openxr_api.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h
index 2f0869374e..d77ae06174 100644
--- a/modules/openxr/extensions/openxr_composition_layer_provider.h
+++ b/modules/openxr/extensions/openxr_composition_layer_provider.h
@@ -32,6 +32,7 @@
#define OPENXR_COMPOSITION_LAYER_PROVIDER_H
#include "openxr_extension_wrapper.h"
+
#include <openxr/openxr.h>
// Interface for OpenXR extensions that provide a composition layer.
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 2c855c3cde..920bfe74b7 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -37,6 +37,7 @@
#include "core/templates/rid.h"
#include "thirdparty/openxr/src/common/xr_linear.h"
+
#include <openxr/openxr.h>
class OpenXRAPI;
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
index 0e814cbb13..d8015fe600 100644
--- a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
@@ -38,7 +38,6 @@
#include "../openxr_api.h"
#include "../util.h"
-
#include "openxr_extension_wrapper.h"
class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper {
diff --git a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h
index c01394529e..619313809d 100644
--- a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h
@@ -33,7 +33,6 @@
#include "../openxr_api.h"
#include "../util.h"
-
#include "openxr_composition_layer_provider.h"
#include "openxr_extension_wrapper.h"
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
index 4dac7bed4f..6fffa1ed07 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "openxr_hand_tracking_extension.h"
+
#include "../openxr_api.h"
+
#include "core/string/print_string.h"
#include "servers/xr_server.h"
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h
index 5ab44ed969..e86831e71b 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.h
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h
@@ -31,9 +31,8 @@
#ifndef OPENXR_HAND_TRACKING_EXTENSION_H
#define OPENXR_HAND_TRACKING_EXTENSION_H
-#include "openxr_extension_wrapper.h"
-
#include "../util.h"
+#include "openxr_extension_wrapper.h"
#define MAX_OPENXR_TRACKED_HANDS 2
diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp
index 116762ee8d..51364d83d8 100644
--- a/modules/openxr/extensions/openxr_htc_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_htc_controller_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
HashMap<String, bool *> OpenXRHTCControllerExtension::get_requested_extensions() {
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index 1d2bd11a00..087631a8b9 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "openxr_htc_vive_tracker_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
+
#include "core/string/print_string.h"
HashMap<String, bool *> OpenXRHTCViveTrackerExtension::get_requested_extensions() {
diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
index aff92ee651..8b8662cfcb 100644
--- a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_huawei_controller_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
HashMap<String, bool *> OpenXRHuaweiControllerExtension::get_requested_extensions() {
diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
index ae372f69b3..7dad8deb8c 100644
--- a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_ml2_controller_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
HashMap<String, bool *> OpenXRML2ControllerExtension::get_requested_extensions() {
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp
index 83d31036a4..39b5c61e8e 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/openxr_opengl_extension.cpp
@@ -28,10 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
+#include "openxr_opengl_extension.h"
+
#ifdef GLES3_ENABLED
-#include "../extensions/openxr_opengl_extension.h"
#include "../openxr_util.h"
+
#include "drivers/gles3/effects/copy_effects.h"
#include "drivers/gles3/storage/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h
index 29a9f35c51..598d3415ad 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.h
+++ b/modules/openxr/extensions/openxr_opengl_extension.h
@@ -33,11 +33,11 @@
#ifdef GLES3_ENABLED
-#include "core/templates/vector.h"
-#include "openxr_extension_wrapper.h"
-
#include "../openxr_api.h"
#include "../util.h"
+#include "openxr_extension_wrapper.h"
+
+#include "core/templates/vector.h"
#ifdef ANDROID_ENABLED
#define XR_USE_GRAPHICS_API_OPENGL_ES
@@ -61,6 +61,7 @@
#define GL3_PROTOTYPES 1
#include "thirdparty/glad/glad/gl.h"
#include "thirdparty/glad/glad/glx.h"
+
#include <X11/Xlib.h>
#endif
@@ -69,7 +70,7 @@
#include <jni.h>
#endif
-// include platform dependent structs
+// Include platform dependent structs.
#include <openxr/openxr_platform.h>
class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.cpp b/modules/openxr/extensions/openxr_palm_pose_extension.cpp
index 75117e8db3..07446c8def 100644
--- a/modules/openxr/extensions/openxr_palm_pose_extension.cpp
+++ b/modules/openxr/extensions/openxr_palm_pose_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_palm_pose_extension.h"
+
#include "core/string/print_string.h"
OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::singleton = nullptr;
diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.cpp b/modules/openxr/extensions/openxr_pico_controller_extension.cpp
index f2fcf22ce2..8be961a68e 100644
--- a/modules/openxr/extensions/openxr_pico_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_pico_controller_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_pico_controller_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
// Pico controllers are not part of the OpenXR spec at the time of writing this
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index d5739db23f..90c1c62050 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -28,10 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "core/string/print_string.h"
+#include "openxr_vulkan_extension.h"
-#include "../extensions/openxr_vulkan_extension.h"
#include "../openxr_util.h"
+
+#include "core/string/print_string.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index 013a8d5a51..4add6f6fa2 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -31,15 +31,14 @@
#ifndef OPENXR_VULKAN_EXTENSION_H
#define OPENXR_VULKAN_EXTENSION_H
-#include "core/templates/vector.h"
+#include "../openxr_api.h"
+#include "../util.h"
#include "openxr_extension_wrapper.h"
+#include "core/templates/vector.h"
#include "drivers/vulkan/vulkan_context.h"
-#include "../openxr_api.h"
-#include "../util.h"
-
-// need to include Vulkan so we know of type definitions
+// Need to include Vulkan so we know of type definitions.
#define XR_USE_GRAPHICS_API_VULKAN
#ifdef WINDOWS_ENABLED
@@ -53,7 +52,7 @@
#include <jni.h>
#endif
-// include platform dependent structs
+// Include platform dependent structs.
#include <openxr/openxr_platform.h>
class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
index 7017496d75..a9b27013f1 100644
--- a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_wmr_controller_extension.h"
+
#include "../action_map/openxr_interaction_profile_meta_data.h"
HashMap<String, bool *> OpenXRWMRControllerExtension::get_requested_extensions() {
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 5879fbd460..21d9203ead 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -29,6 +29,8 @@
/**************************************************************************/
#include "openxr_api.h"
+
+#include "openxr_interface.h"
#include "openxr_util.h"
#include "core/config/engine.h"
@@ -40,10 +42,6 @@
#include "editor/editor_settings.h"
#endif
-#ifdef ANDROID_ENABLED
-#define OPENXR_LOADER_NAME "libopenxr_loader.so"
-#endif
-
// We need to have all the graphics API defines before the Vulkan or OpenGL
// extensions are included, otherwise we'll only get one graphics API.
#ifdef VULKAN_ENABLED
@@ -65,6 +63,7 @@
#define GL3_PROTOTYPES 1
#include "thirdparty/glad/glad/gl.h"
#include "thirdparty/glad/glad/glx.h"
+
#include <X11/Xlib.h>
#endif // X11_ENABLED
#endif // GLES_ENABLED
@@ -81,7 +80,9 @@
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
-#include "modules/openxr/openxr_interface.h"
+#ifdef ANDROID_ENABLED
+#define OPENXR_LOADER_NAME "libopenxr_loader.so"
+#endif
OpenXRAPI *OpenXRAPI::singleton = nullptr;
Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 292e54228d..96af2bfc49 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -31,6 +31,11 @@
#ifndef OPENXR_API_H
#define OPENXR_API_H
+#include "action_map/openxr_action.h"
+#include "extensions/openxr_composition_layer_provider.h"
+#include "extensions/openxr_extension_wrapper.h"
+#include "util.h"
+
#include "core/error/error_macros.h"
#include "core/math/projection.h"
#include "core/math/transform_3d.h"
@@ -44,14 +49,8 @@
#include "servers/xr/xr_pose.h"
#include "thirdparty/openxr/src/common/xr_linear.h"
-#include <openxr/openxr.h>
-#include "action_map/openxr_action.h"
-
-#include "extensions/openxr_composition_layer_provider.h"
-#include "extensions/openxr_extension_wrapper.h"
-
-#include "util.h"
+#include <openxr/openxr.h>
// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing structs which ensures zeroing out unspecified members.
// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set.
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index f36318530c..39cc68ae9b 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -31,13 +31,12 @@
#ifndef OPENXR_INTERFACE_H
#define OPENXR_INTERFACE_H
-#include "servers/xr/xr_interface.h"
-#include "servers/xr/xr_positional_tracker.h"
-
#include "action_map/openxr_action_map.h"
+#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
#include "openxr_api.h"
-#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
+#include "servers/xr/xr_interface.h"
+#include "servers/xr/xr_positional_tracker.h"
// declare some default strings
#define INTERACTION_PROFILE_NONE "/interaction_profiles/none"
diff --git a/modules/openxr/openxr_util.cpp b/modules/openxr/openxr_util.cpp
index 926e918390..0c5cdd7113 100644
--- a/modules/openxr/openxr_util.cpp
+++ b/modules/openxr/openxr_util.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "openxr_util.h"
+
#include <openxr/openxr_reflection.h>
#define XR_ENUM_CASE_STR(name, val) \
diff --git a/modules/openxr/openxr_util.h b/modules/openxr/openxr_util.h
index 7e7a6a1880..8ad68c0b02 100644
--- a/modules/openxr/openxr_util.h
+++ b/modules/openxr/openxr_util.h
@@ -32,6 +32,7 @@
#define OPENXR_UTIL_H
#include "core/string/ustring.h"
+
#include <openxr/openxr.h>
class OpenXRUtil {
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index b7d239fc73..27b179a788 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -29,23 +29,15 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/config/project_settings.h"
-#include "main/main.h"
-
-#include "openxr_interface.h"
#include "action_map/openxr_action.h"
#include "action_map/openxr_action_map.h"
#include "action_map/openxr_action_set.h"
#include "action_map/openxr_interaction_profile.h"
#include "action_map/openxr_interaction_profile_meta_data.h"
-
+#include "openxr_interface.h"
#include "scene/openxr_hand.h"
-#ifdef ANDROID_ENABLED
-#include "extensions/openxr_android_extension.h"
-#endif
-
#include "extensions/openxr_composition_layer_depth_extension.h"
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
@@ -58,15 +50,26 @@
#include "extensions/openxr_pico_controller_extension.h"
#include "extensions/openxr_wmr_controller_extension.h"
+#ifdef TOOLS_ENABLED
+#include "editor/openxr_editor_plugin.h"
+#endif
+
+#ifdef ANDROID_ENABLED
+#include "extensions/openxr_android_extension.h"
+#endif
+
+#include "core/config/project_settings.h"
+#include "main/main.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
static OpenXRAPI *openxr_api = nullptr;
static OpenXRInteractionProfileMetaData *openxr_interaction_profile_meta_data = nullptr;
static Ref<OpenXRInterface> openxr_interface;
#ifdef TOOLS_ENABLED
-
-#include "editor/editor_node.h"
-#include "editor/openxr_editor_plugin.h"
-
static void _editor_init() {
if (OpenXRAPI::openxr_is_enabled(false)) {
// Only add our OpenXR action map editor if OpenXR is enabled for our project
@@ -81,7 +84,6 @@ static void _editor_init() {
EditorNode::get_singleton()->add_editor_plugin(openxr_plugin);
}
}
-
#endif
void initialize_openxr_module(ModuleInitializationLevel p_level) {
diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp
index e341d2b1d4..91571a556d 100644
--- a/modules/openxr/scene/openxr_hand.cpp
+++ b/modules/openxr/scene/openxr_hand.cpp
@@ -28,10 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
+#include "openxr_hand.h"
+
#include "../extensions/openxr_hand_tracking_extension.h"
#include "../openxr_api.h"
-#include "openxr_hand.h"
#include "scene/3d/skeleton_3d.h"
#include "servers/xr_server.h"
diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h
index e79cbe2cfe..7bec3959d8 100644
--- a/modules/openxr/scene/openxr_hand.h
+++ b/modules/openxr/scene/openxr_hand.h
@@ -34,6 +34,8 @@
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
+#include <openxr/openxr.h>
+
class OpenXRAPI;
class OpenXRHandTrackingExtension;
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index 8c03115f05..69fbf87483 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "raycast_occlusion_cull.h"
+
#include "core/config/project_settings.h"
#include "core/object/worker_thread_pool.h"
#include "core/templates/local_vector.h"
diff --git a/modules/raycast/static_raycaster_embree.cpp b/modules/raycast/static_raycaster_embree.cpp
index b2e58812bd..f9076d30dd 100644
--- a/modules/raycast/static_raycaster_embree.cpp
+++ b/modules/raycast/static_raycaster_embree.cpp
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef TOOLS_ENABLED
-
#include "static_raycaster_embree.h"
+#ifdef TOOLS_ENABLED
+
#ifdef __SSE2__
#include <pmmintrin.h>
#endif
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 8d1e92b4e3..704c107f20 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "regex.h"
+
#include "core/os/memory.h"
extern "C" {
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 2ed20c9b14..13476d69de 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -33,7 +33,7 @@
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
-#include "core/templates/rb_map.h"
+#include "core/templates/hash_map.h"
#include "core/templates/vector.h"
#include "core/variant/array.h"
#include "core/variant/dictionary.h"
diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp
index 715e98a79a..9e3a296ce3 100644
--- a/modules/regex/register_types.cpp
+++ b/modules/regex/register_types.cpp
@@ -29,9 +29,11 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/object/class_db.h"
+
#include "regex.h"
+#include "core/object/class_db.h"
+
void initialize_regex_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h
index ac6192e373..6515d5d130 100644
--- a/modules/regex/tests/test_regex.h
+++ b/modules/regex/tests/test_regex.h
@@ -31,8 +31,9 @@
#ifndef TEST_REGEX_H
#define TEST_REGEX_H
+#include "../regex.h"
+
#include "core/string/ustring.h"
-#include "modules/regex/regex.h"
#include "tests/test_macros.h"
diff --git a/modules/text_server_adv/icu_data/icudata_stub.cpp b/modules/text_server_adv/icu_data/icudata_stub.cpp
index a6a9e1cc1d..86448b95bc 100644
--- a/modules/text_server_adv/icu_data/icudata_stub.cpp
+++ b/modules/text_server_adv/icu_data/icudata_stub.cpp
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "unicode/udata.h"
-#include "unicode/utypes.h"
-#include "unicode/uversion.h"
+#include <unicode/udata.h>
+#include <unicode/utypes.h>
+#include <unicode/uversion.h>
typedef struct {
uint16_t header_size;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 6231702e84..eb0cb54caf 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -66,10 +66,10 @@ using namespace godot;
// Thirdparty headers.
#ifdef MODULE_MSDFGEN_ENABLED
-#include "core/ShapeDistanceFinder.h"
-#include "core/contour-combiners.h"
-#include "core/edge-selectors.h"
-#include "msdfgen.h"
+#include <core/ShapeDistanceFinder.h>
+#include <core/contour-combiners.h>
+#include <core/edge-selectors.h>
+#include <msdfgen.h>
#endif
#ifdef MODULE_SVG_ENABLED
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 74ba657604..aba727edaa 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -36,6 +36,8 @@
/* shaping and advanced font features support. */
/*************************************************************************/
+#include "script_iterator.h"
+
#ifdef GDEXTENSION
// Headers for building as GDExtension plug-in.
@@ -79,20 +81,17 @@ using namespace godot;
#else
// Headers for building as built-in module.
-#include "servers/text/text_server_extension.h"
-
#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/worker_thread_pool.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "scene/resources/texture.h"
+#include "servers/text/text_server_extension.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
#endif
-#include "script_iterator.h"
-
// Thirdparty headers.
#include <unicode/ubidi.h>
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 3e6a81c84e..c227f35561 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -55,9 +55,10 @@ using namespace godot;
#ifdef MODULE_SVG_ENABLED
#ifdef MODULE_FREETYPE_ENABLED
-#include "thorvg_bounds_iterator.h"
#include "thorvg_svg_in_ot.h"
+#include "thorvg_bounds_iterator.h"
+
#include <freetype/otsvg.h>
#include <ft2build.h>
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index b76214cf94..dc0a7df81a 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -59,10 +59,10 @@ using namespace godot;
// Thirdparty headers.
#ifdef MODULE_MSDFGEN_ENABLED
-#include "core/ShapeDistanceFinder.h"
-#include "core/contour-combiners.h"
-#include "core/edge-selectors.h"
-#include "msdfgen.h"
+#include <core/ShapeDistanceFinder.h>
+#include <core/contour-combiners.h>
+#include <core/edge-selectors.h>
+#include <msdfgen.h>
#endif
#ifdef MODULE_SVG_ENABLED
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 8abcc41b2a..d81b50779e 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -79,13 +79,12 @@ using namespace godot;
#else
// Headers for building as built-in module.
-#include "servers/text/text_server_extension.h"
-
#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/worker_thread_pool.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "scene/resources/texture.h"
+#include "servers/text/text_server_extension.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 4c781a5c85..cd0ecd9b90 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -55,9 +55,10 @@ using namespace godot;
#ifdef MODULE_SVG_ENABLED
#ifdef MODULE_FREETYPE_ENABLED
-#include "thorvg_bounds_iterator.h"
#include "thorvg_svg_in_ot.h"
+#include "thorvg_bounds_iterator.h"
+
#include <freetype/otsvg.h>
#include <ft2build.h>
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index 315de9b268..31c1e06dee 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "image_saver_tinyexr.h"
+
#include "core/math/math_funcs.h"
#include <zlib.h> // Should come before including tinyexr.
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index e8b92964fb..f6a34837a2 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -30,11 +30,11 @@
#include "register_types.h"
-#include "core/error/error_macros.h"
-
#include "upnp.h"
#include "upnp_device.h"
+#include "core/error/error_macros.h"
+
void initialize_upnp_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index 2975e1474e..dc9bbdbc22 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -31,10 +31,10 @@
#ifndef UPNP_H
#define UPNP_H
-#include "core/object/ref_counted.h"
-
#include "upnp_device.h"
+#include "core/object/ref_counted.h"
+
#include <miniupnpc.h>
class UPNP : public RefCounted {
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 088f03ebe8..d0b35ef0d6 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "register_types.h"
+
#include "scene/resources/mesh.h"
+
#include "thirdparty/vhacd/public/VHACD.h"
static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Ref<MeshConvexDecompositionSettings> &p_settings, Vector<Vector<uint32_t>> *r_convex_indices) {
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp
index 9e280de0ca..8392750798 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp
@@ -34,13 +34,13 @@
#include "core/io/resource_saver.h"
#include "scene/resources/texture.h"
-#include <ogg/ogg.h>
-#include <vorbis/codec.h>
-
#ifdef TOOLS_ENABLED
#include "editor/import/audio_stream_import_settings.h"
#endif
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+
String ResourceImporterOggVorbis::get_importer_name() const {
return "oggvorbisstr";
}
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h
index e7ca41011a..4874419834 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/vorbis/resource_importer_ogg_vorbis.h
@@ -32,6 +32,7 @@
#define RESOURCE_IMPORTER_OGG_VORBIS_H
#include "audio_stream_ogg_vorbis.h"
+
#include "core/io/resource_importer.h"
class ResourceImporterOggVorbis : public ResourceImporter {
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index b8460fe387..c3aa860589 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -30,16 +30,18 @@
#include "image_loader_webp.h"
+#include "webp_common.h"
+
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include "webp_common.h"
-#include <stdlib.h>
#include <webp/decode.h>
#include <webp/encode.h>
+#include <stdlib.h>
+
static Ref<Image> _webp_mem_loader_func(const uint8_t *p_webp_data, int p_size) {
Ref<Image> img;
img.instantiate();
diff --git a/modules/webp/resource_saver_webp.cpp b/modules/webp/resource_saver_webp.cpp
index 2f09ab7964..92285e2eab 100644
--- a/modules/webp/resource_saver_webp.cpp
+++ b/modules/webp/resource_saver_webp.cpp
@@ -30,10 +30,11 @@
#include "resource_saver_webp.h"
+#include "webp_common.h"
+
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "scene/resources/texture.h"
-#include "webp_common.h"
Error ResourceSaverWebP::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<ImageTexture> texture = p_resource;
diff --git a/modules/webp/webp_common.cpp b/modules/webp/webp_common.cpp
index eb9403dcc2..60cb0091e1 100644
--- a/modules/webp/webp_common.cpp
+++ b/modules/webp/webp_common.cpp
@@ -33,10 +33,11 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
-#include <string.h>
#include <webp/decode.h>
#include <webp/encode.h>
+#include <string.h>
+
namespace WebPCommon {
Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quality) {
ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>());
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
index 535a20d67e..dbe6033c4d 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -21,7 +21,7 @@
</description>
</method>
<method name="_create_data_channel" qualifiers="virtual">
- <return type="Object" />
+ <return type="WebRTCDataChannel" />
<param index="0" name="p_label" type="String" />
<param index="1" name="p_config" type="Dictionary" />
<description>
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 93db5eb709..687c7b711e 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -29,14 +29,15 @@
/**************************************************************************/
#include "register_types.h"
-#include "core/config/project_settings.h"
+
#include "webrtc_data_channel.h"
+#include "webrtc_data_channel_extension.h"
#include "webrtc_multiplayer_peer.h"
#include "webrtc_peer_connection.h"
-
-#include "webrtc_data_channel_extension.h"
#include "webrtc_peer_connection_extension.h"
+#include "core/config/project_settings.h"
+
void initialize_webrtc_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/modules/webrtc/webrtc_data_channel.cpp b/modules/webrtc/webrtc_data_channel.cpp
index 71cbd27387..bebf5c2741 100644
--- a/modules/webrtc/webrtc_data_channel.cpp
+++ b/modules/webrtc/webrtc_data_channel.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "webrtc_data_channel.h"
+
#include "core/config/project_settings.h"
void WebRTCDataChannel::_bind_methods() {
diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp
index 22d528a471..f037e35107 100644
--- a/modules/webrtc/webrtc_data_channel_js.cpp
+++ b/modules/webrtc/webrtc_data_channel_js.cpp
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef WEB_ENABLED
-
#include "webrtc_data_channel_js.h"
-#include "emscripten.h"
+#ifdef WEB_ENABLED
+
+#include <emscripten.h>
extern "C" {
typedef void (*RTCChOnOpen)(void *p_obj);
diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h
index 95668f4f8c..d7f4874246 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.h
+++ b/modules/webrtc/webrtc_multiplayer_peer.h
@@ -31,9 +31,10 @@
#ifndef WEBRTC_MULTIPLAYER_PEER_H
#define WEBRTC_MULTIPLAYER_PEER_H
-#include "scene/main/multiplayer_peer.h"
#include "webrtc_peer_connection.h"
+#include "scene/main/multiplayer_peer.h"
+
class WebRTCMultiplayerPeer : public MultiplayerPeer {
GDCLASS(WebRTCMultiplayerPeer, MultiplayerPeer);
diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h
index 2f8ed8b1ed..0f79c17519 100644
--- a/modules/webrtc/webrtc_peer_connection.h
+++ b/modules/webrtc/webrtc_peer_connection.h
@@ -31,8 +31,9 @@
#ifndef WEBRTC_PEER_CONNECTION_H
#define WEBRTC_PEER_CONNECTION_H
+#include "webrtc_data_channel.h"
+
#include "core/io/packet_peer.h"
-#include "modules/webrtc/webrtc_data_channel.h"
class WebRTCPeerConnection : public RefCounted {
GDCLASS(WebRTCPeerConnection, RefCounted);
diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp
index 15e6bac3b0..248b0cf610 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.cpp
+++ b/modules/webrtc/webrtc_peer_connection_extension.cpp
@@ -43,14 +43,3 @@ void WebRTCPeerConnectionExtension::_bind_methods() {
GDVIRTUAL_BIND(_poll);
GDVIRTUAL_BIND(_close);
}
-
-Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String p_label, Dictionary p_options) {
- Object *ret = nullptr;
- if (GDVIRTUAL_CALL(_create_data_channel, p_label, p_options, ret)) {
- WebRTCDataChannel *ch = Object::cast_to<WebRTCDataChannel>(ret);
- ERR_FAIL_COND_V_MSG(ret && !ch, nullptr, "Returned object must be an instance of WebRTCDataChannel.");
- return ch;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_data_channel is unimplemented!");
- return nullptr;
-}
diff --git a/modules/webrtc/webrtc_peer_connection_extension.h b/modules/webrtc/webrtc_peer_connection_extension.h
index a2a5c773f0..f3339f1eb4 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.h
+++ b/modules/webrtc/webrtc_peer_connection_extension.h
@@ -45,17 +45,12 @@ protected:
static void _bind_methods();
public:
- // FIXME Can't be directly exposed due to issues in exchanging Ref(s) between godot and extensions.
- // See godot-cpp GH-652 .
- virtual Ref<WebRTCDataChannel> create_data_channel(String p_label, Dictionary p_options = Dictionary()) override;
- GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary);
- // EXBIND2R(Ref<WebRTCDataChannel>, create_data_channel, String, Dictionary);
-
/** GDExtension **/
EXBIND0RC(ConnectionState, get_connection_state);
EXBIND0RC(GatheringState, get_gathering_state);
EXBIND0RC(SignalingState, get_signaling_state);
EXBIND1R(Error, initialize, Dictionary);
+ EXBIND2R(Ref<WebRTCDataChannel>, create_data_channel, String, Dictionary);
EXBIND0R(Error, create_offer);
EXBIND2R(Error, set_remote_description, String, String);
EXBIND2R(Error, set_local_description, String, String);
diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp
index f979a20367..26256a4e30 100644
--- a/modules/webrtc/webrtc_peer_connection_js.cpp
+++ b/modules/webrtc/webrtc_peer_connection_js.cpp
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef WEB_ENABLED
-
#include "webrtc_peer_connection_js.h"
+#ifdef WEB_ENABLED
+
#include "webrtc_data_channel_js.h"
-#include "emscripten.h"
+#include <emscripten.h>
void WebRTCPeerConnectionJS::_on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate) {
WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
diff --git a/modules/websocket/editor/editor_debugger_server_websocket.cpp b/modules/websocket/editor/editor_debugger_server_websocket.cpp
index 35fc051bc3..a28fc53440 100644
--- a/modules/websocket/editor/editor_debugger_server_websocket.cpp
+++ b/modules/websocket/editor/editor_debugger_server_websocket.cpp
@@ -33,6 +33,7 @@
#ifdef TOOLS_ENABLED
#include "../remote_debugger_peer_websocket.h"
+
#include "core/config/project_settings.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 7b14a3a61d..329e5bd532 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef WEB_ENABLED
-
#include "emws_peer.h"
+#ifdef WEB_ENABLED
+
#include "core/io/ip.h"
void EMWSPeer::_esws_on_connect(void *p_obj, char *p_proto) {
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index 08b2dad977..38f15c82e5 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -33,12 +33,14 @@
#ifdef WEB_ENABLED
+#include "packet_buffer.h"
+#include "websocket_peer.h"
+
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
#include "core/templates/ring_buffer.h"
-#include "emscripten.h"
-#include "packet_buffer.h"
-#include "websocket_peer.h"
+
+#include <emscripten.h>
extern "C" {
typedef void (*WSOnOpen)(void *p_ref, char *p_protocol);
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index 08935626d0..c57210c8c9 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -30,15 +30,10 @@
#include "register_types.h"
-#include "core/config/project_settings.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/error/error_macros.h"
-
+#include "remote_debugger_peer_websocket.h"
#include "websocket_multiplayer_peer.h"
#include "websocket_peer.h"
-#include "remote_debugger_peer_websocket.h"
-
#ifdef WEB_ENABLED
#include "emws_peer.h"
#else
@@ -46,8 +41,15 @@
#endif
#ifdef TOOLS_ENABLED
-#include "editor/debugger/editor_debugger_server.h"
#include "editor/editor_debugger_server_websocket.h"
+#endif
+
+#include "core/config/project_settings.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/error/error_macros.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/debugger/editor_debugger_server.h"
#include "editor/editor_node.h"
#endif
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index 5d26e076c7..50d0d28203 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -31,10 +31,10 @@
#ifndef REMOTE_DEBUGGER_PEER_WEBSOCKET_H
#define REMOTE_DEBUGGER_PEER_WEBSOCKET_H
-#include "core/debugger/remote_debugger_peer.h"
-
#include "websocket_peer.h"
+#include "core/debugger/remote_debugger_peer.h"
+
class RemoteDebuggerPeerWebSocket : public RemoteDebuggerPeer {
Ref<WebSocketPeer> ws_peer;
List<Array> in_queue;
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index 22f1bc939b..f793cb375e 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -31,12 +31,13 @@
#ifndef WEBSOCKET_MULTIPLAYER_PEER_H
#define WEBSOCKET_MULTIPLAYER_PEER_H
+#include "websocket_peer.h"
+
#include "core/error/error_list.h"
#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/templates/list.h"
#include "scene/main/multiplayer_peer.h"
-#include "websocket_peer.h"
class WebSocketMultiplayerPeer : public MultiplayerPeer {
GDCLASS(WebSocketMultiplayerPeer, MultiplayerPeer);
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 109d5102c3..a127a6b75a 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -28,11 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef WEB_ENABLED
-
#include "wsl_peer.h"
-#include "wsl_peer.h"
+#ifndef WEB_ENABLED
#include "core/io/stream_peer_tls.h"
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index c06e768b6d..bf9f5c8527 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -33,16 +33,16 @@
#ifndef WEB_ENABLED
-#include "websocket_peer.h"
-
#include "packet_buffer.h"
+#include "websocket_peer.h"
#include "core/crypto/crypto_core.h"
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
#include "core/io/stream_peer_tcp.h"
#include "core/templates/ring_buffer.h"
-#include "wslay/wslay.h"
+
+#include <wslay/wslay.h>
#define WSL_MAX_HEADER_SIZE 4096
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index 554ca0398b..a7ce7e45d2 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -35,7 +35,7 @@
extern "C" {
#endif
-#include "stddef.h"
+#include <stddef.h>
enum WebXRInputEvent {
WEBXR_INPUT_EVENT_SELECTSTART,
diff --git a/modules/webxr/webxr_interface.cpp b/modules/webxr/webxr_interface.cpp
index 5e30d0c996..85ed9f472e 100644
--- a/modules/webxr/webxr_interface.cpp
+++ b/modules/webxr/webxr_interface.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "webxr_interface.h"
+
#include <stdlib.h>
void WebXRInterface::_bind_methods() {
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index e1df2ea94e..47f20ce1a3 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -28,20 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
+#include "webxr_interface_js.h"
+
#ifdef WEB_ENABLED
-#include "webxr_interface_js.h"
+#include "godot_webxr.h"
#include "core/input/input.h"
#include "core/os/os.h"
#include "drivers/gles3/storage/texture_storage.h"
-#include "emscripten.h"
-#include "godot_webxr.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/rendering_server_globals.h"
+#include <emscripten.h>
#include <stdlib.h>
void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) {
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index c3da058b1d..e5da9b3a4f 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -29,8 +29,10 @@
/**************************************************************************/
#include "register_types.h"
+
#include "core/crypto/crypto_core.h"
-#include "thirdparty/xatlas/xatlas.h"
+
+#include <xatlas.h>
extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
diff --git a/modules/zip/register_types.cpp b/modules/zip/register_types.cpp
index 2df72d0cda..b2da90826e 100644
--- a/modules/zip/register_types.cpp
+++ b/modules/zip/register_types.cpp
@@ -30,10 +30,11 @@
#include "register_types.h"
-#include "core/object/class_db.h"
#include "zip_packer.h"
#include "zip_reader.h"
+#include "core/object/class_db.h"
+
void initialize_zip_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 4d9a49c35c..f02b292868 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -453,6 +453,10 @@ void DisplayServerAndroid::window_move_to_foreground(DisplayServer::WindowID p_w
// Not supported on Android.
}
+bool DisplayServerAndroid::window_is_focused(WindowID p_window) const {
+ return true;
+}
+
bool DisplayServerAndroid::window_can_draw(DisplayServer::WindowID p_window) const {
return true;
}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index ad1cbddb08..e0ad2cb916 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -178,6 +178,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 6030239695..cb82091073 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2227,7 +2227,7 @@ String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_
return apksigner_path;
}
-bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
@@ -2286,7 +2286,8 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
err += TTR("Either Debug Keystore, Debug User AND Debug Password settings must be configured OR none of them.") + "\n";
}
- if (!FileAccess::exists(dk)) {
+ // Use OR to make the export UI able to show this error.
+ if ((p_debug || !dk.is_empty()) && !FileAccess::exists(dk)) {
dk = EDITOR_GET("export/android/debug_keystore");
if (!FileAccess::exists(dk)) {
valid = false;
@@ -2303,7 +2304,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
err += TTR("Either Release Keystore, Release User AND Release Password settings must be configured OR none of them.") + "\n";
}
- if (!rk.is_empty() && !FileAccess::exists(rk)) {
+ if (!p_debug && !rk.is_empty() && !FileAccess::exists(rk)) {
valid = false;
err += TTR("Release keystore incorrectly configured in the export preset.") + "\n";
}
@@ -2323,7 +2324,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
valid = false;
}
- // Validate that adb is available
+ // Validate that adb is available.
String adb_path = get_adb_path();
if (!FileAccess::exists(adb_path)) {
err += TTR("Unable to find Android SDK platform-tools' adb command.");
@@ -2345,7 +2346,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
if (!target_sdk_version.is_valid_int()) {
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
}
- // Validate that apksigner is available
+ // Validate that apksigner is available.
String apksigner_path = get_apksigner_path(target_sdk_version.to_int());
if (!FileAccess::exists(apksigner_path)) {
err += TTR("Unable to find Android SDK build-tools' apksigner command.");
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 390b8c6465..0ac0fbb10b 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -219,7 +219,7 @@ public:
static String get_apksigner_path(int p_target_sdk = -1, bool p_check_executes = false);
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index ce4a2ecfe4..542ab51660 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -35,7 +35,7 @@
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
- android:launchMode="singleTask"
+ android:launchMode="singleInstance"
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="landscape"
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 3d1d4d22ce..64d3d4eca1 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -62,7 +62,6 @@ open class GodotEditor : FullScreenGodotApp() {
private const val WAIT_FOR_DEBUGGER = false
- private const val EXTRA_FORCE_QUIT = "force_quit_requested"
private const val EXTRA_COMMAND_LINE_PARAMS = "command_line_params"
private const val EDITOR_ID = 777
@@ -96,7 +95,9 @@ open class GodotEditor : FullScreenGodotApp() {
// requested on demand based on use-cases.
PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO))
- handleIntentParams(intent)
+ val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
+ Log.d(TAG, "Received parameters ${params.contentToString()}")
+ updateCommandLineParams(params)
if (BuildConfig.BUILD_TYPE == "dev" && WAIT_FOR_DEBUGGER) {
Debug.waitForDebugger()
@@ -105,25 +106,6 @@ open class GodotEditor : FullScreenGodotApp() {
super.onCreate(savedInstanceState)
}
- override fun onNewIntent(newIntent: Intent) {
- intent = newIntent
- handleIntentParams(newIntent)
- super.onNewIntent(newIntent)
- }
-
- private fun handleIntentParams(receivedIntent: Intent) {
- val forceQuitRequested = receivedIntent.getBooleanExtra(EXTRA_FORCE_QUIT, false)
- if (forceQuitRequested) {
- Log.d(TAG, "Force quit requested, terminating..")
- ProcessPhoenix.forceQuit(this)
- return
- }
-
- val params = receivedIntent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
- Log.d(TAG, "Received parameters ${params.contentToString()}")
- updateCommandLineParams(params)
- }
-
override fun onGodotSetupCompleted() {
super.onGodotSetupCompleted()
val longPressEnabled = enableLongPressGestures()
@@ -154,7 +136,7 @@ open class GodotEditor : FullScreenGodotApp() {
private fun updateCommandLineParams(args: Array<String>?) {
// Update the list of command line params with the new args
commandLineParams.clear()
- if (args != null && args.isNotEmpty()) {
+ if (!args.isNullOrEmpty()) {
commandLineParams.addAll(listOf(*args))
}
if (BuildConfig.BUILD_TYPE == "dev") {
@@ -201,6 +183,7 @@ open class GodotEditor : FullScreenGodotApp() {
ProcessPhoenix.triggerRebirth(this, newInstance)
} else {
Log.d(TAG, "Starting $targetClass with parameters ${args.contentToString()}")
+ newInstance.putExtra(EXTRA_NEW_LAUNCH, true)
startActivity(newInstance)
}
return instanceId
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index 677c9d8f13..3e975449d8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -51,6 +51,9 @@ import androidx.fragment.app.FragmentActivity;
public abstract class FullScreenGodotApp extends FragmentActivity implements GodotHost {
private static final String TAG = FullScreenGodotApp.class.getSimpleName();
+ protected static final String EXTRA_FORCE_QUIT = "force_quit_requested";
+ protected static final String EXTRA_NEW_LAUNCH = "new_launch_requested";
+
@Nullable
private Godot godotFragment;
@@ -59,6 +62,8 @@ public abstract class FullScreenGodotApp extends FragmentActivity implements God
super.onCreate(savedInstanceState);
setContentView(R.layout.godot_app_layout);
+ handleStartIntent(getIntent(), true);
+
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.godot_fragment_container);
if (currentFragment instanceof Godot) {
Log.v(TAG, "Reusing existing Godot fragment instance.");
@@ -109,11 +114,35 @@ public abstract class FullScreenGodotApp extends FragmentActivity implements God
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
+ setIntent(intent);
+
+ handleStartIntent(intent, false);
+
if (godotFragment != null) {
godotFragment.onNewIntent(intent);
}
}
+ private void handleStartIntent(Intent intent, boolean newLaunch) {
+ boolean forceQuitRequested = intent.getBooleanExtra(EXTRA_FORCE_QUIT, false);
+ if (forceQuitRequested) {
+ Log.d(TAG, "Force quit requested, terminating..");
+ ProcessPhoenix.forceQuit(this);
+ return;
+ }
+
+ if (!newLaunch) {
+ boolean newLaunchRequested = intent.getBooleanExtra(EXTRA_NEW_LAUNCH, false);
+ if (newLaunchRequested) {
+ Log.d(TAG, "New launch requested, restarting..");
+
+ Intent restartIntent = new Intent(intent).putExtra(EXTRA_NEW_LAUNCH, false);
+ ProcessPhoenix.triggerRebirth(this, restartIntent);
+ return;
+ }
+ }
+ }
+
@CallSuper
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index b29bdeec62..da16449c61 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -193,6 +193,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual float screen_get_max_scale() const override;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index bfb09b6861..7d91274a0c 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -562,6 +562,10 @@ void DisplayServerIOS::window_move_to_foreground(WindowID p_window) {
// Probably not supported for iOS
}
+bool DisplayServerIOS::window_is_focused(WindowID p_window) const {
+ return true;
+}
+
float DisplayServerIOS::screen_get_max_scale() const {
return screen_get_scale(SCREEN_OF_MAIN_WINDOW);
}
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index ae0d120513..9962a48250 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -1899,7 +1899,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return OK;
}
-bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index 2e461c8ed6..6616bbd714 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -208,7 +208,7 @@ public:
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual void get_platform_features(List<String> *r_features) const override {
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index ebdbd061d1..310778388b 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -496,11 +496,19 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
return font_config_initialized;
}
#endif
+
+#ifndef __linux__
+ // `bsd` includes **all** BSD, not only "other BSD" (see `get_name()`).
+ if (p_feature == "bsd") {
+ return true;
+ }
+#endif
+
if (p_feature == "pc") {
return true;
}
- // Match against the specific OS (linux, freebsd, etc).
+ // Match against the specific OS (`linux`, `freebsd`, `netbsd`, `openbsd`).
if (p_feature == get_name().to_lower()) {
return true;
}
@@ -953,32 +961,41 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
args.push_back(path);
args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args.
Error result = execute("gio", args, nullptr, &err_code); // For GNOME based machines.
- if (result == OK && !err_code) {
- return OK;
- } else if (err_code == 2) {
- return ERR_FILE_NOT_FOUND;
+ if (result == OK) { // The `execute` function has done its job without errors.
+ if (!err_code) { // The shell command has been executed without errors.
+ return OK;
+ } else if (err_code == 1) {
+ ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
+ return ERR_FILE_NOT_FOUND;
+ }
}
args.pop_front();
args.push_front("move");
args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`.
result = execute("kioclient5", args, nullptr, &err_code); // For KDE based machines.
- if (result == OK && !err_code) {
- return OK;
- } else if (err_code == 2) {
- return ERR_FILE_NOT_FOUND;
+ if (result == OK) { // The `execute` function has done its job without errors.
+ if (!err_code) { // The shell command has been executed without errors.
+ return OK;
+ } else if (err_code == 1) {
+ ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
+ return ERR_FILE_NOT_FOUND;
+ }
}
args.pop_front();
args.pop_back();
result = execute("gvfs-trash", args, nullptr, &err_code); // For older Linux machines.
- if (result == OK && !err_code) {
- return OK;
- } else if (err_code == 2) {
- return ERR_FILE_NOT_FOUND;
+ if (result == OK) { // The `execute` function has done its job without errors.
+ if (!err_code) { // The shell command has been executed without errors.
+ return OK;
+ } else if (err_code == 1) {
+ ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
+ return ERR_FILE_NOT_FOUND;
+ }
}
- // If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually.
+ // If the commands `kioclient5`, `gio` or `gvfs-trash` don't work on the system we do it manually.
String trash_path = "";
String mnt = get_mountpoint(path);
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 83b6fb7628..a607e26ac5 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -2626,6 +2626,15 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
XFlush(x11_display);
}
+bool DisplayServerX11::window_is_focused(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ return wd.focused;
+}
+
bool DisplayServerX11::window_can_draw(WindowID p_window) const {
//this seems to be all that is provided by X11
return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 176a1ffb9a..180362923b 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -477,6 +477,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 5944cc8abd..93fa93b259 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -117,6 +117,7 @@ public:
bool no_focus = false;
bool is_popup = false;
bool mpass = false;
+ bool focused = false;
Rect2i parent_safe_rect;
};
@@ -390,6 +391,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index b77715d648..a0a851b7dc 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -3075,6 +3075,15 @@ void DisplayServerMacOS::window_move_to_foreground(WindowID p_window) {
}
}
+bool DisplayServerMacOS::window_is_focused(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ return wd.focused;
+}
+
bool DisplayServerMacOS::window_can_draw(WindowID p_window) const {
return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
}
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 802c8d42c3..0b5f2b1266 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -2081,7 +2081,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
return err;
}
-bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 0477a8c0cc..0764b63e8c 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -148,7 +148,7 @@ public:
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual void get_platform_features(List<String> *r_features) const override {
diff --git a/platform/macos/export/lipo.cpp b/platform/macos/export/lipo.cpp
index 15b369a8ed..2d77e5960d 100644
--- a/platform/macos/export/lipo.cpp
+++ b/platform/macos/export/lipo.cpp
@@ -45,25 +45,27 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f
uint64_t max_size = 0;
for (int i = 0; i < p_files.size(); i++) {
- MachO mh;
- if (!mh.open_file(p_files[i])) {
- ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s.\"", p_files[i]));
- }
+ {
+ MachO mh;
+ if (!mh.open_file(p_files[i])) {
+ ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s\".", p_files[i]));
+ }
- FatArch arch;
- arch.cputype = mh.get_cputype();
- arch.cpusubtype = mh.get_cpusubtype();
- arch.offset = 0;
- arch.size = mh.get_size();
- arch.align = mh.get_align();
- max_size += arch.size;
+ FatArch arch;
+ arch.cputype = mh.get_cputype();
+ arch.cpusubtype = mh.get_cpusubtype();
+ arch.offset = 0;
+ arch.size = mh.get_size();
+ arch.align = mh.get_align();
+ max_size += arch.size;
- archs.push_back(arch);
+ archs.push_back(arch);
+ }
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
- ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i]));
+ ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
}
@@ -100,7 +102,7 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
- ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i]));
+ ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
uint64_t cur = fa->get_position();
for (uint64_t j = cur; j < archs[i].offset; j++) {
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index df971c5139..1c6dbb1981 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -314,6 +314,7 @@
[self windowDidResize:notification]; // Emit resize event, to ensure content is resized if the window was resized while it was hidden.
+ wd.focused = true;
ds->set_last_focused_window(window_id);
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
}
@@ -330,6 +331,7 @@
[(GodotButtonView *)wd.window_button_view displayButtons];
}
+ wd.focused = false;
ds->release_pressed_events();
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
}
@@ -342,6 +344,7 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.focused = false;
ds->release_pressed_events();
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
}
@@ -353,9 +356,11 @@
}
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
-
- ds->set_last_focused_window(window_id);
- ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
+ if ([wd.window_object isKeyWindow]) {
+ wd.focused = true;
+ ds->set_last_focused_window(window_id);
+ ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
+ }
}
@end
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 69de383efc..a0a91a1cf1 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -128,7 +128,7 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
}
}
-bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
#ifndef DEV_ENABLED
// We don't provide export templates for the UWP platform currently as it
// has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index 999d54cb80..cc86bdb280 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -434,7 +434,7 @@ public:
virtual void get_export_options(List<ExportOption> *r_options) const override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 6cb56b404f..951ce110e0 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -1073,6 +1073,10 @@ void DisplayServerWeb::window_move_to_foreground(WindowID p_window) {
// Not supported.
}
+bool DisplayServerWeb::window_is_focused(WindowID p_window) const {
+ return true;
+}
+
bool DisplayServerWeb::window_can_draw(WindowID p_window) const {
return true;
}
diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h
index 3b03b102cd..a4fd75f33b 100644
--- a/platform/web/display_server_web.h
+++ b/platform/web/display_server_web.h
@@ -211,6 +211,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index a398593f90..e3cdd6a60d 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -358,7 +358,7 @@ Ref<Texture2D> EditorExportPlatformWeb::get_logo() const {
return logo;
}
-bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
bool extensions = (bool)p_preset->get("variant/extensions_support");
diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h
index a1d3fed2f3..2de4a4c153 100644
--- a/platform/web/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -106,7 +106,7 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index fc208eb4bb..ea93c47ec5 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1615,6 +1615,15 @@ void DisplayServerWindows::window_move_to_foreground(WindowID p_window) {
}
}
+bool DisplayServerWindows::window_is_focused(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ return wd.window_focused;
+}
+
bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
_THREAD_SAFE_METHOD_
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index ae2cd4e8b5..7228de7d31 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -594,6 +594,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 7371e4daf7..367b471196 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -674,9 +674,9 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
return OK;
}
-bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err = "";
- bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates);
+ bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates, p_debug);
String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 184b2f96f8..c644b1f9e1 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -79,7 +79,7 @@ public:
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) const override;
- virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index ad7c637a37..0334bdd973 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -86,7 +86,7 @@ typedef int(__cdecl *NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle, NvDRSProfileHan
typedef int(__cdecl *NvAPI_DRS_FindProfileByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *);
NvAPI_GetErrorMessage_t NvAPI_GetErrorMessage__;
-static bool nvapi_err_check(char *msg, int status) {
+static bool nvapi_err_check(const char *msg, int status) {
if (status != 0) {
if (OS::get_singleton()->is_stdout_verbose()) {
NvAPI_ShortString err_desc = { 0 };
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 8b19b653fc..58dad40403 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -34,11 +34,6 @@
#include "core/math/geometry_2d.h"
#include "line_builder.h"
-// Needed so we can bind functions
-VARIANT_ENUM_CAST(Line2D::LineJointMode)
-VARIANT_ENUM_CAST(Line2D::LineCapMode)
-VARIANT_ENUM_CAST(Line2D::LineTextureMode)
-
Line2D::Line2D() {
}
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index b98c27138f..aa873ca642 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -138,4 +138,9 @@ private:
bool _antialiased = false;
};
+// Needed so we can bind functions
+VARIANT_ENUM_CAST(Line2D::LineJointMode)
+VARIANT_ENUM_CAST(Line2D::LineCapMode)
+VARIANT_ENUM_CAST(Line2D::LineTextureMode)
+
#endif // LINE_2D_H
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 936244fdb1..73a801c822 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -246,22 +246,14 @@ void NavigationAgent2D::_notification(int p_what) {
} break;
case NOTIFICATION_PAUSED: {
- if (agent_parent && !agent_parent->can_process()) {
- map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
- } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
- map_before_pause = RID();
+ if (agent_parent) {
+ NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
}
} break;
case NOTIFICATION_UNPAUSED: {
- if (agent_parent && !agent_parent->can_process()) {
- map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
- } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
- map_before_pause = RID();
+ if (agent_parent) {
+ NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
}
} break;
@@ -954,6 +946,7 @@ void NavigationAgent2D::_update_debug_path() {
}
RenderingServer::get_singleton()->canvas_item_set_parent(debug_path_instance, agent_parent->get_canvas());
+ RenderingServer::get_singleton()->canvas_item_set_z_index(debug_path_instance, RS::CANVAS_ITEM_Z_MAX - 1);
RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
const Vector<Vector2> &navigation_path = navigation_result->get_path();
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index ca43abf833..10c703168b 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -43,7 +43,6 @@ class NavigationAgent2D : public Node {
Node2D *agent_parent = nullptr;
RID agent;
- RID map_before_pause;
RID map_override;
bool avoidance_enabled = false;
@@ -75,7 +74,7 @@ class NavigationAgent2D : public Node {
Vector2 safe_velocity;
/// The submitted target velocity, sets the "wanted" rvo agent velocity on the next update
- // this velocity is not guaranteed, the simulation will try to fulfil it if possible
+ // this velocity is not guaranteed, the simulation will try to fulfill it if possible
// if other agents or obstacles interfere it will be changed accordingly
Vector2 velocity;
bool velocity_submitted = false;
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 3ee1260c0d..8e96f8265c 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -96,6 +96,7 @@ void NavigationObstacle2D::_notification(int p_what) {
_update_map(map_before_pause);
map_before_pause = RID();
}
+ NavigationServer2D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_UNPAUSED: {
@@ -106,6 +107,7 @@ void NavigationObstacle2D::_notification(int p_what) {
_update_map(map_before_pause);
map_before_pause = RID();
}
+ NavigationServer2D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index c14fb29353..693e03e1d4 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -35,7 +35,6 @@
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
-#include "servers/navigation_server_3d.h"
void NavigationRegion2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
@@ -50,14 +49,12 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
if (!enabled) {
NavigationServer2D::get_singleton()->region_set_map(region, RID());
- NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
} else {
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
- NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
#ifdef DEBUG_ENABLED
- if (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
+ if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_navigation_enabled()) {
queue_redraw();
}
#endif // DEBUG_ENABLED
@@ -166,7 +163,6 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled) {
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
- NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
if (constrain_avoidance_obstacles[i].is_valid()) {
NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map());
@@ -184,9 +180,6 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
NavigationServer2D::get_singleton()->region_set_map(region, RID());
- if (enabled) {
- NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
- }
for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
if (constrain_avoidance_obstacles[i].is_valid()) {
NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID());
@@ -215,78 +208,8 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_DRAW: {
#ifdef DEBUG_ENABLED
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) && navigation_polygon.is_valid()) {
- Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
- if (navigation_polygon_vertices.size() < 3) {
- return;
- }
-
- const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
-
- bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color();
- bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines();
- bool enable_edge_connections = use_edge_connections && ns2d->get_debug_navigation_enable_edge_connections() && ns2d->map_get_use_edge_connections(get_world_2d()->get_navigation_map());
-
- Color debug_face_color = ns2d->get_debug_navigation_geometry_face_color();
- Color debug_edge_color = ns2d->get_debug_navigation_geometry_edge_color();
- Color debug_edge_connection_color = ns2d->get_debug_navigation_edge_connection_color();
-
- if (!enabled) {
- debug_face_color = ns2d->get_debug_navigation_geometry_face_disabled_color();
- debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color();
- }
-
- RandomPCG rand;
-
- for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
- // An array of vertices for this polygon.
- Vector<int> polygon = navigation_polygon->get_polygon(i);
- Vector<Vector2> debug_polygon_vertices;
- debug_polygon_vertices.resize(polygon.size());
- for (int j = 0; j < polygon.size(); j++) {
- ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
- debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]];
- }
-
- // Generate the polygon color, slightly randomly modified from the settings one.
- Color random_variation_color = debug_face_color;
- if (enabled_geometry_face_random_color) {
- random_variation_color.set_hsv(
- debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1,
- debug_face_color.get_s(),
- debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
- }
- random_variation_color.a = debug_face_color.a;
-
- Vector<Color> debug_face_colors;
- debug_face_colors.push_back(random_variation_color);
- RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_polygon_vertices, debug_face_colors);
-
- if (enabled_edge_lines) {
- Vector<Color> debug_edge_colors;
- debug_edge_colors.push_back(debug_edge_color);
- debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline.
- RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_polygon_vertices, debug_edge_colors);
- }
- }
-
- if (enable_edge_connections) {
- // Draw the region edge connections.
- Transform2D xform = get_global_transform();
- real_t radius = ns2d->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
- for (int i = 0; i < ns2d->region_get_connections_count(region); i++) {
- // Two main points
- Vector2 a = ns2d->region_get_connection_pathway_start(region, i);
- a = xform.affine_inverse().xform(a);
- Vector2 b = ns2d->region_get_connection_pathway_end(region, i);
- b = xform.affine_inverse().xform(b);
- draw_line(a, b, debug_edge_connection_color);
-
- // Draw a circle to illustrate the margins.
- real_t angle = a.angle_to_point(b);
- draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, debug_edge_connection_color);
- draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, debug_edge_connection_color);
- }
- }
+ _update_debug_mesh();
+ _update_debug_edge_connections_mesh();
}
#endif // DEBUG_ENABLED
} break;
@@ -327,13 +250,13 @@ void NavigationRegion2D::_navigation_polygon_changed() {
_update_avoidance_constrain();
}
-void NavigationRegion2D::_map_changed(RID p_map) {
#ifdef DEBUG_ENABLED
+void NavigationRegion2D::_navigation_map_changed(RID p_map) {
if (is_inside_tree() && get_world_2d()->get_navigation_map() == p_map) {
queue_redraw();
}
-#endif // DEBUG_ENABLED
}
+#endif // DEBUG_ENABLED
PackedStringArray NavigationRegion2D::get_configuration_warnings() const {
PackedStringArray warnings = Node2D::get_configuration_warnings();
@@ -419,8 +342,8 @@ NavigationRegion2D::NavigationRegion2D() {
NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
- NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
+ NavigationServer2D::get_singleton()->connect(SNAME("map_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed));
+ NavigationServer2D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed));
#endif // DEBUG_ENABLED
}
@@ -436,8 +359,8 @@ NavigationRegion2D::~NavigationRegion2D() {
constrain_avoidance_obstacles.clear();
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
- NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
+ NavigationServer2D::get_singleton()->disconnect(SNAME("map_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed));
+ NavigationServer2D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed));
#endif // DEBUG_ENABLED
}
@@ -548,3 +471,86 @@ bool NavigationRegion2D::get_avoidance_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Avoidance layer number must be between 1 and 32 inclusive.");
return get_avoidance_layers() & (1 << (p_layer_number - 1));
}
+
+#ifdef DEBUG_ENABLED
+void NavigationRegion2D::_update_debug_mesh() {
+ Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
+ if (navigation_polygon_vertices.size() < 3) {
+ return;
+ }
+
+ const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
+
+ bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color();
+ bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines();
+
+ Color debug_face_color = ns2d->get_debug_navigation_geometry_face_color();
+ Color debug_edge_color = ns2d->get_debug_navigation_geometry_edge_color();
+
+ if (!enabled) {
+ debug_face_color = ns2d->get_debug_navigation_geometry_face_disabled_color();
+ debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color();
+ }
+
+ RandomPCG rand;
+
+ for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
+ Vector<int> polygon = navigation_polygon->get_polygon(i);
+ Vector<Vector2> debug_polygon_vertices;
+ debug_polygon_vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
+ debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]];
+ }
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color = debug_face_color;
+ if (enabled_geometry_face_random_color) {
+ random_variation_color.set_hsv(
+ debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1,
+ debug_face_color.get_s(),
+ debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
+ }
+ random_variation_color.a = debug_face_color.a;
+
+ Vector<Color> debug_face_colors;
+ debug_face_colors.push_back(random_variation_color);
+ RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_polygon_vertices, debug_face_colors);
+
+ if (enabled_edge_lines) {
+ Vector<Color> debug_edge_colors;
+ debug_edge_colors.push_back(debug_edge_color);
+ debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline.
+ RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_polygon_vertices, debug_edge_colors);
+ }
+ }
+}
+#endif // DEBUG_ENABLED
+
+#ifdef DEBUG_ENABLED
+void NavigationRegion2D::_update_debug_edge_connections_mesh() {
+ const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
+ bool enable_edge_connections = use_edge_connections && ns2d->get_debug_navigation_enable_edge_connections() && ns2d->map_get_use_edge_connections(get_world_2d()->get_navigation_map());
+
+ if (enable_edge_connections) {
+ Color debug_edge_connection_color = ns2d->get_debug_navigation_edge_connection_color();
+ // Draw the region edge connections.
+ Transform2D xform = get_global_transform();
+ real_t radius = ns2d->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
+ for (int i = 0; i < ns2d->region_get_connections_count(region); i++) {
+ // Two main points
+ Vector2 a = ns2d->region_get_connection_pathway_start(region, i);
+ a = xform.affine_inverse().xform(a);
+ Vector2 b = ns2d->region_get_connection_pathway_end(region, i);
+ b = xform.affine_inverse().xform(b);
+ draw_line(a, b, debug_edge_connection_color);
+
+ // Draw a circle to illustrate the margins.
+ real_t angle = a.angle_to_point(b);
+ draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, debug_edge_connection_color);
+ draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, debug_edge_connection_color);
+ }
+ }
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 39de0a0004..642f1663cd 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -52,7 +52,13 @@ class NavigationRegion2D : public Node2D {
Transform2D current_global_transform;
void _navigation_polygon_changed();
- void _map_changed(RID p_RID);
+
+#ifdef DEBUG_ENABLED
+private:
+ void _update_debug_mesh();
+ void _update_debug_edge_connections_mesh();
+ void _navigation_map_changed(RID p_map);
+#endif // DEBUG_ENABLED
protected:
void _notification(int p_what);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 63fa8cdd35..5ea751f089 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -3086,7 +3086,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r
// Create the runtime TileData.
TileData *tile_data_runtime_use = tile_data->duplicate();
- tile_data->set_allow_transform(true);
+ tile_data_runtime_use->set_allow_transform(true);
q.runtime_tile_data_cache[E_cell.value] = tile_data_runtime_use;
GDVIRTUAL_CALL(_tile_data_runtime_update, q.layer, E_cell.value, tile_data_runtime_use);
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 80b360a2fd..63a2ff5534 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -261,22 +261,14 @@ void NavigationAgent3D::_notification(int p_what) {
} break;
case NOTIFICATION_PAUSED: {
- if (agent_parent && !agent_parent->can_process()) {
- map_before_pause = NavigationServer3D::get_singleton()->agent_get_map(get_rid());
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
- } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
- map_before_pause = RID();
+ if (agent_parent) {
+ NavigationServer3D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
}
} break;
case NOTIFICATION_UNPAUSED: {
- if (agent_parent && !agent_parent->can_process()) {
- map_before_pause = NavigationServer3D::get_singleton()->agent_get_map(get_rid());
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
- } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
- map_before_pause = RID();
+ if (agent_parent) {
+ NavigationServer3D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
}
} break;
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index b74e816d43..3032942cdd 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -43,7 +43,6 @@ class NavigationAgent3D : public Node {
Node3D *agent_parent = nullptr;
RID agent;
- RID map_before_pause;
RID map_override;
bool avoidance_enabled = false;
@@ -78,7 +77,7 @@ class NavigationAgent3D : public Node {
Vector3 safe_velocity;
/// The submitted target velocity, sets the "wanted" rvo agent velocity on the next update
- // this velocity is not guaranteed, the simulation will try to fulfil it if possible
+ // this velocity is not guaranteed, the simulation will try to fulfill it if possible
// if other agents or obstacles interfere it will be changed accordingly
Vector3 velocity;
bool velocity_submitted = false;
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 2c29991ab9..df6dd99aac 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -120,6 +120,7 @@ void NavigationObstacle3D::_notification(int p_what) {
_update_map(map_before_pause);
map_before_pause = RID();
}
+ NavigationServer3D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_UNPAUSED: {
@@ -130,6 +131,7 @@ void NavigationObstacle3D::_notification(int p_what) {
_update_map(map_before_pause);
map_before_pause = RID();
}
+ NavigationServer3D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 165d44436c..4c2f56b7b3 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -30,7 +30,8 @@
#include "navigation_region_3d.h"
-#include "mesh_instance_3d.h"
+#include "core/core_string_names.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "servers/navigation_server_3d.h"
void NavigationRegion3D::set_enabled(bool p_enabled) {
@@ -179,12 +180,10 @@ void NavigationRegion3D::_notification(int p_what) {
_update_debug_mesh();
}
#endif // DEBUG_ENABLED
-
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
set_physics_process_internal(true);
-
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -224,13 +223,13 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_naviga
}
if (navigation_mesh.is_valid()) {
- navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ navigation_mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
navigation_mesh = p_navigation_mesh;
if (navigation_mesh.is_valid()) {
- navigation_mesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ navigation_mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh);
@@ -263,6 +262,7 @@ Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
struct BakeThreadsArgs {
NavigationRegion3D *nav_region = nullptr;
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
};
void _bake_navigation_mesh(void *p_user_data) {
@@ -270,8 +270,9 @@ void _bake_navigation_mesh(void *p_user_data) {
if (args->nav_region->get_navigation_mesh().is_valid()) {
Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry_data = args->source_geometry_data;
- NavigationServer3D::get_singleton()->region_bake_navigation_mesh(nav_mesh, args->nav_region);
+ NavigationServer3D::get_singleton()->bake_from_source_geometry_data(nav_mesh, source_geometry_data);
args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
memdelete(args);
} else {
@@ -282,10 +283,18 @@ void _bake_navigation_mesh(void *p_user_data) {
}
void NavigationRegion3D::bake_navigation_mesh(bool p_on_thread) {
+ ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred().");
+ ERR_FAIL_COND_MSG(!navigation_mesh.is_valid(), "Baking the navigation mesh requires a valid `NavigationMesh` resource.");
ERR_FAIL_COND_MSG(bake_thread.is_started(), "Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh.");
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
+ source_geometry_data.instantiate();
+
+ NavigationServer3D::get_singleton()->parse_source_geometry_data(navigation_mesh, source_geometry_data, this);
+
BakeThreadsArgs *args = memnew(BakeThreadsArgs);
args->nav_region = this;
+ args->source_geometry_data = source_geometry_data;
if (p_on_thread) {
bake_thread.start(_bake_navigation_mesh, args);
@@ -371,7 +380,7 @@ bool NavigationRegion3D::_get(const StringName &p_name, Variant &r_ret) const {
}
#endif // DISABLE_DEPRECATED
-void NavigationRegion3D::_navigation_changed() {
+void NavigationRegion3D::_navigation_mesh_changed() {
update_gizmos();
update_configuration_warnings();
@@ -397,9 +406,9 @@ NavigationRegion3D::NavigationRegion3D() {
NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
- NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
- NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
+ NavigationServer3D::get_singleton()->connect(SNAME("map_changed"), callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
+ NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
+ NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
#endif // DEBUG_ENABLED
}
@@ -409,15 +418,15 @@ NavigationRegion3D::~NavigationRegion3D() {
}
if (navigation_mesh.is_valid()) {
- navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ navigation_mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(region);
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
- NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
- NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
+ NavigationServer3D::get_singleton()->disconnect(SNAME("map_changed"), callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
+ NavigationServer3D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
+ NavigationServer3D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
ERR_FAIL_NULL(RenderingServer::get_singleton());
if (debug_instance.is_valid()) {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index fd6deebd63..84b57d064f 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -50,7 +50,7 @@ class NavigationRegion3D : public Node3D {
Thread bake_thread;
- void _navigation_changed();
+ void _navigation_mesh_changed();
#ifdef DEBUG_ENABLED
RID debug_instance;
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 932e4ea549..4f9c523806 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -110,7 +110,7 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
}
for (Node3D *&E : data.children) {
- if (E->data.top_level_active) {
+ if (E->data.top_level) {
continue; //don't propagate to a top_level
}
E->_propagate_transform_changed(p_origin);
@@ -153,7 +153,7 @@ void Node3D::_notification(int p_what) {
data.local_transform = data.parent->get_global_transform() * get_transform();
_replace_dirty_mask(DIRTY_EULER_ROTATION_AND_SCALE); // As local transform was updated, rot/scale should be dirty.
}
- data.top_level_active = true;
+ data.top_level = true;
}
_set_dirty_bits(DIRTY_GLOBAL_TRANSFORM); // Global is always dirty upon entering a scene.
@@ -173,7 +173,7 @@ void Node3D::_notification(int p_what) {
}
data.parent = nullptr;
data.C = nullptr;
- data.top_level_active = false;
+ data.top_level = false;
_update_visibility_parent(true);
} break;
@@ -305,7 +305,7 @@ Quaternion Node3D::get_quaternion() const {
void Node3D::set_global_transform(const Transform3D &p_transform) {
ERR_THREAD_GUARD;
- Transform3D xform = (data.parent && !data.top_level_active)
+ Transform3D xform = (data.parent && !data.top_level)
? data.parent->get_global_transform().affine_inverse() * p_transform
: p_transform;
@@ -337,7 +337,7 @@ Transform3D Node3D::get_global_transform() const {
}
Transform3D new_global;
- if (data.parent && !data.top_level_active) {
+ if (data.parent && !data.top_level) {
new_global = data.parent->get_global_transform() * data.local_transform;
} else {
new_global = data.local_transform;
@@ -727,12 +727,8 @@ void Node3D::set_as_top_level(bool p_enabled) {
} else if (data.parent) {
set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
}
-
- data.top_level = p_enabled;
- data.top_level_active = p_enabled;
- } else {
- data.top_level = p_enabled;
}
+ data.top_level = p_enabled;
}
bool Node3D::is_set_as_top_level() const {
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 935f0b149a..3b6583174f 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -101,7 +101,6 @@ private:
Viewport *viewport = nullptr;
- bool top_level_active = false;
bool top_level = false;
bool inside_world = false;
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index c71f80ea0e..9516973ae2 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -361,6 +361,8 @@ void PathFollow3D::set_progress(real_t p_progress) {
if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
progress = path_length;
}
+ } else {
+ progress = CLAMP(progress, 0, path_length);
}
}
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index d0c186fb29..e23703a6dc 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -274,9 +274,9 @@ void VehicleWheel3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel3D::get_steering);
ADD_GROUP("Per-Wheel Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, U"-1024,1024.0,0.01,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_engine_force", "get_engine_force");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, U"0.0,1.0,0.01,suffix:kg\u22C5m/s\u00B2 (N)"), "set_brake", "get_brake");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01,radians"), "set_steering", "get_steering");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, U"-1024,1024,0.01,or_less,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, U"-128,128,0.01,or_less,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_brake", "get_brake");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_steering", "get_steering");
ADD_GROUP("VehicleBody3D Motion", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
@@ -918,9 +918,9 @@ void VehicleBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody3D::get_steering);
ADD_GROUP("Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, U"-1024,1024.0,0.01,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_engine_force", "get_engine_force");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, U"0.0,1.0,0.01,suffix:kg\u22C5m/s\u00B2 (N)"), "set_brake", "get_brake");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01,radians"), "set_steering", "get_steering");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, U"-1024,1024,0.01,or_less,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, U"-128,128,0.01,or_less,or_greater,suffix:kg\u22C5m/s\u00B2 (N)"), "set_brake", "get_brake");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_steering", "get_steering");
}
VehicleBody3D::VehicleBody3D() {
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index e5b77654cf..3ac3ca7363 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -366,11 +366,9 @@ void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
if (toggle_mode) {
status.pressed = !status.pressed;
- if (status.pressed) {
- _unpress_group();
- if (button_group.is_valid()) {
- button_group->emit_signal(SNAME("pressed"), this);
- }
+ _unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal(SNAME("pressed"), this);
}
_toggled(status.pressed);
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index efbc067d20..c453d86264 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -3326,8 +3326,6 @@ CodeEdit::~CodeEdit() {
// Return true if l should come before r
bool CodeCompletionOptionCompare::operator()(const ScriptLanguage::CodeCompletionOption &l, const ScriptLanguage::CodeCompletionOption &r) const {
- // Check if we are not completing an empty string in this case there is no reason to get matches characteristics.
-
TypedArray<int> lcharac = l.get_option_cached_characteristics();
TypedArray<int> rcharac = r.get_option_cached_characteristics();
@@ -3344,5 +3342,5 @@ bool CodeCompletionOptionCompare::operator()(const ScriptLanguage::CodeCompletio
return l.matches[i].second > r.matches[i].second;
}
}
- return l.display < r.display;
+ return l.display.naturalnocasecmp_to(r.display) < 0;
}
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 0860bf3968..9e99bda60b 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -44,12 +44,6 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) {
}
}
-void AcceptDialog::_parent_focused() {
- if (close_on_escape && !is_exclusive()) {
- _cancel_pressed();
- }
-}
-
void AcceptDialog::_update_theme_item_cache() {
Window::_update_theme_item_cache();
@@ -70,16 +64,6 @@ void AcceptDialog::_notification(int p_what) {
get_ok_button()->grab_focus();
}
_update_child_rects();
-
- parent_visible = get_parent_visible_window();
- if (parent_visible) {
- parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
- }
- } else {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
- parent_visible = nullptr;
- }
}
} break;
@@ -92,10 +76,9 @@ void AcceptDialog::_notification(int p_what) {
}
} break;
- case NOTIFICATION_EXIT_TREE: {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
- parent_visible = nullptr;
+ case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
+ if (close_on_escape && !is_exclusive()) {
+ _cancel_pressed();
}
} break;
@@ -129,21 +112,9 @@ void AcceptDialog::_ok_pressed() {
}
void AcceptDialog::_cancel_pressed() {
- Window *parent_window = parent_visible;
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
- parent_visible = nullptr;
- }
-
call_deferred(SNAME("hide"));
-
emit_signal(SNAME("canceled"));
-
cancel_pressed();
-
- if (parent_window) {
- //parent_window->grab_focus();
- }
set_input_as_handled();
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 1821a886c0..ebe5ce326a 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -44,8 +44,6 @@ class LineEdit;
class AcceptDialog : public Window {
GDCLASS(AcceptDialog, Window);
- Window *parent_visible = nullptr;
-
Panel *bg_panel = nullptr;
Label *message_label = nullptr;
HBoxContainer *buttons_hbox = nullptr;
@@ -65,7 +63,6 @@ class AcceptDialog : public Window {
static bool swap_cancel_ok;
void _input_from_window(const Ref<InputEvent> &p_event);
- void _parent_focused();
protected:
virtual Size2 _get_contents_minimum_size() const override;
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 2a3956dd22..d8ec581089 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -131,7 +131,6 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) {
screen_pos.x += screen_size.x - pm->get_size().width;
}
pm->set_position(screen_pos);
- pm->set_parent_rect(Rect2(Point2(screen_pos - pm->get_position()), Size2(screen_size.x, screen_pos.y)));
pm->popup();
if (p_focus_item) {
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 3074bc369f..4e80d7a2d6 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -97,16 +97,14 @@ void MenuButton::show_popup() {
}
emit_signal(SNAME("about_to_popup"));
- Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
-
- popup->set_size(Size2(size.width, 0));
- Point2 gp = get_screen_position();
- gp.y += size.y;
+ Rect2 rect = get_screen_rect();
+ rect.position.y += rect.size.height;
+ rect.size.height = 0;
+ popup->set_size(rect.size);
if (is_layout_rtl()) {
- gp.x += size.width - popup->get_size().width;
+ rect.position.x += rect.size.width - popup->get_size().width;
}
- popup->set_position(gp);
- popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size));
+ popup->set_position(rect.position);
// If not triggered by the mouse, start the popup with its first enabled item focused.
if (!_was_pressed_by_mouse()) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 445edc1ef9..adeaf9a49f 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -2033,10 +2033,6 @@ String PopupMenu::get_tooltip(const Point2 &p_pos) const {
return items[over].tooltip;
}
-void PopupMenu::set_parent_rect(const Rect2 &p_rect) {
- parent_rect = p_rect;
-}
-
void PopupMenu::add_autohide_area(const Rect2 &p_area) {
autohide_areas.push_back(p_area);
}
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 892559ba3c..572467bf94 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -98,7 +98,6 @@ class PopupMenu : public Popup {
bool during_grabbed_click = false;
int mouse_over = -1;
int submenu_over = -1;
- Rect2 parent_rect;
String _get_accel_text(const Item &p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 _get_contents_minimum_size() const override;
@@ -292,8 +291,6 @@ public:
void clear();
- void set_parent_rect(const Rect2 &p_rect);
-
virtual String get_tooltip(const Point2 &p_pos) const;
void add_autohide_area(const Rect2 &p_area);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index fe3139c173..9409ae2315 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -2781,6 +2781,44 @@ int RichTextLabel::get_progress_bar_delay() const {
return progress_delay;
}
+_FORCE_INLINE_ float RichTextLabel::_update_scroll_exceeds(float p_total_height, float p_ctrl_height, float p_width, int p_idx, float p_old_scroll, float p_text_rect_height) {
+ updating_scroll = true;
+
+ float total_height = p_total_height;
+ bool exceeds = p_total_height > p_ctrl_height && scroll_active;
+ if (exceeds != scroll_visible) {
+ if (exceeds) {
+ scroll_visible = true;
+ scroll_w = vscroll->get_combined_minimum_size().width;
+ vscroll->show();
+ vscroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -scroll_w);
+ } else {
+ scroll_visible = false;
+ scroll_w = 0;
+ vscroll->hide();
+ }
+
+ main->first_resized_line.store(0);
+
+ total_height = 0;
+ for (int j = 0; j <= p_idx; j++) {
+ total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, p_width, total_height);
+
+ main->first_resized_line.store(j);
+ }
+ }
+ vscroll->set_max(total_height);
+ vscroll->set_page(p_text_rect_height);
+ if (scroll_follow && scroll_following) {
+ vscroll->set_value(total_height);
+ } else {
+ vscroll->set_value(p_old_scroll);
+ }
+ updating_scroll = false;
+
+ return total_height;
+}
+
bool RichTextLabel::_validate_line_caches() {
if (updating.load()) {
return false;
@@ -2790,7 +2828,7 @@ bool RichTextLabel::_validate_line_caches() {
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
- int ctrl_height = get_size().height;
+ float ctrl_height = get_size().height;
// Update fonts.
float old_scroll = vscroll->get_value();
@@ -2814,40 +2852,7 @@ bool RichTextLabel::_validate_line_caches() {
float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
-
- updating_scroll = true;
- bool exceeds = total_height > ctrl_height && scroll_active;
- if (exceeds != scroll_visible) {
- if (exceeds) {
- scroll_visible = true;
- scroll_w = vscroll->get_combined_minimum_size().width;
- vscroll->show();
- vscroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -scroll_w);
- } else {
- scroll_visible = false;
- scroll_w = 0;
- vscroll->hide();
- }
-
- main->first_resized_line.store(0);
-
- total_height = 0;
- for (int j = 0; j <= i; j++) {
- total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
-
- main->first_resized_line.store(j);
- }
- }
-
- vscroll->set_max(total_height);
- vscroll->set_page(text_rect.size.height);
- if (scroll_follow && scroll_following) {
- vscroll->set_value(total_height);
- } else {
- vscroll->set_value(old_scroll);
- }
- updating_scroll = false;
-
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
main->first_resized_line.store(i);
}
@@ -2886,47 +2891,34 @@ void RichTextLabel::_process_line_caches() {
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
- int ctrl_height = get_size().height;
+ float ctrl_height = get_size().height;
int fi = main->first_invalid_line.load();
int total_chars = main->lines[fi].char_offset;
+ float old_scroll = vscroll->get_value();
- float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
- for (int i = fi; i < (int)main->lines.size(); i++) {
- total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
- updating_scroll = true;
- bool exceeds = total_height > ctrl_height && scroll_active;
- if (exceeds != scroll_visible) {
- if (exceeds) {
- scroll_visible = true;
- scroll_w = vscroll->get_combined_minimum_size().width;
- vscroll->show();
- vscroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -scroll_w);
- } else {
- scroll_visible = false;
- scroll_w = 0;
- vscroll->hide();
- }
- main->first_invalid_line.store(0);
- main->first_resized_line.store(0);
- main->first_invalid_font_line.store(0);
-
- // since scroll was added or removed we need to resize all lines
- total_height = 0;
- for (int j = 0; j <= i; j++) {
- total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
+ float total_height = 0;
+ if (fi != 0) {
+ // Update fonts.
- main->first_invalid_line.store(j);
- main->first_resized_line.store(j);
- main->first_invalid_font_line.store(j);
- }
+ for (int i = main->first_invalid_font_line.load(); i < fi; i++) {
+ _update_line_font(main, i, theme_cache.normal_font, theme_cache.normal_font_size);
}
- vscroll->set_max(total_height);
- vscroll->set_page(text_rect.size.height);
- if (scroll_follow && scroll_following) {
- vscroll->set_value(total_height);
+ // Resize lines without reshaping.
+ int sr = MIN(main->first_invalid_font_line.load(), main->first_resized_line.load());
+ main->first_invalid_font_line.store(fi);
+
+ for (int i = sr; i < fi; i++) {
+ total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
+
+ main->first_resized_line.store(i);
}
- updating_scroll = false;
+ }
+
+ for (int i = fi; i < (int)main->lines.size(); i++) {
+ total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
main->first_invalid_line.store(i);
main->first_resized_line.store(i);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index cbdad3e4d7..66891ab567 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -421,6 +421,7 @@ private:
void _stop_thread();
bool _validate_line_caches();
void _process_line_caches();
+ _FORCE_INLINE_ float _update_scroll_exceeds(float p_total_height, float p_ctrl_height, float p_width, int p_idx, float p_old_scroll, float p_text_rect_height);
void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 039fa46bb0..3b2013f7ec 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -112,6 +112,14 @@ float TextEdit::Text::get_width() const {
return width;
}
+void TextEdit::Text::set_brk_flags(BitField<TextServer::LineBreakFlag> p_flags) {
+ brk_flags = p_flags;
+}
+
+BitField<TextServer::LineBreakFlag> TextEdit::Text::get_brk_flags() const {
+ return brk_flags;
+}
+
int TextEdit::Text::get_line_wrap_amount(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
@@ -180,6 +188,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan
text.write[p_line].data_buf->set_width(width);
text.write[p_line].data_buf->set_direction((TextServer::Direction)direction);
+ text.write[p_line].data_buf->set_break_flags(brk_flags);
text.write[p_line].data_buf->set_preserve_control(draw_control_chars);
if (p_ime_text.length() > 0) {
if (p_text_changed) {
@@ -247,21 +256,19 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan
void TextEdit::Text::invalidate_all_lines() {
for (int i = 0; i < text.size(); i++) {
text.write[i].data_buf->set_width(width);
+ text.write[i].data_buf->set_break_flags(brk_flags);
if (tab_size_dirty) {
if (tab_size > 0) {
Vector<float> tabs;
tabs.push_back(font->get_char_size(' ', font_size).width * tab_size);
text.write[i].data_buf->tab_align(tabs);
}
- // Tabs have changes, force width update.
- text.write[i].width = get_line_width(i);
}
+ text.write[i].width = get_line_width(i);
}
+ tab_size_dirty = false;
- if (tab_size_dirty) {
- _calculate_max_line_width();
- tab_size_dirty = false;
- }
+ _calculate_max_line_width();
}
void TextEdit::Text::invalidate_font() {
@@ -2935,6 +2942,7 @@ void TextEdit::_update_placeholder() {
// Placeholder is generally smaller then text documents, and updates less so this should be fast enough for now.
placeholder_data_buf->clear();
placeholder_data_buf->set_width(text.get_width());
+ placeholder_data_buf->set_break_flags(text.get_brk_flags());
placeholder_data_buf->set_direction((TextServer::Direction)text_direction);
placeholder_data_buf->set_preserve_control(draw_control_chars);
placeholder_data_buf->add_string(placeholder_text, theme_cache.font, theme_cache.font_size, language);
@@ -5256,6 +5264,7 @@ void TextEdit::set_line_wrapping_mode(LineWrappingMode p_wrapping_mode) {
if (line_wrapping_mode != p_wrapping_mode) {
line_wrapping_mode = p_wrapping_mode;
_update_wrap_at_column(true);
+ queue_redraw();
}
}
@@ -5263,6 +5272,22 @@ TextEdit::LineWrappingMode TextEdit::get_line_wrapping_mode() const {
return line_wrapping_mode;
}
+void TextEdit::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
+ if (autowrap_mode == p_mode) {
+ return;
+ }
+
+ autowrap_mode = p_mode;
+ if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE) {
+ _update_wrap_at_column(true);
+ queue_redraw();
+ }
+}
+
+TextServer::AutowrapMode TextEdit::get_autowrap_mode() const {
+ return autowrap_mode;
+}
+
bool TextEdit::is_line_wrapped(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
if (get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
@@ -5540,37 +5565,32 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) {
}
visible_width -= 20; // Give it a little more space.
- if (get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
- // Adjust x offset.
- Vector2i caret_pos;
+ Vector2i caret_pos;
- // Get position of the start of caret.
- if (ime_text.length() != 0 && ime_selection.x != 0) {
- caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
- } else {
- caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
- }
+ // Get position of the start of caret.
+ if (ime_text.length() != 0 && ime_selection.x != 0) {
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
+ } else {
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
+ }
- // Get position of the end of caret.
- if (ime_text.length() != 0) {
- if (ime_selection.y != 0) {
- caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
- } else {
- caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
- }
+ // Get position of the end of caret.
+ if (ime_text.length() != 0) {
+ if (ime_selection.y != 0) {
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
- caret_pos.y = caret_pos.x;
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
}
+ } else {
+ caret_pos.y = caret_pos.x;
+ }
- if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) {
- first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
- }
+ if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) {
+ first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
+ }
- if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) {
- first_visible_col = MIN(caret_pos.x, caret_pos.y);
- }
- } else {
- first_visible_col = 0;
+ if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) {
+ first_visible_col = MIN(caret_pos.x, caret_pos.y);
}
h_scroll->set_value(first_visible_col);
@@ -6280,6 +6300,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_line_wrapping_mode", "mode"), &TextEdit::set_line_wrapping_mode);
ClassDB::bind_method(D_METHOD("get_line_wrapping_mode"), &TextEdit::get_line_wrapping_mode);
+ ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &TextEdit::set_autowrap_mode);
+ ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &TextEdit::get_autowrap_mode);
+
ClassDB::bind_method(D_METHOD("is_line_wrapped", "line"), &TextEdit::is_line_wrapped);
ClassDB::bind_method(D_METHOD("get_line_wrap_count", "line"), &TextEdit::get_line_wrap_count);
ClassDB::bind_method(D_METHOD("get_line_wrap_index_at_column", "line", "column"), &TextEdit::get_line_wrap_index_at_column);
@@ -6415,6 +6438,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
@@ -7222,10 +7246,26 @@ void TextEdit::_update_wrap_at_column(bool p_force) {
if ((wrap_at_column != new_wrap_at) || p_force) {
wrap_at_column = new_wrap_at;
if (line_wrapping_mode) {
+ BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
+ switch (autowrap_mode) {
+ case TextServer::AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_WORD:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_ARBITRARY:
+ autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_OFF:
+ break;
+ }
+ text.set_brk_flags(autowrap_flags);
text.set_width(wrap_at_column);
} else {
text.set_width(-1);
}
+
text.invalidate_all_lines();
_update_placeholder();
}
@@ -7293,7 +7333,7 @@ void TextEdit::_update_scrollbars() {
v_scroll->hide();
}
- if (total_width > visible_width && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
+ if (total_width > visible_width) {
h_scroll->show();
h_scroll->set_max(total_width);
h_scroll->set_page(visible_width);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 6eed200a28..83f6d58bea 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -172,6 +172,7 @@ private:
String language;
TextServer::Direction direction = TextServer::DIRECTION_AUTO;
+ BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY;
bool draw_control_chars = false;
int line_height = -1;
@@ -198,6 +199,8 @@ private:
void set_width(float p_width);
float get_width() const;
+ void set_brk_flags(BitField<TextServer::LineBreakFlag> p_flags);
+ BitField<TextServer::LineBreakFlag> get_brk_flags() const;
int get_line_wrap_amount(int p_line) const;
Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
@@ -460,6 +463,7 @@ private:
/* Line wrapping. */
LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE;
+ TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_WORD_SMART;
int wrap_at_column = 0;
int wrap_right_offset = 10;
@@ -894,6 +898,9 @@ public:
void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode);
LineWrappingMode get_line_wrapping_mode() const;
+ void set_autowrap_mode(TextServer::AutowrapMode p_mode);
+ TextServer::AutowrapMode get_autowrap_mode() const;
+
bool is_line_wrapped(int p_line) const;
int get_line_wrap_count(int p_line) const;
int get_line_wrap_index_at_column(int p_line, int p_column) const;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 54e1b02518..ea89a719e8 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -46,11 +46,6 @@
#include <stdint.h>
-VARIANT_ENUM_CAST(Node::ProcessMode);
-VARIANT_ENUM_CAST(Node::ProcessThreadGroup);
-VARIANT_BITFIELD_CAST(Node::ProcessThreadMessages);
-VARIANT_ENUM_CAST(Node::InternalMode);
-
int Node::orphan_node_count = 0;
thread_local Node *Node::current_process_thread_group = nullptr;
@@ -3446,9 +3441,9 @@ void Node::_bind_methods() {
BIND_ENUM_CONSTANT(PROCESS_THREAD_GROUP_MAIN_THREAD);
BIND_ENUM_CONSTANT(PROCESS_THREAD_GROUP_SUB_THREAD);
- BIND_ENUM_CONSTANT(FLAG_PROCESS_THREAD_MESSAGES);
- BIND_ENUM_CONSTANT(FLAG_PROCESS_THREAD_MESSAGES_PHYSICS);
- BIND_ENUM_CONSTANT(FLAG_PROCESS_THREAD_MESSAGES_ALL);
+ BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES);
+ BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_PHYSICS);
+ BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_ALL);
BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS);
BIND_ENUM_CONSTANT(DUPLICATE_GROUPS);
diff --git a/scene/main/node.h b/scene/main/node.h
index bb29e473e0..ed8f699d7b 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -711,6 +711,10 @@ public:
};
VARIANT_ENUM_CAST(Node::DuplicateFlags);
+VARIANT_ENUM_CAST(Node::ProcessMode);
+VARIANT_ENUM_CAST(Node::ProcessThreadGroup);
+VARIANT_BITFIELD_CAST(Node::ProcessThreadMessages);
+VARIANT_ENUM_CAST(Node::InternalMode);
typedef HashSet<Node *, Node::Comparator> NodeSet;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index e071011c48..6eec6b8371 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -456,7 +456,9 @@ bool SceneTree::physics_process(double p_time) {
flush_transform_notifications();
- MainLoop::physics_process(p_time);
+ if (MainLoop::physics_process(p_time)) {
+ _quit = true;
+ }
physics_process_time = p_time;
emit_signal(SNAME("physics_frame"));
@@ -484,7 +486,9 @@ bool SceneTree::physics_process(double p_time) {
bool SceneTree::process(double p_time) {
root_lock++;
- MainLoop::process(p_time);
+ if (MainLoop::process(p_time)) {
+ _quit = true;
+ }
process_time = p_time;
@@ -737,14 +741,6 @@ void SceneTree::set_debug_navigation_hint(bool p_enabled) {
bool SceneTree::is_debugging_navigation_hint() const {
return debug_navigation_hint;
}
-
-void SceneTree::set_debug_avoidance_hint(bool p_enabled) {
- debug_avoidance_hint = p_enabled;
-}
-
-bool SceneTree::is_debugging_avoidance_hint() const {
- return debug_avoidance_hint;
-}
#endif
void SceneTree::set_debug_collisions_color(const Color &p_color) {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 4e7a10c7e9..452fac7423 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -132,7 +132,6 @@ private:
bool debug_collisions_hint = false;
bool debug_paths_hint = false;
bool debug_navigation_hint = false;
- bool debug_avoidance_hint = false;
#endif
bool paused = false;
int root_lock = 0;
@@ -185,12 +184,8 @@ private:
Color debug_collision_contact_color;
Color debug_paths_color;
float debug_paths_width = 1.0f;
- Color debug_navigation_color;
- Color debug_navigation_disabled_color;
Ref<ArrayMesh> debug_contact_mesh;
Ref<Material> debug_paths_material;
- Ref<Material> navigation_material;
- Ref<Material> navigation_disabled_material;
Ref<Material> collision_material;
int collision_debug_contacts;
@@ -351,9 +346,6 @@ public:
void set_debug_navigation_hint(bool p_enabled);
bool is_debugging_navigation_hint() const;
-
- void set_debug_avoidance_hint(bool p_enabled);
- bool is_debugging_avoidance_hint() const;
#else
void set_debug_collisions_hint(bool p_enabled) {}
bool is_debugging_collisions_hint() const { return false; }
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index b82b215e54..e8395f59c9 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -616,6 +616,8 @@ void Window::_update_from_window() {
void Window::_clear_window() {
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+ bool had_focus = has_focus();
+
DisplayServer::get_singleton()->window_set_rect_changed_callback(Callable(), window_id);
DisplayServer::get_singleton()->window_set_window_event_callback(Callable(), window_id);
DisplayServer::get_singleton()->window_set_input_event_callback(Callable(), window_id);
@@ -638,7 +640,7 @@ void Window::_clear_window() {
window_id = DisplayServer::INVALID_WINDOW_ID;
// If closing window was focused and has a parent, return focus.
- if (focused && transient_parent) {
+ if (had_focus && transient_parent) {
transient_parent->grab_focus();
}
@@ -1185,6 +1187,7 @@ void Window::_notification(int p_what) {
{
position = DisplayServer::get_singleton()->window_get_position(window_id);
size = DisplayServer::get_singleton()->window_get_size(window_id);
+ focused = DisplayServer::get_singleton()->window_is_focused(window_id);
}
_update_window_size(); // Inform DisplayServer of minimum and maximum size.
_update_viewport_size(); // Then feed back to the viewport.
@@ -1762,6 +1765,9 @@ void Window::grab_focus() {
bool Window::has_focus() const {
ERR_READ_THREAD_GUARD_V(false);
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_is_focused(window_id);
+ }
return focused;
}
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index a4fe24dfd9..9706fb1a5d 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -165,6 +165,7 @@
#include "scene/resources/mesh_data_tool.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/particle_process_material.h"
@@ -930,6 +931,7 @@ void register_scene_types() {
GDREGISTER_CLASS(PathFollow2D);
GDREGISTER_CLASS(NavigationMesh);
+ GDREGISTER_CLASS(NavigationMeshSourceGeometryData3D);
GDREGISTER_CLASS(NavigationPolygon);
GDREGISTER_CLASS(NavigationRegion2D);
GDREGISTER_CLASS(NavigationAgent2D);
diff --git a/scene/resources/navigation_mesh_source_geometry_data_3d.cpp b/scene/resources/navigation_mesh_source_geometry_data_3d.cpp
new file mode 100644
index 0000000000..0201fb70b2
--- /dev/null
+++ b/scene/resources/navigation_mesh_source_geometry_data_3d.cpp
@@ -0,0 +1,181 @@
+/**************************************************************************/
+/* navigation_mesh_source_geometry_data_3d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "navigation_mesh_source_geometry_data_3d.h"
+
+void NavigationMeshSourceGeometryData3D::set_vertices(const Vector<float> &p_vertices) {
+ vertices = p_vertices;
+}
+
+void NavigationMeshSourceGeometryData3D::set_indices(const Vector<int> &p_indices) {
+ indices = p_indices;
+}
+
+void NavigationMeshSourceGeometryData3D::clear() {
+ vertices.clear();
+ indices.clear();
+}
+
+void NavigationMeshSourceGeometryData3D::_add_vertex(const Vector3 &p_vec3) {
+ vertices.push_back(p_vec3.x);
+ vertices.push_back(p_vec3.y);
+ vertices.push_back(p_vec3.z);
+}
+
+void NavigationMeshSourceGeometryData3D::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
+ int current_vertex_count;
+ for (int i = 0; i < p_mesh->get_surface_count(); i++) {
+ current_vertex_count = vertices.size() / 3;
+
+ if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ int index_count = 0;
+ if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ index_count = p_mesh->surface_get_array_index_len(i);
+ } else {
+ index_count = p_mesh->surface_get_array_len(i);
+ }
+
+ ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
+
+ int face_count = index_count / 3;
+
+ Array a = p_mesh->surface_get_arrays(i);
+
+ Vector<Vector3> mesh_vertices = a[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = mesh_vertices.ptr();
+
+ if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ Vector<int> mesh_indices = a[Mesh::ARRAY_INDEX];
+ const int *ir = mesh_indices.ptr();
+
+ for (int j = 0; j < mesh_vertices.size(); j++) {
+ _add_vertex(p_xform.xform(vr[j]));
+ }
+
+ for (int j = 0; j < face_count; j++) {
+ // CCW
+ indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
+ indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
+ indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
+ }
+ } else {
+ face_count = mesh_vertices.size() / 3;
+ for (int j = 0; j < face_count; j++) {
+ _add_vertex(p_xform.xform(vr[j * 3 + 0]));
+ _add_vertex(p_xform.xform(vr[j * 3 + 2]));
+ _add_vertex(p_xform.xform(vr[j * 3 + 1]));
+
+ indices.push_back(current_vertex_count + (j * 3 + 0));
+ indices.push_back(current_vertex_count + (j * 3 + 1));
+ indices.push_back(current_vertex_count + (j * 3 + 2));
+ }
+ }
+ }
+}
+
+void NavigationMeshSourceGeometryData3D::_add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
+ Vector<Vector3> mesh_vertices = p_mesh_array[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = mesh_vertices.ptr();
+
+ Vector<int> mesh_indices = p_mesh_array[Mesh::ARRAY_INDEX];
+ const int *ir = mesh_indices.ptr();
+
+ const int face_count = mesh_indices.size() / 3;
+ const int current_vertex_count = vertices.size() / 3;
+
+ for (int j = 0; j < mesh_vertices.size(); j++) {
+ _add_vertex(p_xform.xform(vr[j]));
+ }
+
+ for (int j = 0; j < face_count; j++) {
+ // CCW
+ indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
+ indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
+ indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
+ }
+}
+
+void NavigationMeshSourceGeometryData3D::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
+ int face_count = p_faces.size() / 3;
+ int current_vertex_count = vertices.size() / 3;
+
+ for (int j = 0; j < face_count; j++) {
+ _add_vertex(p_xform.xform(p_faces[j * 3 + 0]));
+ _add_vertex(p_xform.xform(p_faces[j * 3 + 1]));
+ _add_vertex(p_xform.xform(p_faces[j * 3 + 2]));
+
+ indices.push_back(current_vertex_count + (j * 3 + 0));
+ indices.push_back(current_vertex_count + (j * 3 + 2));
+ indices.push_back(current_vertex_count + (j * 3 + 1));
+ }
+}
+
+void NavigationMeshSourceGeometryData3D::add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
+ ERR_FAIL_COND(!p_mesh.is_valid());
+ _add_mesh(p_mesh, root_node_transform * p_xform);
+}
+
+void NavigationMeshSourceGeometryData3D::add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
+ ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);
+ _add_mesh_array(p_mesh_array, root_node_transform * p_xform);
+}
+
+void NavigationMeshSourceGeometryData3D::add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
+ ERR_FAIL_COND(p_faces.size() % 3 != 0);
+ _add_faces(p_faces, root_node_transform * p_xform);
+}
+
+void NavigationMeshSourceGeometryData3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMeshSourceGeometryData3D::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMeshSourceGeometryData3D::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &NavigationMeshSourceGeometryData3D::set_indices);
+ ClassDB::bind_method(D_METHOD("get_indices"), &NavigationMeshSourceGeometryData3D::get_indices);
+
+ ClassDB::bind_method(D_METHOD("clear"), &NavigationMeshSourceGeometryData3D::clear);
+ ClassDB::bind_method(D_METHOD("has_data"), &NavigationMeshSourceGeometryData3D::has_data);
+
+ ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh);
+ ClassDB::bind_method(D_METHOD("add_mesh_array", "mesh_array", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh_array);
+ ClassDB::bind_method(D_METHOD("add_faces", "faces", "xform"), &NavigationMeshSourceGeometryData3D::add_faces);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");
+}
+
+NavigationMeshSourceGeometryData3D::NavigationMeshSourceGeometryData3D() {
+}
+
+NavigationMeshSourceGeometryData3D::~NavigationMeshSourceGeometryData3D() {
+ clear();
+}
diff --git a/scene/resources/navigation_mesh_source_geometry_data_3d.h b/scene/resources/navigation_mesh_source_geometry_data_3d.h
new file mode 100644
index 0000000000..ec8bddd4dd
--- /dev/null
+++ b/scene/resources/navigation_mesh_source_geometry_data_3d.h
@@ -0,0 +1,75 @@
+/**************************************************************************/
+/* navigation_mesh_source_geometry_data_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H
+#define NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+
+class NavigationMeshSourceGeometryData3D : public Resource {
+ GDCLASS(NavigationMeshSourceGeometryData3D, Resource);
+
+ Vector<float> vertices;
+ Vector<int> indices;
+
+protected:
+ static void _bind_methods();
+
+private:
+ void _add_vertex(const Vector3 &p_vec3);
+ void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform);
+ void _add_mesh_array(const Array &p_array, const Transform3D &p_xform);
+ void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform);
+
+public:
+ // kept root node transform here on the geometry data
+ // if we add this transform to all exposed functions we need to break comp on all functions later
+ // when navmesh changes from global transform to relative to navregion
+ // but if it stays here we can just remove it and change the internal functions only
+ Transform3D root_node_transform;
+
+ void set_vertices(const Vector<float> &p_vertices);
+ const Vector<float> &get_vertices() const { return vertices; }
+
+ void set_indices(const Vector<int> &p_indices);
+ const Vector<int> &get_indices() const { return indices; }
+
+ bool has_data() { return vertices.size() && indices.size(); };
+ void clear();
+
+ void add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform);
+ void add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform);
+ void add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform);
+
+ NavigationMeshSourceGeometryData3D();
+ ~NavigationMeshSourceGeometryData3D();
+};
+
+#endif // NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index f84dfe0d7a..23942658cc 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -473,7 +473,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
const String base_property = string_property.get_slice("/", 0);
const int index = string_property.get_slice("/", 2).to_int();
- Array array = dnp.base->get(base_property);
+ bool valid;
+ Array array = dnp.base->get(base_property, &valid);
+ ERR_CONTINUE(!valid);
+
if (array.size() >= index) {
array.push_back(other);
} else {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index b0449f0a26..837aa39ce1 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2692,7 +2692,7 @@ Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
- RWLockRead r(rw_lock);
+ RWLockWrite r(rw_lock);
frames[p_frame].duration = p_duration;
}
@@ -2708,6 +2708,8 @@ float AnimatedTexture::get_frame_duration(int p_frame) const {
void AnimatedTexture::set_speed_scale(float p_scale) {
ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
+ RWLockWrite r(rw_lock);
+
speed_scale = p_scale;
}
@@ -2804,7 +2806,7 @@ void AnimatedTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_greater,or_lesser"), "set_speed_scale", "get_speed_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_less,or_greater"), "set_speed_scale", "get_speed_scale");
for (int i = 0; i < MAX_FRAMES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index ec9f4806a0..08853679e1 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -2563,7 +2563,7 @@ void TileSet::_compatibility_conversion() {
Transform2D xform;
xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
- xform = transpose ? xform.rotated(Math_PI).scaled(Size2(-1, -1)) : xform;
+ xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
int alternative_tile = 0;
if (!atlas_source->has_tile(coords)) {
@@ -2677,7 +2677,7 @@ void TileSet::_compatibility_conversion() {
Transform2D xform;
xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
- xform = transpose ? xform.rotated(Math_PI).scaled(Size2(-1, -1)) : xform;
+ xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
int alternative_tile = 0;
if (!atlas_source->has_tile(coords)) {
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 516f2f1be6..41fa0d2d47 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -716,6 +716,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_move_to_foreground", "window_id"), &DisplayServer::window_move_to_foreground, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_is_focused", "window_id"), &DisplayServer::window_is_focused, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_can_draw", "window_id"), &DisplayServer::window_can_draw, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_set_transient", "window_id", "parent_window_id"), &DisplayServer::window_set_transient);
diff --git a/servers/display_server.h b/servers/display_server.h
index d8e67b4f92..fc8207f2d3 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -424,6 +424,7 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const = 0;
virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {}
virtual Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector3i(); }
diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h
index 0c43b84f2e..af13f8db21 100644
--- a/servers/display_server_headless.h
+++ b/servers/display_server_headless.h
@@ -119,6 +119,7 @@ public:
void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override {}
void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override {}
+ bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override { return true; };
bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override { return false; }
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 4b3bb421d1..e906db2acf 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -433,6 +433,8 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_get_avoidance_enabled", "agent"), &NavigationServer2D::agent_get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map);
+ ClassDB::bind_method(D_METHOD("agent_set_paused", "agent", "paused"), &NavigationServer2D::agent_set_paused);
+ ClassDB::bind_method(D_METHOD("agent_get_paused", "agent"), &NavigationServer2D::agent_get_paused);
ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer2D::agent_set_neighbor_distance);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon_agents", "agent", "time_horizon"), &NavigationServer2D::agent_set_time_horizon_agents);
@@ -453,6 +455,8 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer2D::obstacle_get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer2D::obstacle_set_map);
ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer2D::obstacle_get_map);
+ ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &NavigationServer2D::obstacle_set_paused);
+ ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &NavigationServer2D::obstacle_get_paused);
ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer2D::obstacle_set_radius);
ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer2D::obstacle_set_velocity);
ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer2D::obstacle_set_position);
@@ -594,6 +598,8 @@ void FORWARD_2(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid
void FORWARD_2(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3);
bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
+void FORWARD_2(agent_set_paused, RID, p_agent, bool, p_paused, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(agent_get_paused, RID, p_agent, rid_to_rid);
void FORWARD_1(free, RID, p_object, rid_to_rid);
void FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable);
@@ -610,6 +616,8 @@ void FORWARD_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled,
bool FORWARD_1_C(obstacle_get_avoidance_enabled, RID, p_obstacle, rid_to_rid);
void FORWARD_2(obstacle_set_map, RID, p_obstacle, RID, p_map, rid_to_rid, rid_to_rid);
RID FORWARD_1_C(obstacle_get_map, RID, p_obstacle, rid_to_rid);
+void FORWARD_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(obstacle_get_paused, RID, p_obstacle, rid_to_rid);
void FORWARD_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius, rid_to_rid, real_to_real);
void FORWARD_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity, rid_to_rid, v2_to_v3);
void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 36c964e2ea..b9b1e2a75e 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -178,6 +178,10 @@ public:
/// Put the agent in the map.
virtual void agent_set_map(RID p_agent, RID p_map);
virtual RID agent_get_map(RID p_agent) const;
+
+ virtual void agent_set_paused(RID p_agent, bool p_paused);
+ virtual bool agent_get_paused(RID p_agent) const;
+
virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled);
virtual bool agent_get_avoidance_enabled(RID p_agent) const;
@@ -222,7 +226,7 @@ public:
virtual void agent_set_velocity_forced(RID p_agent, Vector2 p_velocity);
/// The wanted velocity for the agent as a "suggestion" to the avoidance simulation.
- /// The simulation will try to fulfil this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
+ /// The simulation will try to fulfill this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity);
/// Position of the agent in world space.
@@ -244,6 +248,8 @@ public:
virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const;
virtual void obstacle_set_map(RID p_obstacle, RID p_map);
virtual RID obstacle_get_map(RID p_obstacle) const;
+ virtual void obstacle_set_paused(RID p_obstacle, bool p_paused);
+ virtual bool obstacle_get_paused(RID p_obstacle) const;
virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius);
virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity);
virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position);
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 45b85a616e..904bbfaf60 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -113,6 +113,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer3D::agent_get_map);
+ ClassDB::bind_method(D_METHOD("agent_set_paused", "agent", "paused"), &NavigationServer3D::agent_set_paused);
+ ClassDB::bind_method(D_METHOD("agent_get_paused", "agent"), &NavigationServer3D::agent_get_paused);
ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer3D::agent_set_neighbor_distance);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer3D::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon_agents", "agent", "time_horizon"), &NavigationServer3D::agent_set_time_horizon_agents);
@@ -136,6 +138,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("obstacle_get_use_3d_avoidance", "obstacle"), &NavigationServer3D::obstacle_get_use_3d_avoidance);
ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer3D::obstacle_set_map);
ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer3D::obstacle_get_map);
+ ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &NavigationServer3D::obstacle_set_paused);
+ ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &NavigationServer3D::obstacle_get_paused);
ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer3D::obstacle_set_radius);
ClassDB::bind_method(D_METHOD("obstacle_set_height", "obstacle", "height"), &NavigationServer3D::obstacle_set_height);
ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer3D::obstacle_set_velocity);
@@ -143,6 +147,9 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer3D::obstacle_set_vertices);
ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer3D::obstacle_set_avoidance_layers);
+ ClassDB::bind_method(D_METHOD("parse_source_geometry_data", "navigation_mesh", "source_geometry_data", "root_node", "callback"), &NavigationServer3D::parse_source_geometry_data);
+ ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data", "navigation_mesh", "source_geometry_data", "callback"), &NavigationServer3D::bake_from_source_geometry_data);
+
ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer3D::free);
ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer3D::set_active);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index da3741ed8b..cf5552e676 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -35,6 +35,7 @@
#include "core/templates/rid.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "servers/navigation/navigation_path_query_parameters_3d.h"
#include "servers/navigation/navigation_path_query_result_3d.h"
@@ -197,6 +198,9 @@ public:
virtual void agent_set_map(RID p_agent, RID p_map) = 0;
virtual RID agent_get_map(RID p_agent) const = 0;
+ virtual void agent_set_paused(RID p_agent, bool p_paused) = 0;
+ virtual bool agent_get_paused(RID p_agent) const = 0;
+
virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled) = 0;
virtual bool agent_get_avoidance_enabled(RID p_agent) const = 0;
@@ -243,7 +247,7 @@ public:
virtual void agent_set_velocity_forced(RID p_agent, Vector3 p_velocity) = 0;
/// The wanted velocity for the agent as a "suggestion" to the avoidance simulation.
- /// The simulation will try to fulfil this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
+ /// The simulation will try to fulfill this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
virtual void agent_set_velocity(RID p_agent, Vector3 p_velocity) = 0;
/// Position of the agent in world space.
@@ -263,6 +267,10 @@ public:
virtual RID obstacle_create() = 0;
virtual void obstacle_set_map(RID p_obstacle, RID p_map) = 0;
virtual RID obstacle_get_map(RID p_obstacle) const = 0;
+
+ virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) = 0;
+ virtual bool obstacle_get_paused(RID p_obstacle) const = 0;
+
virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) = 0;
virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const = 0;
virtual void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) = 0;
@@ -291,6 +299,9 @@ public:
virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const = 0;
+ virtual void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) = 0;
+ virtual void bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) = 0;
+
NavigationServer3D();
~NavigationServer3D() override;
diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h
index d2f11ccfa0..8e91ec812f 100644
--- a/servers/navigation_server_3d_dummy.h
+++ b/servers/navigation_server_3d_dummy.h
@@ -103,6 +103,8 @@ public:
RID agent_create() override { return RID(); }
void agent_set_map(RID p_agent, RID p_map) override {}
RID agent_get_map(RID p_agent) const override { return RID(); }
+ void agent_set_paused(RID p_agent, bool p_paused) override {}
+ bool agent_get_paused(RID p_agent) const override { return false; }
void agent_set_avoidance_enabled(RID p_agent, bool p_enabled) override {}
bool agent_get_avoidance_enabled(RID p_agent) const override { return false; }
void agent_set_use_3d_avoidance(RID p_agent, bool p_enabled) override {}
@@ -125,6 +127,8 @@ public:
RID obstacle_create() override { return RID(); }
void obstacle_set_map(RID p_obstacle, RID p_map) override {}
RID obstacle_get_map(RID p_obstacle) const override { return RID(); }
+ void obstacle_set_paused(RID p_obstacle, bool p_paused) override {}
+ bool obstacle_get_paused(RID p_obstacle) const override { return false; }
void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) override {}
bool obstacle_get_avoidance_enabled(RID p_obstacle) const override { return false; }
void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) override {}
@@ -135,6 +139,8 @@ public:
void obstacle_set_position(RID p_obstacle, Vector3 p_position) override {}
void obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) override {}
void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {}
+ void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override {}
+ void bake_from_source_geometry_data(Ref<NavigationMesh> p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {}
void free(RID p_object) override {}
void set_active(bool p_active) override {}
void process(real_t delta_time) override {}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index eea891792a..4f47a80c13 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -984,9 +984,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
to_draw = _indices_to_primitives(surf->primitive, to_draw);
to_draw *= inst->instance_count;
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
}
}
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 0b4157c5d6..77dd39b8d9 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1884,9 +1884,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
to_draw = _indices_to_primitives(surf->primitive, to_draw);
to_draw *= inst->instance_count;
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
- p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
}
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index d3c22e4826..67b5cdd291 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -727,6 +727,12 @@ void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
void MeshStorage::mesh_clear(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
+
+ // Clear instance data before mesh data.
+ for (MeshInstance *mi : mesh->instances) {
+ _mesh_instance_clear(mi);
+ }
+
for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];
if (s.vertex_buffer.is_valid()) {
@@ -766,10 +772,6 @@ void MeshStorage::mesh_clear(RID p_mesh) {
mesh->surfaces = nullptr;
mesh->surface_count = 0;
mesh->material_cache.clear();
- //clear instance data
- for (MeshInstance *mi : mesh->instances) {
- _mesh_instance_clear(mi);
- }
mesh->has_bone_weights = false;
mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
@@ -860,6 +862,7 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
if (mi->blend_weights_buffer.is_valid()) {
RD::get_singleton()->free(mi->blend_weights_buffer);
+ mi->blend_weights_buffer = RID();
}
mi->blend_weights.clear();
mi->weights_dirty = false;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 8813c2e651..71f6a28671 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -1403,7 +1403,7 @@ void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, Disp
int RendererViewport::get_total_objects_drawn() const {
return total_objects_drawn;
}
-int RendererViewport::get_total_vertices_drawn() const {
+int RendererViewport::get_total_primitives_drawn() const {
return total_vertices_drawn;
}
int RendererViewport::get_total_draw_calls_used() const {
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 2f9537a47c..c004d05b23 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -297,7 +297,7 @@ public:
bool free(RID p_rid);
int get_total_objects_drawn() const;
- int get_total_vertices_drawn() const;
+ int get_total_primitives_drawn() const;
int get_total_draw_calls_used() const;
// Workaround for setting this on thread.
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 5f14245307..65bdb94c9f 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -251,7 +251,7 @@ uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) {
if (p_info == RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME) {
return RSG::viewport->get_total_objects_drawn();
} else if (p_info == RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME) {
- return RSG::viewport->get_total_vertices_drawn();
+ return RSG::viewport->get_total_primitives_drawn();
} else if (p_info == RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME) {
return RSG::viewport->get_total_draw_calls_used();
}
diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h
index 243b75626f..a4d3fd1d70 100644
--- a/tests/core/io/test_file_access.h
+++ b/tests/core/io/test_file_access.h
@@ -38,25 +38,27 @@
namespace TestFileAccess {
TEST_CASE("[FileAccess] CSV read") {
- Ref<FileAccess> f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(TestUtils::get_data_path("testdata.csv"), FileAccess::READ);
REQUIRE(!f.is_null());
Vector<String> header = f->get_csv_line(); // Default delimiter: ",".
- REQUIRE(header.size() == 3);
+ REQUIRE(header.size() == 4);
Vector<String> row1 = f->get_csv_line(","); // Explicit delimiter, should be the same.
- REQUIRE(row1.size() == 3);
+ REQUIRE(row1.size() == 4);
CHECK(row1[0] == "GOOD_MORNING");
CHECK(row1[1] == "Good Morning");
CHECK(row1[2] == "Guten Morgen");
+ CHECK(row1[3] == "Bonjour");
Vector<String> row2 = f->get_csv_line();
- REQUIRE(row2.size() == 3);
+ REQUIRE(row2.size() == 4);
CHECK(row2[0] == "GOOD_EVENING");
CHECK(row2[1] == "Good Evening");
CHECK(row2[2].is_empty()); // Use case: not yet translated!
// https://github.com/godotengine/godot/issues/44269
CHECK_MESSAGE(row2[2] != "\"", "Should not parse empty string as a single double quote.");
+ CHECK(row2[3] == "\"\""); // Intentionally testing only escaped double quotes.
Vector<String> row3 = f->get_csv_line();
REQUIRE(row3.size() == 6);
diff --git a/tests/core/string/test_translation.h b/tests/core/string/test_translation.h
index 3519f3050b..bf9674d6b1 100644
--- a/tests/core/string/test_translation.h
+++ b/tests/core/string/test_translation.h
@@ -151,7 +151,7 @@ TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages")
}
#ifdef TOOLS_ENABLED
-TEST_CASE("[Translation] CSV import") {
+TEST_CASE("[TranslationCSV] CSV import") {
Ref<ResourceImporterCSVTranslation> import_csv_translation = memnew(ResourceImporterCSVTranslation);
HashMap<StringName, Variant> options;
@@ -163,17 +163,39 @@ TEST_CASE("[Translation] CSV import") {
Error result = import_csv_translation->import(TestUtils::get_data_path("translations.csv"),
"", options, nullptr, &gen_files);
CHECK(result == OK);
- CHECK(gen_files.size() == 2);
+ CHECK(gen_files.size() == 4);
+
+ TranslationServer *ts = TranslationServer::get_singleton();
for (const String &file : gen_files) {
Ref<Translation> translation = ResourceLoader::load(file);
CHECK(translation.is_valid());
- TranslationServer::get_singleton()->add_translation(translation);
+ ts->add_translation(translation);
}
- TranslationServer::get_singleton()->set_locale("de");
+ ts->set_locale("en");
+
+ // `tr` can be called on any Object, we reuse TranslationServer for convenience.
+ CHECK(ts->tr("GOOD_MORNING") == "Good Morning");
+ CHECK(ts->tr("GOOD_EVENING") == "Good Evening");
+
+ ts->set_locale("de");
+
+ CHECK(ts->tr("GOOD_MORNING") == "Guten Morgen");
+ CHECK(ts->tr("GOOD_EVENING") == "Good Evening"); // Left blank in CSV, should source from 'en'.
+
+ ts->set_locale("ja");
+
+ CHECK(ts->tr("GOOD_MORNING") == String::utf8("おはよう"));
+ CHECK(ts->tr("GOOD_EVENING") == String::utf8("こんばんは"));
+
+ /* FIXME: This passes, but triggers a chain reaction that makes test_viewport
+ * and test_text_edit explode in a billion glittery Unicode particles.
+ ts->set_locale("fa");
- CHECK(Object().tr("GOOD_MORNING", "") == "Guten Morgen");
+ CHECK(ts->tr("GOOD_MORNING") == String::utf8("صبح بخیر"));
+ CHECK(ts->tr("GOOD_EVENING") == String::utf8("عصر بخیر"));
+ */
}
#endif // TOOLS_ENABLED
diff --git a/tests/core/variant/test_variant.h b/tests/core/variant/test_variant.h
index 024fcf53c4..66b58620d2 100644
--- a/tests/core/variant/test_variant.h
+++ b/tests/core/variant/test_variant.h
@@ -1171,6 +1171,22 @@ TEST_CASE("[Variant] Utility functions") {
}
}
+TEST_CASE("[Variant] Operator NOT") {
+ // Verify that operator NOT works for all types and is consistent with booleanize().
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ Variant value;
+ Callable::CallError err;
+ Variant::construct((Variant::Type)i, value, nullptr, 0, err);
+
+ REQUIRE_EQ(err.error, Callable::CallError::CALL_OK);
+
+ Variant result = Variant::evaluate(Variant::OP_NOT, value, Variant());
+
+ REQUIRE_EQ(result.get_type(), Variant::BOOL);
+ CHECK_EQ(!value.booleanize(), result.operator bool());
+ }
+}
+
} // namespace TestVariant
#endif // TEST_VARIANT_H
diff --git a/tests/data/testdata.csv b/tests/data/testdata.csv
new file mode 100644
index 0000000000..8f5cc914ac
--- /dev/null
+++ b/tests/data/testdata.csv
@@ -0,0 +1,8 @@
+Header 1,Header 2,Header 3,Header 4
+GOOD_MORNING,"Good Morning","Guten Morgen","Bonjour"
+GOOD_EVENING,"Good Evening","",""""""
+Without quotes,"With, comma","With ""inner"" quotes","With ""inner"", quotes"","" and comma","With ""inner
+split"" quotes and
+line breaks","With \nnewline chars"
+Some other~delimiter~should still work, shouldn't it?
+What about tab separated lines, good?
diff --git a/tests/data/translations.csv b/tests/data/translations.csv
index 8cb7b800c5..6b5efc9b91 100644
--- a/tests/data/translations.csv
+++ b/tests/data/translations.csv
@@ -1,8 +1,3 @@
-keys,en,de
-GOOD_MORNING,"Good Morning","Guten Morgen"
-GOOD_EVENING,"Good Evening",""
-Without quotes,"With, comma","With ""inner"" quotes","With ""inner"", quotes"","" and comma","With ""inner
-split"" quotes and
-line breaks","With \nnewline chars"
-Some other~delimiter~should still work, shouldn't it?
-What about tab separated lines, good?
+keys,en,de,ja,fa
+GOOD_MORNING,"Good Morning","Guten Morgen","おはよう","صبح بخیر"
+GOOD_EVENING,"Good Evening","","こんばんは","عصر بخیر"
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index c8ce49f318..d6858fbcb4 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -3496,7 +3496,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->confirm_code_completion();
CHECK(code_edit->get_line(0) == "test");
- /* Favorize good capitalisation. */
+ /* Favorize good capitalization. */
code_edit->clear();
code_edit->insert_text_at_caret("te");
code_edit->set_caret_column(2);
@@ -3506,7 +3506,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->confirm_code_completion();
CHECK(code_edit->get_line(0) == "test");
- /* Favorize location to good capitalisation. */
+ /* Favorize location to good capitalization. */
code_edit->clear();
code_edit->insert_text_at_caret("te");
code_edit->set_caret_column(2);
@@ -3526,7 +3526,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->confirm_code_completion();
CHECK(code_edit->get_line(0) == "stest");
- /* Favorize good capitalisation to closest to start. */
+ /* Favorize good capitalization to closest to start. */
code_edit->clear();
code_edit->insert_text_at_caret("te");
code_edit->set_caret_column(2);
diff --git a/tests/scene/test_navigation_obstacle_2d.h b/tests/scene/test_navigation_obstacle_2d.h
new file mode 100644
index 0000000000..97d28e0a48
--- /dev/null
+++ b/tests/scene/test_navigation_obstacle_2d.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/* test_navigation_obstacle_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_NAVIGATION_OBSTACLE_2D_H
+#define TEST_NAVIGATION_OBSTACLE_2D_H
+
+#include "scene/2d/navigation_obstacle_2d.h"
+#include "scene/main/window.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNavigationObstacle2D {
+
+TEST_SUITE("[Navigation]") {
+ TEST_CASE("[SceneTree][NavigationObstacle2D] New obstacle should have valid RID") {
+ NavigationObstacle2D *obstacle_node = memnew(NavigationObstacle2D);
+ CHECK(obstacle_node->get_rid().is_valid());
+ memdelete(obstacle_node);
+ }
+
+ TEST_CASE("[SceneTree][NavigationObstacle2D] New obstacle should attach to default map") {
+ Node2D *node_2d = memnew(Node2D);
+ SceneTree::get_singleton()->get_root()->add_child(node_2d);
+
+ NavigationObstacle2D *obstacle_node = memnew(NavigationObstacle2D);
+ // obstacle should not be attached to any map when outside of tree
+ CHECK_FALSE(obstacle_node->get_navigation_map().is_valid());
+
+ SUBCASE("Obstacle should attach to default map when it enters the tree") {
+ node_2d->add_child(obstacle_node);
+ CHECK(obstacle_node->get_navigation_map().is_valid());
+ CHECK(obstacle_node->get_navigation_map() == node_2d->get_world_2d()->get_navigation_map());
+ }
+
+ memdelete(obstacle_node);
+ memdelete(node_2d);
+ }
+}
+
+} //namespace TestNavigationObstacle2D
+
+#endif // TEST_NAVIGATION_OBSTACLE_2D_H
diff --git a/tests/scene/test_navigation_obstacle_3d.h b/tests/scene/test_navigation_obstacle_3d.h
new file mode 100644
index 0000000000..8769f4fb64
--- /dev/null
+++ b/tests/scene/test_navigation_obstacle_3d.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/* test_navigation_obstacle_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_NAVIGATION_OBSTACLE_3D_H
+#define TEST_NAVIGATION_OBSTACLE_3D_H
+
+#include "scene/3d/navigation_obstacle_3d.h"
+#include "scene/main/window.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNavigationObstacle3D {
+
+TEST_SUITE("[Navigation]") {
+ TEST_CASE("[SceneTree][NavigationObstacle3D] New obstacle should have valid RID") {
+ NavigationObstacle3D *obstacle_node = memnew(NavigationObstacle3D);
+ CHECK(obstacle_node->get_rid().is_valid());
+ memdelete(obstacle_node);
+ }
+
+ TEST_CASE("[SceneTree][NavigationObstacle3D] New obstacle should attach to default map") {
+ Node3D *node_3d = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(node_3d);
+
+ NavigationObstacle3D *obstacle_node = memnew(NavigationObstacle3D);
+ // obstacle should not be attached to any map when outside of tree
+ CHECK_FALSE(obstacle_node->get_navigation_map().is_valid());
+
+ SUBCASE("Obstacle should attach to default map when it enters the tree") {
+ node_3d->add_child(obstacle_node);
+ CHECK(obstacle_node->get_navigation_map().is_valid());
+ CHECK(obstacle_node->get_navigation_map() == node_3d->get_world_3d()->get_navigation_map());
+ }
+
+ memdelete(obstacle_node);
+ memdelete(node_3d);
+ }
+}
+
+} //namespace TestNavigationObstacle3D
+
+#endif // TEST_NAVIGATION_OBSTACLE_3D_H
diff --git a/tests/scene/test_navigation_region_2d.h b/tests/scene/test_navigation_region_2d.h
new file mode 100644
index 0000000000..4574893c8d
--- /dev/null
+++ b/tests/scene/test_navigation_region_2d.h
@@ -0,0 +1,51 @@
+/**************************************************************************/
+/* test_navigation_region_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_NAVIGATION_REGION_2D_H
+#define TEST_NAVIGATION_REGION_2D_H
+
+#include "scene/2d/navigation_region_2d.h"
+#include "scene/main/window.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNavigationRegion2D {
+
+TEST_SUITE("[Navigation]") {
+ TEST_CASE("[SceneTree][NavigationRegion2D] New region should have valid RID") {
+ NavigationRegion2D *region_node = memnew(NavigationRegion2D);
+ CHECK(region_node->get_region_rid().is_valid());
+ memdelete(region_node);
+ }
+}
+
+} //namespace TestNavigationRegion2D
+
+#endif // TEST_NAVIGATION_REGION_2D_H
diff --git a/tests/scene/test_navigation_region_3d.h b/tests/scene/test_navigation_region_3d.h
new file mode 100644
index 0000000000..4c5ae34615
--- /dev/null
+++ b/tests/scene/test_navigation_region_3d.h
@@ -0,0 +1,51 @@
+/**************************************************************************/
+/* test_navigation_region_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_NAVIGATION_REGION_3D_H
+#define TEST_NAVIGATION_REGION_3D_H
+
+#include "scene/3d/navigation_region_3d.h"
+#include "scene/main/window.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNavigationRegion3D {
+
+TEST_SUITE("[Navigation]") {
+ TEST_CASE("[SceneTree][NavigationRegion3D] New region should have valid RID") {
+ NavigationRegion3D *region_node = memnew(NavigationRegion3D);
+ CHECK(region_node->get_region_rid().is_valid());
+ memdelete(region_node);
+ }
+}
+
+} //namespace TestNavigationRegion3D
+
+#endif // TEST_NAVIGATION_REGION_3D_H
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 67d473128e..345e617285 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -3827,10 +3827,10 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
text_edit->adjust_viewport_to_caret();
MessageQueue::get_singleton()->flush();
- CHECK(text_edit->get_first_visible_line() == (visible_lines / 2) + 4);
- CHECK(text_edit->get_v_scroll() == (visible_lines + (visible_lines / 2)) - 1);
- CHECK(text_edit->get_last_full_visible_line() == (visible_lines) + 3);
- CHECK(text_edit->get_last_full_visible_line_wrap_index() == 1);
+ CHECK(text_edit->get_first_visible_line() == (visible_lines / 2) + 6);
+ CHECK(text_edit->get_v_scroll() == (visible_lines + (visible_lines / 2)) + 1);
+ CHECK(text_edit->get_last_full_visible_line() == (visible_lines) + 5);
+ CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
CHECK(text_edit->get_caret_wrap_index() == 1);
text_edit->center_viewport_to_caret();
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index ef071f4115..d0f124bd05 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -98,6 +98,10 @@
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_navigation_agent_2d.h"
#include "tests/scene/test_navigation_agent_3d.h"
+#include "tests/scene/test_navigation_obstacle_2d.h"
+#include "tests/scene/test_navigation_obstacle_3d.h"
+#include "tests/scene/test_navigation_region_2d.h"
+#include "tests/scene/test_navigation_region_3d.h"
#include "tests/scene/test_node.h"
#include "tests/scene/test_path_2d.h"
#include "tests/scene/test_path_3d.h"