summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/first_interaction.yml35
-rw-r--r--.gitignore1
-rw-r--r--SConstruct1043
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/crypto/SCsub12
-rw-r--r--core/io/resource.cpp3
-rw-r--r--core/math/convex_hull.cpp10
-rw-r--r--core/os/pool_allocator.cpp5
-rw-r--r--core/string/ustring.cpp10
-rw-r--r--core/string/ustring.h2
-rw-r--r--core/variant/variant_op.cpp10
-rw-r--r--doc/classes/Array.xml32
-rw-r--r--doc/classes/AudioStreamPlayer.xml46
-rw-r--r--doc/classes/CanvasItem.xml7
-rw-r--r--doc/classes/EditorExportPlatformPC.xml3
-rw-r--r--doc/classes/GPUParticles2D.xml12
-rw-r--r--doc/classes/GPUParticles3D.xml12
-rw-r--r--doc/classes/JSONRPC.xml4
-rw-r--r--doc/classes/JavaClass.xml4
-rw-r--r--doc/classes/JavaClassWrapper.xml5
-rw-r--r--doc/classes/PackedColorArray.xml1
-rw-r--r--doc/classes/PackedFloat64Array.xml1
-rw-r--r--doc/classes/PackedInt64Array.xml1
-rw-r--r--doc/classes/PackedStringArray.xml1
-rw-r--r--doc/classes/PackedVector2Array.xml1
-rw-r--r--doc/classes/PackedVector3Array.xml1
-rw-r--r--doc/classes/PhysicalBone3D.xml5
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState2DExtension.xml44
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml2
-rw-r--r--doc/classes/PhysicsServer2D.xml16
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml160
-rw-r--r--doc/classes/PhysicsServer3D.xml14
-rw-r--r--doc/classes/ProjectSettings.xml9
-rw-r--r--doc/classes/RayCast2D.xml15
-rw-r--r--doc/classes/RayCast3D.xml15
-rw-r--r--doc/classes/RenderingDevice.xml2
-rw-r--r--doc/classes/ResourceLoader.xml1
-rw-r--r--doc/classes/RigidBody2D.xml5
-rw-r--r--doc/classes/RigidBody3D.xml5
-rw-r--r--doc/classes/ShapeCast2D.xml1
-rw-r--r--doc/classes/ShapeCast3D.xml1
-rw-r--r--doc/classes/SkeletonProfile.xml16
-rw-r--r--doc/classes/SliderJoint3D.xml46
-rw-r--r--doc/classes/String.xml7
-rw-r--r--doc/classes/TextServer.xml10
-rw-r--r--doc/classes/TextServerExtension.xml9
-rw-r--r--doc/classes/UndoRedo.xml10
-rw-r--r--doc/classes/Vector2.xml2
-rw-r--r--doc/classes/Vector3.xml1
-rw-r--r--doc/classes/Viewport.xml41
-rw-r--r--doc/classes/ViewportTexture.xml9
-rw-r--r--drivers/gles3/storage/light_storage.cpp6
-rw-r--r--editor/editor_file_system.cpp17
-rw-r--r--editor/editor_help.cpp18
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_node.h4
-rw-r--r--editor/editor_properties_array_dict.cpp110
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_resource_picker.cpp11
-rw-r--r--editor/filesystem_dock.cpp118
-rw-r--r--editor/groups_editor.cpp10
-rw-r--r--editor/gui/scene_tree_editor.cpp11
-rw-r--r--editor/gui/scene_tree_editor.h1
-rw-r--r--editor/import/resource_importer_csv_translation.cpp3
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp27
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--main/main.cpp2
-rw-r--r--methods.py45
-rw-r--r--misc/msvs/props.template8
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp32
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp7
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp9
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_settings.h1
-rw-r--r--modules/mbedtls/SCsub6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DebugView.cs73
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp1
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp1
-rw-r--r--modules/navigation/2d/nav_mesh_generator_2d.cpp144
-rw-r--r--modules/openxr/util.h20
-rw-r--r--modules/text_server_adv/text_server_adv.cpp50
-rw-r--r--modules/text_server_adv/text_server_adv.h1
-rw-r--r--modules/text_server_fb/text_server_fb.cpp41
-rw-r--r--modules/text_server_fb/text_server_fb.h1
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml4
-rw-r--r--modules/upnp/upnp.cpp29
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml1
-rw-r--r--platform/android/export/export_plugin.cpp10
-rw-r--r--platform/windows/display_server_windows.cpp144
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/doc_classes/EditorExportPlatformWindows.xml1
-rw-r--r--scene/2d/camera_2d.cpp4
-rw-r--r--scene/3d/decal.cpp2
-rw-r--r--scene/3d/skeleton_3d.cpp1
-rw-r--r--scene/animation/animation_mixer.cpp14
-rw-r--r--scene/animation/animation_mixer.h7
-rw-r--r--scene/gui/control.cpp4
-rw-r--r--scene/main/node.cpp4
-rw-r--r--scene/resources/skeleton_profile.cpp57
-rw-r--r--scene/resources/skeleton_profile.h12
-rw-r--r--scene/theme/default_theme.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp2
-rw-r--r--servers/rendering/rendering_device.cpp19
-rw-r--r--servers/rendering/rendering_device_driver.h2
-rw-r--r--servers/rendering/rendering_device_graph.cpp6
-rw-r--r--servers/rendering/rendering_light_culler.cpp18
-rw-r--r--servers/rendering/rendering_light_culler.h33
-rw-r--r--servers/text/text_server_extension.cpp9
-rw-r--r--servers/text/text_server_extension.h2
-rw-r--r--servers/text_server.cpp1
-rw-r--r--servers/text_server.h1
-rw-r--r--tests/core/math/test_vector2.h4
-rw-r--r--thirdparty/README.md12
-rw-r--r--thirdparty/certs/ca-certificates.crt51
-rw-r--r--thirdparty/enet/patches/godot_socket.patch16
-rw-r--r--thirdparty/enet/protocol.c16
-rw-r--r--thirdparty/squish/LICENSE.txt20
-rw-r--r--thirdparty/squish/godot-changes.patch211
-rw-r--r--thirdparty/squish/patches/config_sse.patch31
-rw-r--r--thirdparty/squish/patches/decompress_bc4_bc5.patch85
131 files changed, 2119 insertions, 1260 deletions
diff --git a/.github/workflows/first_interaction.yml b/.github/workflows/first_interaction.yml
deleted file mode 100644
index ed0f5c860f..0000000000
--- a/.github/workflows/first_interaction.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-name: 🔗 GHA
-
-on:
- issues:
- types: [opened]
- pull_request:
- branches: [master]
- types: [opened]
-
-jobs:
- check_for_first_issue:
- name: 🌱 Check for first interaction
- runs-on: ubuntu-latest
- steps:
- - uses: actions/first-interaction@v1
- with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- issue-message: |
- Hello from the maintainer team!
-
- First of all, thank you for taking the time to report an issue here.
-
- In case you haven't already, be sure to attach an MRP (minimal reproduction project) if **specific** steps or assets are needed in order to reproduce the issue. Contributors will use the MRP to validate that the fix is working as intended.
-
- The time it will take to assess and fix your issue may vary. Follow the blog about our [new releases](https://godotengine.org/blog/release/) and [pre-releases](https://godotengine.org/blog/pre-release/) to track new fixes or go to [our forum](https://forum.godotengine.org/) where users could help you in the meantime.
-
- Thank you for your patience.
- pr-message: |
- Hi there, fellow Godot contributor!
-
- Thank you for your first PR.
-
- Be sure to join us in the [developers chat](https://chat.godotengine.org) to talk about your PR, especially if you need help or guidance. Don't forget to consult the [contributing docs](https://docs.godotengine.org/en/stable/contributing/development/index.html) too!
-
- Thank you for your patience.
diff --git a/.gitignore b/.gitignore
index 46dcf84b43..3946cc96e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ platform/windows/godot_res.res
# Ninja build files
build.ninja
.ninja
+run_ninja_env.bat
# Generated by Godot binary
.import/
diff --git a/SConstruct b/SConstruct
index 73ef420a0d..2cce05a20b 100644
--- a/SConstruct
+++ b/SConstruct
@@ -303,11 +303,6 @@ else:
selected_platform = "macos"
elif sys.platform == "win32":
selected_platform = "windows"
- else:
- print("Could not detect platform automatically. Supported platforms:")
- for x in platform_list:
- print("\t" + x)
- print("\nPlease run SCons again and select a valid platform: platform=<string>")
if selected_platform != "":
print("Automatically detected platform: " + selected_platform)
@@ -334,6 +329,16 @@ if selected_platform == "javascript":
print('Platform "javascript" has been renamed to "web" in Godot 4. Building for platform "web".')
selected_platform = "web"
+if selected_platform not in platform_list:
+ if selected_platform == "":
+ print("Could not detect platform automatically.")
+ elif selected_platform != "list":
+ print(f'Invalid target platform "{selected_platform}".')
+
+ print("The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list)))
+ print("Please run SCons again and select a valid platform: platform=<string>.")
+ Exit(0 if selected_platform == "list" else 255)
+
# Make sure to update this to the found, valid platform as it's used through the buildsystem as the reference.
# It should always be re-set after calling `opts.Update()` otherwise it uses the original input value.
env_base["platform"] = selected_platform
@@ -480,571 +485,551 @@ if not env_base["deprecated"]:
if env_base["precision"] == "double":
env_base.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
-if selected_platform in platform_list:
- tmppath = "./platform/" + selected_platform
- sys.path.insert(0, tmppath)
- import detect
-
- env = env_base.Clone()
-
- # Default num_jobs to local cpu count if not user specified.
- # SCons has a peculiarity where user-specified options won't be overridden
- # by SetOption, so we can rely on this to know if we should use our default.
- initial_num_jobs = env.GetOption("num_jobs")
- altered_num_jobs = initial_num_jobs + 1
- env.SetOption("num_jobs", altered_num_jobs)
- if env.GetOption("num_jobs") == altered_num_jobs:
- cpu_count = os.cpu_count()
- if cpu_count is None:
- print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.")
- else:
- safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
- print(
- "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument."
- % (cpu_count, safer_cpu_count)
- )
- env.SetOption("num_jobs", safer_cpu_count)
-
- env.extra_suffix = ""
-
- if env["extra_suffix"] != "":
- env.extra_suffix += "." + env["extra_suffix"]
-
- # Environment flags
- env.Append(CPPDEFINES=env.get("cppdefines", "").split())
- env.Append(CCFLAGS=env.get("ccflags", "").split())
- env.Append(CXXFLAGS=env.get("cxxflags", "").split())
- env.Append(CFLAGS=env.get("cflags", "").split())
- env.Append(LINKFLAGS=env.get("linkflags", "").split())
-
- # Feature build profile
- disabled_classes = []
- if env["build_profile"] != "":
- print("Using feature build profile: " + env["build_profile"])
- import json
+tmppath = "./platform/" + selected_platform
+sys.path.insert(0, tmppath)
+import detect
+
+env = env_base.Clone()
+
+# Default num_jobs to local cpu count if not user specified.
+# SCons has a peculiarity where user-specified options won't be overridden
+# by SetOption, so we can rely on this to know if we should use our default.
+initial_num_jobs = env.GetOption("num_jobs")
+altered_num_jobs = initial_num_jobs + 1
+env.SetOption("num_jobs", altered_num_jobs)
+if env.GetOption("num_jobs") == altered_num_jobs:
+ cpu_count = os.cpu_count()
+ if cpu_count is None:
+ print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.")
+ else:
+ safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
+ print(
+ "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument."
+ % (cpu_count, safer_cpu_count)
+ )
+ env.SetOption("num_jobs", safer_cpu_count)
+
+env.extra_suffix = ""
+
+if env["extra_suffix"] != "":
+ env.extra_suffix += "." + env["extra_suffix"]
+
+# Environment flags
+env.Append(CPPDEFINES=env.get("cppdefines", "").split())
+env.Append(CCFLAGS=env.get("ccflags", "").split())
+env.Append(CXXFLAGS=env.get("cxxflags", "").split())
+env.Append(CFLAGS=env.get("cflags", "").split())
+env.Append(LINKFLAGS=env.get("linkflags", "").split())
+
+# Feature build profile
+disabled_classes = []
+if env["build_profile"] != "":
+ print("Using feature build profile: " + env["build_profile"])
+ import json
- try:
- ft = json.load(open(env["build_profile"]))
- if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
- if "disabled_build_options" in ft:
- dbo = ft["disabled_build_options"]
- for c in dbo:
- env[c] = dbo[c]
- except:
- print("Error opening feature build profile: " + env["build_profile"])
- Exit(255)
- methods.write_disabled_classes(disabled_classes)
-
- # Platform specific flags.
- # These can sometimes override default options.
- flag_list = platform_flags[selected_platform]
- for f in flag_list:
- if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
- env[f[0]] = f[1]
-
- # 'dev_mode' and 'production' are aliases to set default options if they haven't been
- # set manually by the user.
- # These need to be checked *after* platform specific flags so that different
- # default values can be set (e.g. to keep LTO off for `production` on some platforms).
- if env["dev_mode"]:
- env["verbose"] = methods.get_cmdline_bool("verbose", True)
- env["warnings"] = ARGUMENTS.get("warnings", "extra")
- env["werror"] = methods.get_cmdline_bool("werror", True)
- env["tests"] = methods.get_cmdline_bool("tests", True)
- if env["production"]:
- env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
- env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
- # LTO "auto" means we handle the preferred option in each platform detect.py.
- env["lto"] = ARGUMENTS.get("lto", "auto")
-
- # Run SCU file generation script if in a SCU build.
- if env["scu_build"]:
- max_includes_per_scu = 8
- if env_base.dev_build == True:
- max_includes_per_scu = 1024
-
- read_scu_limit = int(env["scu_limit"])
- read_scu_limit = max(0, min(read_scu_limit, 1024))
- if read_scu_limit != 0:
- max_includes_per_scu = read_scu_limit
-
- methods.set_scu_folders(scu_builders.generate_scu_files(max_includes_per_scu))
-
- # Must happen after the flags' definition, as configure is when most flags
- # are actually handled to change compile options, etc.
- detect.configure(env)
-
- print(f'Building for platform "{selected_platform}", architecture "{env["arch"]}", target "{env["target"]}".')
- if env.dev_build:
- print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
-
- # Set optimize and debug_symbols flags.
- # "custom" means do nothing and let users set their own optimization flags.
- # Needs to happen after configure to have `env.msvc` defined.
- if env.msvc:
- if env["debug_symbols"]:
- env.Append(CCFLAGS=["/Zi", "/FS"])
- env.Append(LINKFLAGS=["/DEBUG:FULL"])
- else:
- env.Append(LINKFLAGS=["/DEBUG:NONE"])
-
- if env["optimize"] == "speed":
- env.Append(CCFLAGS=["/O2"])
- env.Append(LINKFLAGS=["/OPT:REF"])
- elif env["optimize"] == "speed_trace":
- env.Append(CCFLAGS=["/O2"])
- env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
- elif env["optimize"] == "size":
- env.Append(CCFLAGS=["/O1"])
- env.Append(LINKFLAGS=["/OPT:REF"])
- elif env["optimize"] == "debug" or env["optimize"] == "none":
- env.Append(CCFLAGS=["/Od"])
+ try:
+ ft = json.load(open(env["build_profile"]))
+ if "disabled_classes" in ft:
+ disabled_classes = ft["disabled_classes"]
+ if "disabled_build_options" in ft:
+ dbo = ft["disabled_build_options"]
+ for c in dbo:
+ env[c] = dbo[c]
+ except:
+ print("Error opening feature build profile: " + env["build_profile"])
+ Exit(255)
+methods.write_disabled_classes(disabled_classes)
+
+# Platform specific flags.
+# These can sometimes override default options.
+flag_list = platform_flags[selected_platform]
+for f in flag_list:
+ if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
+ env[f[0]] = f[1]
+
+# 'dev_mode' and 'production' are aliases to set default options if they haven't been
+# set manually by the user.
+# These need to be checked *after* platform specific flags so that different
+# default values can be set (e.g. to keep LTO off for `production` on some platforms).
+if env["dev_mode"]:
+ env["verbose"] = methods.get_cmdline_bool("verbose", True)
+ env["warnings"] = ARGUMENTS.get("warnings", "extra")
+ env["werror"] = methods.get_cmdline_bool("werror", True)
+ env["tests"] = methods.get_cmdline_bool("tests", True)
+if env["production"]:
+ env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
+ env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
+ # LTO "auto" means we handle the preferred option in each platform detect.py.
+ env["lto"] = ARGUMENTS.get("lto", "auto")
+
+# Run SCU file generation script if in a SCU build.
+if env["scu_build"]:
+ max_includes_per_scu = 8
+ if env_base.dev_build == True:
+ max_includes_per_scu = 1024
+
+ read_scu_limit = int(env["scu_limit"])
+ read_scu_limit = max(0, min(read_scu_limit, 1024))
+ if read_scu_limit != 0:
+ max_includes_per_scu = read_scu_limit
+
+ methods.set_scu_folders(scu_builders.generate_scu_files(max_includes_per_scu))
+
+# Must happen after the flags' definition, as configure is when most flags
+# are actually handled to change compile options, etc.
+detect.configure(env)
+
+print(f'Building for platform "{selected_platform}", architecture "{env["arch"]}", target "{env["target"]}".')
+if env.dev_build:
+ print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
+
+# Set optimize and debug_symbols flags.
+# "custom" means do nothing and let users set their own optimization flags.
+# Needs to happen after configure to have `env.msvc` defined.
+if env.msvc:
+ if env["debug_symbols"]:
+ env.Append(CCFLAGS=["/Zi", "/FS"])
+ env.Append(LINKFLAGS=["/DEBUG:FULL"])
else:
- if env["debug_symbols"]:
- # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
- # otherwise addr2line doesn't understand them
- env.Append(CCFLAGS=["-gdwarf-4"])
- if env.dev_build:
- env.Append(CCFLAGS=["-g3"])
- else:
- env.Append(CCFLAGS=["-g2"])
+ env.Append(LINKFLAGS=["/DEBUG:NONE"])
+
+ if env["optimize"] == "speed":
+ env.Append(CCFLAGS=["/O2"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "speed_trace":
+ env.Append(CCFLAGS=["/O2"])
+ env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
+ elif env["optimize"] == "size":
+ env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "debug" or env["optimize"] == "none":
+ env.Append(CCFLAGS=["/Od"])
+else:
+ if env["debug_symbols"]:
+ # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
+ # otherwise addr2line doesn't understand them
+ env.Append(CCFLAGS=["-gdwarf-4"])
+ if env.dev_build:
+ env.Append(CCFLAGS=["-g3"])
else:
- if methods.using_clang(env) and not methods.is_vanilla_clang(env):
- # Apple Clang, its linker doesn't like -s.
- env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
- else:
- env.Append(LINKFLAGS=["-s"])
-
- if env["optimize"] == "speed":
- env.Append(CCFLAGS=["-O3"])
- # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
- elif env["optimize"] == "speed_trace":
- env.Append(CCFLAGS=["-O2"])
- elif env["optimize"] == "size":
- env.Append(CCFLAGS=["-Os"])
- elif env["optimize"] == "debug":
- env.Append(CCFLAGS=["-Og"])
- elif env["optimize"] == "none":
- env.Append(CCFLAGS=["-O0"])
-
- # Needs to happen after configure to handle "auto".
- if env["lto"] != "none":
- print("Using LTO: " + env["lto"])
-
- # Set our C and C++ standard requirements.
- # C++17 is required as we need guaranteed copy elision as per GH-36436.
- # Prepending to make it possible to override.
- # This needs to come after `configure`, otherwise we don't have env.msvc.
- if not env.msvc:
- # Specifying GNU extensions support explicitly, which are supported by
- # both GCC and Clang. Both currently default to gnu11 and gnu++14.
- env.Prepend(CFLAGS=["-std=gnu11"])
- env.Prepend(CXXFLAGS=["-std=gnu++17"])
+ env.Append(CCFLAGS=["-g2"])
else:
- # MSVC doesn't have clear C standard support, /std only covers C++.
- # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
- env.Prepend(CCFLAGS=["/std:c++17"])
-
- # Enforce our minimal compiler version requirements
- cc_version = methods.get_compiler_version(env) or {
- "major": None,
- "minor": None,
- "patch": None,
- "metadata1": None,
- "metadata2": None,
- "date": None,
- }
- cc_version_major = int(cc_version["major"] or -1)
- cc_version_minor = int(cc_version["minor"] or -1)
- cc_version_metadata1 = cc_version["metadata1"] or ""
-
- if methods.using_gcc(env):
- if cc_version_major == -1:
- print(
- "Couldn't detect compiler version, skipping version checks. "
- "Build may fail if the compiler doesn't support C++17 fully."
- )
- # GCC 8 before 8.4 has a regression in the support of guaranteed copy elision
- # which causes a build failure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86521
- elif cc_version_major == 8 and cc_version_minor < 4:
- print(
- "Detected GCC 8 version < 8.4, which is not supported due to a "
- "regression in its C++17 guaranteed copy elision support. Use a "
- 'newer GCC version, or Clang 6 or later by passing "use_llvm=yes" '
- "to the SCons command line."
- )
- Exit(255)
- elif cc_version_major < 7:
- print(
- "Detected GCC version older than 7, which does not fully support "
- "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC "
- 'version, or Clang 6 or later by passing "use_llvm=yes" to the '
- "SCons command line."
- )
- Exit(255)
- elif cc_version_metadata1 == "win32":
+ if methods.using_clang(env) and not methods.is_vanilla_clang(env):
+ # Apple Clang, its linker doesn't like -s.
+ env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
+ else:
+ env.Append(LINKFLAGS=["-s"])
+
+ if env["optimize"] == "speed":
+ env.Append(CCFLAGS=["-O3"])
+ # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
+ elif env["optimize"] == "speed_trace":
+ env.Append(CCFLAGS=["-O2"])
+ elif env["optimize"] == "size":
+ env.Append(CCFLAGS=["-Os"])
+ elif env["optimize"] == "debug":
+ env.Append(CCFLAGS=["-Og"])
+ elif env["optimize"] == "none":
+ env.Append(CCFLAGS=["-O0"])
+
+# Needs to happen after configure to handle "auto".
+if env["lto"] != "none":
+ print("Using LTO: " + env["lto"])
+
+# Set our C and C++ standard requirements.
+# C++17 is required as we need guaranteed copy elision as per GH-36436.
+# Prepending to make it possible to override.
+# This needs to come after `configure`, otherwise we don't have env.msvc.
+if not env.msvc:
+ # Specifying GNU extensions support explicitly, which are supported by
+ # both GCC and Clang. Both currently default to gnu11 and gnu++14.
+ env.Prepend(CFLAGS=["-std=gnu11"])
+ env.Prepend(CXXFLAGS=["-std=gnu++17"])
+else:
+ # MSVC doesn't have clear C standard support, /std only covers C++.
+ # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
+ env.Prepend(CCFLAGS=["/std:c++17"])
+
+# Enforce our minimal compiler version requirements
+cc_version = methods.get_compiler_version(env) or {
+ "major": None,
+ "minor": None,
+ "patch": None,
+ "metadata1": None,
+ "metadata2": None,
+ "date": None,
+}
+cc_version_major = int(cc_version["major"] or -1)
+cc_version_minor = int(cc_version["minor"] or -1)
+cc_version_metadata1 = cc_version["metadata1"] or ""
+
+if methods.using_gcc(env):
+ if cc_version_major == -1:
+ print(
+ "Couldn't detect compiler version, skipping version checks. "
+ "Build may fail if the compiler doesn't support C++17 fully."
+ )
+ # GCC 8 before 8.4 has a regression in the support of guaranteed copy elision
+ # which causes a build failure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86521
+ elif cc_version_major == 8 and cc_version_minor < 4:
+ print(
+ "Detected GCC 8 version < 8.4, which is not supported due to a "
+ "regression in its C++17 guaranteed copy elision support. Use a "
+ 'newer GCC version, or Clang 6 or later by passing "use_llvm=yes" '
+ "to the SCons command line."
+ )
+ Exit(255)
+ elif cc_version_major < 7:
+ print(
+ "Detected GCC version older than 7, which does not fully support "
+ "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC "
+ 'version, or Clang 6 or later by passing "use_llvm=yes" to the '
+ "SCons command line."
+ )
+ Exit(255)
+ elif cc_version_metadata1 == "win32":
+ print(
+ "Detected mingw version is not using posix threads. Only posix "
+ "version of mingw is supported. "
+ 'Use "update-alternatives --config x86_64-w64-mingw32-g++" '
+ "to switch to posix threads."
+ )
+ Exit(255)
+elif methods.using_clang(env):
+ if cc_version_major == -1:
+ print(
+ "Couldn't detect compiler version, skipping version checks. "
+ "Build may fail if the compiler doesn't support C++17 fully."
+ )
+ # Apple LLVM versions differ from upstream LLVM version \o/, compare
+ # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
+ elif env["platform"] == "macos" or env["platform"] == "ios":
+ vanilla = methods.is_vanilla_clang(env)
+ if vanilla and cc_version_major < 6:
print(
- "Detected mingw version is not using posix threads. Only posix "
- "version of mingw is supported. "
- 'Use "update-alternatives --config x86_64-w64-mingw32-g++" '
- "to switch to posix threads."
+ "Detected Clang version older than 6, which does not fully support "
+ "C++17. Supported versions are Clang 6 and later."
)
Exit(255)
- elif methods.using_clang(env):
- if cc_version_major == -1:
- print(
- "Couldn't detect compiler version, skipping version checks. "
- "Build may fail if the compiler doesn't support C++17 fully."
- )
- # Apple LLVM versions differ from upstream LLVM version \o/, compare
- # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
- elif env["platform"] == "macos" or env["platform"] == "ios":
- vanilla = methods.is_vanilla_clang(env)
- if vanilla and cc_version_major < 6:
- print(
- "Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later."
- )
- Exit(255)
- elif not vanilla and cc_version_major < 10:
- print(
- "Detected Apple Clang version older than 10, which does not fully "
- "support C++17. Supported versions are Apple Clang 10 and later."
- )
- Exit(255)
- elif cc_version_major < 6:
+ elif not vanilla and cc_version_major < 10:
print(
- "Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later."
+ "Detected Apple Clang version older than 10, which does not fully "
+ "support C++17. Supported versions are Apple Clang 10 and later."
)
Exit(255)
+ elif cc_version_major < 6:
+ print(
+ "Detected Clang version older than 6, which does not fully support "
+ "C++17. Supported versions are Clang 6 and later."
+ )
+ Exit(255)
- # Disable exception handling. Godot doesn't use exceptions anywhere, and this
- # saves around 20% of binary size and very significant build time (GH-80513).
- if env["disable_exceptions"]:
- if env.msvc:
- env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)])
- else:
- env.Append(CXXFLAGS=["-fno-exceptions"])
- elif env.msvc:
- env.Append(CXXFLAGS=["/EHsc"])
-
- # Configure compiler warnings
- if env.msvc: # MSVC
- if env["warnings"] == "no":
- env.Append(CCFLAGS=["/w"])
- else:
- if env["warnings"] == "extra":
- env.Append(CCFLAGS=["/W4"])
- elif env["warnings"] == "all":
- # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too.
- env.Append(CCFLAGS=["/W3", "/w34458"])
- elif env["warnings"] == "moderate":
- env.Append(CCFLAGS=["/W2"])
- # Disable warnings which we don't plan to fix.
+# Disable exception handling. Godot doesn't use exceptions anywhere, and this
+# saves around 20% of binary size and very significant build time (GH-80513).
+if env["disable_exceptions"]:
+ if env.msvc:
+ env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)])
+ else:
+ env.Append(CXXFLAGS=["-fno-exceptions"])
+elif env.msvc:
+ env.Append(CXXFLAGS=["/EHsc"])
+
+# Configure compiler warnings
+if env.msvc: # MSVC
+ if env["warnings"] == "no":
+ env.Append(CCFLAGS=["/w"])
+ else:
+ if env["warnings"] == "extra":
+ env.Append(CCFLAGS=["/W4"])
+ elif env["warnings"] == "all":
+ # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too.
+ env.Append(CCFLAGS=["/W3", "/w34458"])
+ elif env["warnings"] == "moderate":
+ env.Append(CCFLAGS=["/W2"])
+ # Disable warnings which we don't plan to fix.
+
+ env.Append(
+ CCFLAGS=[
+ "/wd4100", # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
+ "/wd4127", # C4127 (conditional expression is constant)
+ "/wd4201", # C4201 (non-standard nameless struct/union): Only relevant for C89.
+ "/wd4244", # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
+ "/wd4245",
+ "/wd4267",
+ "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid.
+ "/wd4514", # C4514 (unreferenced inline function has been removed)
+ "/wd4714", # C4714 (function marked as __forceinline not inlined)
+ "/wd4820", # C4820 (padding added after construct)
+ ]
+ )
+
+ if env["werror"]:
+ env.Append(CCFLAGS=["/WX"])
+ env.Append(LINKFLAGS=["/WX"])
+else: # GCC, Clang
+ common_warnings = []
+ if methods.using_gcc(env):
+ common_warnings += ["-Wshadow", "-Wno-misleading-indentation"]
+ if cc_version_major == 7: # Bogus warning fixed in 8+.
+ common_warnings += ["-Wno-strict-overflow"]
+ if cc_version_major < 11:
+ # Regression in GCC 9/10, spams so much in our variadic templates
+ # that we need to outright disable it.
+ common_warnings += ["-Wno-type-limits"]
+ if cc_version_major >= 12: # False positives in our error macros, see GH-58747.
+ common_warnings += ["-Wno-return-type"]
+ elif methods.using_clang(env) or methods.using_emcc(env):
+ common_warnings += ["-Wshadow-field-in-constructor", "-Wshadow-uncaptured-local"]
+ # We often implement `operator<` for structs of pointers as a requirement
+ # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
+ common_warnings += ["-Wno-ordered-compare-function-pointers"]
+
+ if env["warnings"] == "extra":
+ env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
+ env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
+ if methods.using_gcc(env):
env.Append(
CCFLAGS=[
- "/wd4100", # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
- "/wd4127", # C4127 (conditional expression is constant)
- "/wd4201", # C4201 (non-standard nameless struct/union): Only relevant for C89.
- "/wd4244", # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
- "/wd4245",
- "/wd4267",
- "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid.
- "/wd4514", # C4514 (unreferenced inline function has been removed)
- "/wd4714", # C4714 (function marked as __forceinline not inlined)
- "/wd4820", # C4820 (padding added after construct)
+ "-Walloc-zero",
+ "-Wduplicated-branches",
+ "-Wduplicated-cond",
+ "-Wstringop-overflow=4",
]
)
-
- if env["werror"]:
- env.Append(CCFLAGS=["/WX"])
- env.Append(LINKFLAGS=["/WX"])
- else: # GCC, Clang
- common_warnings = []
-
- if methods.using_gcc(env):
- common_warnings += ["-Wshadow", "-Wno-misleading-indentation"]
- if cc_version_major == 7: # Bogus warning fixed in 8+.
- common_warnings += ["-Wno-strict-overflow"]
- if cc_version_major < 11:
- # Regression in GCC 9/10, spams so much in our variadic templates
- # that we need to outright disable it.
- common_warnings += ["-Wno-type-limits"]
- if cc_version_major >= 12: # False positives in our error macros, see GH-58747.
- common_warnings += ["-Wno-return-type"]
+ env.Append(CXXFLAGS=["-Wplacement-new=1"])
+ # Need to fix a warning with AudioServer lambdas before enabling.
+ # if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
+ # env.Append(CXXFLAGS=["-Wnoexcept"])
+ if cc_version_major >= 9:
+ env.Append(CCFLAGS=["-Wattribute-alias=2"])
+ if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11.
+ env.Append(CCFLAGS=["-Wlogical-op"])
elif methods.using_clang(env) or methods.using_emcc(env):
- common_warnings += ["-Wshadow-field-in-constructor", "-Wshadow-uncaptured-local"]
- # We often implement `operator<` for structs of pointers as a requirement
- # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
- common_warnings += ["-Wno-ordered-compare-function-pointers"]
-
- if env["warnings"] == "extra":
- env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
- env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
- if methods.using_gcc(env):
- env.Append(
- CCFLAGS=[
- "-Walloc-zero",
- "-Wduplicated-branches",
- "-Wduplicated-cond",
- "-Wstringop-overflow=4",
- ]
- )
- env.Append(CXXFLAGS=["-Wplacement-new=1"])
- # Need to fix a warning with AudioServer lambdas before enabling.
- # if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
- # env.Append(CXXFLAGS=["-Wnoexcept"])
- if cc_version_major >= 9:
- env.Append(CCFLAGS=["-Wattribute-alias=2"])
- if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11.
- env.Append(CCFLAGS=["-Wlogical-op"])
- elif methods.using_clang(env) or methods.using_emcc(env):
- env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
- elif env["warnings"] == "all":
- env.Append(CCFLAGS=["-Wall"] + common_warnings)
- elif env["warnings"] == "moderate":
- env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings)
- else: # 'no'
- env.Append(CCFLAGS=["-w"])
-
- if env["werror"]:
- env.Append(CCFLAGS=["-Werror"])
+ env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
+ elif env["warnings"] == "all":
+ env.Append(CCFLAGS=["-Wall"] + common_warnings)
+ elif env["warnings"] == "moderate":
+ env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings)
+ else: # 'no'
+ env.Append(CCFLAGS=["-w"])
+
+ if env["werror"]:
+ env.Append(CCFLAGS=["-Werror"])
+
+if hasattr(detect, "get_program_suffix"):
+ suffix = "." + detect.get_program_suffix()
+else:
+ suffix = "." + selected_platform
- if hasattr(detect, "get_program_suffix"):
- suffix = "." + detect.get_program_suffix()
- else:
- suffix = "." + selected_platform
+suffix += "." + env["target"]
+if env.dev_build:
+ suffix += ".dev"
- suffix += "." + env["target"]
- if env.dev_build:
- suffix += ".dev"
+if env_base["precision"] == "double":
+ suffix += ".double"
- if env_base["precision"] == "double":
- suffix += ".double"
+suffix += "." + env["arch"]
- suffix += "." + env["arch"]
+if not env["threads"]:
+ suffix += ".nothreads"
- if not env["threads"]:
- suffix += ".nothreads"
+suffix += env.extra_suffix
- suffix += env.extra_suffix
+sys.path.remove(tmppath)
+sys.modules.pop("detect")
- sys.path.remove(tmppath)
- sys.modules.pop("detect")
+modules_enabled = OrderedDict()
+env.module_dependencies = {}
+env.module_icons_paths = []
+env.doc_class_path = platform_doc_class_path
- modules_enabled = OrderedDict()
- env.module_dependencies = {}
- env.module_icons_paths = []
- env.doc_class_path = platform_doc_class_path
+for name, path in modules_detected.items():
+ if not env["module_" + name + "_enabled"]:
+ continue
+ sys.path.insert(0, path)
+ env.current_module = name
+ import config
- for name, path in modules_detected.items():
- if not env["module_" + name + "_enabled"]:
+ if config.can_build(env, selected_platform):
+ # Disable it if a required dependency is missing.
+ if not env.module_check_dependencies(name):
continue
- sys.path.insert(0, path)
- env.current_module = name
- import config
-
- if config.can_build(env, selected_platform):
- # Disable it if a required dependency is missing.
- if not env.module_check_dependencies(name):
- continue
-
- config.configure(env)
- # Get doc classes paths (if present)
- try:
- doc_classes = config.get_doc_classes()
- doc_path = config.get_doc_path()
- for c in doc_classes:
- env.doc_class_path[c] = path + "/" + doc_path
- except Exception:
- pass
- # Get icon paths (if present)
- try:
- icons_path = config.get_icons_path()
- env.module_icons_paths.append(path + "/" + icons_path)
- except Exception:
- # Default path for module icons
- env.module_icons_paths.append(path + "/" + "icons")
- modules_enabled[name] = path
-
- sys.path.remove(path)
- sys.modules.pop("config")
-
- env.module_list = modules_enabled
- methods.sort_module_list(env)
- if env.editor_build:
- # Add editor-specific dependencies to the dependency graph.
- env.module_add_dependencies("editor", ["freetype", "svg"])
+ config.configure(env)
+ # Get doc classes paths (if present)
+ try:
+ doc_classes = config.get_doc_classes()
+ doc_path = config.get_doc_path()
+ for c in doc_classes:
+ env.doc_class_path[c] = path + "/" + doc_path
+ except Exception:
+ pass
+ # Get icon paths (if present)
+ try:
+ icons_path = config.get_icons_path()
+ env.module_icons_paths.append(path + "/" + icons_path)
+ except Exception:
+ # Default path for module icons
+ env.module_icons_paths.append(path + "/" + "icons")
+ modules_enabled[name] = path
- # And check if they are met.
- if not env.module_check_dependencies("editor"):
- print("Not all modules required by editor builds are enabled.")
- Exit(255)
+ sys.path.remove(path)
+ sys.modules.pop("config")
- methods.generate_version_header(env.module_version_string)
-
- env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
- env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
- env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
- # (SH)LIBSUFFIX will be used for our own built libraries
- # LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default,
- # so we need to append the default suffixes to keep the ability
- # to link against thirdparty libraries (.a, .so, .lib, etc.).
- if os.name == "nt":
- # On Windows, only static libraries and import libraries can be
- # statically linked - both using .lib extension
- env["LIBSUFFIXES"] += [env["LIBSUFFIX"]]
- else:
- env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]]
- env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
- env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
+env.module_list = modules_enabled
+methods.sort_module_list(env)
- env["OBJPREFIX"] = env["object_prefix"]
- env["SHOBJPREFIX"] = env["object_prefix"]
+if env.editor_build:
+ # Add editor-specific dependencies to the dependency graph.
+ env.module_add_dependencies("editor", ["freetype", "svg"])
- if env["disable_3d"]:
- if env.editor_build:
- print("Build option 'disable_3d=yes' cannot be used for editor builds, only for export template builds.")
- Exit(255)
- else:
- env.Append(CPPDEFINES=["_3D_DISABLED"])
- if env["disable_advanced_gui"]:
- if env.editor_build:
- print(
- "Build option 'disable_advanced_gui=yes' cannot be used for editor builds, "
- "only for export template builds."
- )
- Exit(255)
- else:
- env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"])
- if env["minizip"]:
- env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
- if env["brotli"]:
- env.Append(CPPDEFINES=["BROTLI_ENABLED"])
-
- if not env["verbose"]:
- methods.no_verbose(sys, env)
-
- GLSL_BUILDERS = {
- "RD_GLSL": env.Builder(
- action=env.Run(glsl_builders.build_rd_headers),
- suffix="glsl.gen.h",
- src_suffix=".glsl",
- ),
- "GLSL_HEADER": env.Builder(
- action=env.Run(glsl_builders.build_raw_headers),
- suffix="glsl.gen.h",
- src_suffix=".glsl",
- ),
- "GLES3_GLSL": env.Builder(
- action=env.Run(gles3_builders.build_gles3_headers),
- suffix="glsl.gen.h",
- src_suffix=".glsl",
- ),
- }
- env.Append(BUILDERS=GLSL_BUILDERS)
-
- scons_cache_path = os.environ.get("SCONS_CACHE")
- if scons_cache_path != None:
- CacheDir(scons_cache_path)
- print("Scons cache enabled... (path: '" + scons_cache_path + "')")
-
- if env["vsproj"]:
- env.vs_incs = []
- env.vs_srcs = []
-
- # CompileDB and Ninja are only available with certain SCons versions which
- # not everybody might have yet, so we have to check.
- from SCons import __version__ as scons_raw_version
-
- scons_ver = env._get_major_minor_revision(scons_raw_version)
- if env["compiledb"] and scons_ver < (4, 0, 0):
- # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
- print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version)
+ # And check if they are met.
+ if not env.module_check_dependencies("editor"):
+ print("Not all modules required by editor builds are enabled.")
Exit(255)
- if scons_ver >= (4, 0, 0):
- env.Tool("compilation_db")
- env.Alias("compiledb", env.CompilationDatabase())
- if env["ninja"]:
- if scons_ver < (4, 2, 0):
- print("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version)
- Exit(255)
-
- SetOption("experimental", "ninja")
-
- # By setting this we allow the user to run ninja by themselves with all
- # the flags they need, as apparently automatically running from scons
- # is way slower.
- SetOption("disable_execute_ninja", True)
-
- env.Tool("ninja")
-
- # Threads
- if env["threads"]:
- env.Append(CPPDEFINES=["THREADS_ENABLED"])
+methods.generate_version_header(env.module_version_string)
+
+env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
+env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
+env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
+# (SH)LIBSUFFIX will be used for our own built libraries
+# LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default,
+# so we need to append the default suffixes to keep the ability
+# to link against thirdparty libraries (.a, .so, .lib, etc.).
+if os.name == "nt":
+ # On Windows, only static libraries and import libraries can be
+ # statically linked - both using .lib extension
+ env["LIBSUFFIXES"] += [env["LIBSUFFIX"]]
+else:
+ env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]]
+env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
+env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
- # Build subdirs, the build order is dependent on link order.
- Export("env")
+env["OBJPREFIX"] = env["object_prefix"]
+env["SHOBJPREFIX"] = env["object_prefix"]
- SConscript("core/SCsub")
- SConscript("servers/SCsub")
- SConscript("scene/SCsub")
+if env["disable_3d"]:
if env.editor_build:
- SConscript("editor/SCsub")
- SConscript("drivers/SCsub")
-
- SConscript("platform/SCsub")
- SConscript("modules/SCsub")
- if env["tests"]:
- SConscript("tests/SCsub")
- SConscript("main/SCsub")
-
- SConscript("platform/" + selected_platform + "/SCsub") # Build selected platform.
-
- # Microsoft Visual Studio Project Generation
- if env["vsproj"]:
- env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]]
- methods.generate_vs_project(env, ARGUMENTS, env["vsproj_name"])
- methods.generate_cpp_hint_file("cpp.hint")
-
- # Check for the existence of headers
- conf = Configure(env)
- if "check_c_headers" in env:
- headers = env["check_c_headers"]
- for header in headers:
- if conf.CheckCHeader(header):
- env.AppendUnique(CPPDEFINES=[headers[header]])
-
-elif selected_platform != "":
- if selected_platform == "list":
- print("The following platforms are available:\n")
+ print("Build option 'disable_3d=yes' cannot be used for editor builds, only for export template builds.")
+ Exit(255)
else:
- print('Invalid target platform "' + selected_platform + '".')
- print("The following platforms were detected:\n")
-
- for x in platform_list:
- print("\t" + x)
-
- print("\nPlease run SCons again and select a valid platform: platform=<string>")
-
- if selected_platform == "list":
- # Exit early to suppress the rest of the built-in SCons messages
- Exit()
+ env.Append(CPPDEFINES=["_3D_DISABLED"])
+if env["disable_advanced_gui"]:
+ if env.editor_build:
+ print(
+ "Build option 'disable_advanced_gui=yes' cannot be used for editor builds, "
+ "only for export template builds."
+ )
+ Exit(255)
else:
+ env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"])
+if env["minizip"]:
+ env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
+if env["brotli"]:
+ env.Append(CPPDEFINES=["BROTLI_ENABLED"])
+
+if not env["verbose"]:
+ methods.no_verbose(sys, env)
+
+GLSL_BUILDERS = {
+ "RD_GLSL": env.Builder(
+ action=env.Run(glsl_builders.build_rd_headers),
+ suffix="glsl.gen.h",
+ src_suffix=".glsl",
+ ),
+ "GLSL_HEADER": env.Builder(
+ action=env.Run(glsl_builders.build_raw_headers),
+ suffix="glsl.gen.h",
+ src_suffix=".glsl",
+ ),
+ "GLES3_GLSL": env.Builder(
+ action=env.Run(gles3_builders.build_gles3_headers),
+ suffix="glsl.gen.h",
+ src_suffix=".glsl",
+ ),
+}
+env.Append(BUILDERS=GLSL_BUILDERS)
+
+scons_cache_path = os.environ.get("SCONS_CACHE")
+if scons_cache_path != None:
+ CacheDir(scons_cache_path)
+ print("Scons cache enabled... (path: '" + scons_cache_path + "')")
+
+if env["vsproj"]:
+ env.vs_incs = []
+ env.vs_srcs = []
+
+# CompileDB and Ninja are only available with certain SCons versions which
+# not everybody might have yet, so we have to check.
+from SCons import __version__ as scons_raw_version
+
+scons_ver = env._get_major_minor_revision(scons_raw_version)
+if env["compiledb"] and scons_ver < (4, 0, 0):
+ # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
+ print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version)
+ Exit(255)
+if scons_ver >= (4, 0, 0):
+ env.Tool("compilation_db")
+ env.Alias("compiledb", env.CompilationDatabase())
+
+if env["ninja"]:
+ if scons_ver < (4, 2, 0):
+ print("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version)
Exit(255)
-# The following only makes sense when the 'env' is defined, and assumes it is.
-if "env" in locals():
- # FIXME: This method mixes both cosmetic progress stuff and cache handling...
- methods.show_progress(env)
- # TODO: replace this with `env.Dump(format="json")`
- # once we start requiring SCons 4.0 as min version.
- methods.dump(env)
+ SetOption("experimental", "ninja")
+
+ # By setting this we allow the user to run ninja by themselves with all
+ # the flags they need, as apparently automatically running from scons
+ # is way slower.
+ SetOption("disable_execute_ninja", True)
+
+ env.Tool("ninja")
+
+# Threads
+if env["threads"]:
+ env.Append(CPPDEFINES=["THREADS_ENABLED"])
+
+# Build subdirs, the build order is dependent on link order.
+Export("env")
+
+SConscript("core/SCsub")
+SConscript("servers/SCsub")
+SConscript("scene/SCsub")
+if env.editor_build:
+ SConscript("editor/SCsub")
+SConscript("drivers/SCsub")
+
+SConscript("platform/SCsub")
+SConscript("modules/SCsub")
+if env["tests"]:
+ SConscript("tests/SCsub")
+SConscript("main/SCsub")
+
+SConscript("platform/" + selected_platform + "/SCsub") # Build selected platform.
+
+# Microsoft Visual Studio Project Generation
+if env["vsproj"]:
+ env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]]
+ methods.generate_vs_project(env, ARGUMENTS, env["vsproj_name"])
+ methods.generate_cpp_hint_file("cpp.hint")
+
+# Check for the existence of headers
+conf = Configure(env)
+if "check_c_headers" in env:
+ headers = env["check_c_headers"]
+ for header in headers:
+ if conf.CheckCHeader(header):
+ env.AppendUnique(CPPDEFINES=[headers[header]])
+
+
+# FIXME: This method mixes both cosmetic progress stuff and cache handling...
+methods.show_progress(env)
+# TODO: replace this with `env.Dump(format="json")`
+# once we start requiring SCons 4.0 as min version.
+methods.dump(env)
def print_elapsed_time():
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 14023c5c75..352486bd09 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1438,6 +1438,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/run/disable_stdout", false);
GLOBAL_DEF("application/run/disable_stderr", false);
GLOBAL_DEF("application/run/print_header", true);
+ GLOBAL_DEF("application/run/enable_alt_space_menu", false);
GLOBAL_DEF_RST("application/config/use_hidden_project_data_directory", true);
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
@@ -1538,6 +1539,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
diff --git a/core/crypto/SCsub b/core/crypto/SCsub
index ac79e10d19..a6defdfdab 100644
--- a/core/crypto/SCsub
+++ b/core/crypto/SCsub
@@ -21,9 +21,9 @@ if is_builtin or not has_module:
# to make a "light" build with only the necessary mbedtls files.
if not has_module:
# Minimal mbedTLS config file
- env_crypto.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
+ env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Build minimal mbedTLS library (MD5/SHA/Base64/AES).
env_thirdparty = env_crypto.Clone()
env_thirdparty.disable_warnings()
@@ -46,9 +46,9 @@ if not has_module:
env.core_sources += thirdparty_obj
elif is_builtin:
# Module mbedTLS config file
- env_crypto.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
+ env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Needed to force rebuilding the core files when the configuration file is updated.
thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index dc974a545a..74f18ceee1 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -424,8 +424,7 @@ RID Resource::get_rid() const {
}
}
if (_get_extension() && _get_extension()->get_rid) {
- RID ret;
- ret.from_uint64(_get_extension()->get_rid(_get_extension_instance()));
+ RID ret = RID::from_uint64(_get_extension()->get_rid(_get_extension_instance()));
if (ret.is_valid()) {
return ret;
}
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 478fde3a64..80662c1b07 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -77,15 +77,17 @@ subject to the following restrictions:
#ifdef DEBUG_ENABLED
#define CHULL_ASSERT(m_cond) \
- do { \
+ if constexpr (true) { \
if (unlikely(!(m_cond))) { \
ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \
} \
- } while (0)
+ } else \
+ ((void)0)
#else
#define CHULL_ASSERT(m_cond) \
- do { \
- } while (0)
+ if constexpr (true) { \
+ } else \
+ ((void)0)
#endif
#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS)
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index acbaed4ce8..9a993cd14f 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -36,12 +36,13 @@
#include "core/string/print_string.h"
#define COMPACT_CHUNK(m_entry, m_to_pos) \
- do { \
+ if constexpr (true) { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
void *_src = &((unsigned char *)pool)[(m_entry).pos]; \
memmove(_dst, _src, aligned((m_entry).len)); \
(m_entry).pos = m_to_pos; \
- } while (0);
+ } else \
+ ((void)0)
void PoolAllocator::mt_lock() const {
}
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index bdef1b9bbe..2b62b72a51 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -2110,12 +2110,12 @@ CharString String::utf8() const {
String String::utf16(const char16_t *p_utf16, int p_len) {
String ret;
- ret.parse_utf16(p_utf16, p_len);
+ ret.parse_utf16(p_utf16, p_len, true);
return ret;
}
-Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
+Error String::parse_utf16(const char16_t *p_utf16, int p_len, bool p_default_little_endian) {
if (!p_utf16) {
return ERR_INVALID_DATA;
}
@@ -2125,8 +2125,12 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
int cstr_size = 0;
int str_size = 0;
+#ifdef BIG_ENDIAN_ENABLED
+ bool byteswap = p_default_little_endian;
+#else
+ bool byteswap = !p_default_little_endian;
+#endif
/* HANDLE BOM (Byte Order Mark) */
- bool byteswap = false; // assume correct endianness if no BOM found
if (p_len < 0 || p_len >= 1) {
bool has_bom = false;
if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is
diff --git a/core/string/ustring.h b/core/string/ustring.h
index fa904c8200..693df6dcba 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -393,7 +393,7 @@ public:
static String utf8(const char *p_utf8, int p_len = -1);
Char16String utf16() const;
- Error parse_utf16(const char16_t *p_utf16, int p_len = -1);
+ Error parse_utf16(const char16_t *p_utf16, int p_len = -1, bool p_default_little_endian = true);
static String utf16(const char16_t *p_utf16, int p_len = -1);
static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 60ae09c6f1..dcf4b287d1 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -230,18 +230,20 @@ public:
};
#define register_string_op(m_op_type, m_op_code) \
- do { \
+ if constexpr (true) { \
register_op<m_op_type<String, String>>(m_op_code, Variant::STRING, Variant::STRING); \
register_op<m_op_type<String, StringName>>(m_op_code, Variant::STRING, Variant::STRING_NAME); \
register_op<m_op_type<StringName, String>>(m_op_code, Variant::STRING_NAME, Variant::STRING); \
register_op<m_op_type<StringName, StringName>>(m_op_code, Variant::STRING_NAME, Variant::STRING_NAME); \
- } while (false)
+ } else \
+ ((void)0)
#define register_string_modulo_op(m_class, m_type) \
- do { \
+ if constexpr (true) { \
register_op<OperatorEvaluatorStringFormat<String, m_class>>(Variant::OP_MODULE, Variant::STRING, m_type); \
register_op<OperatorEvaluatorStringFormat<StringName, m_class>>(Variant::OP_MODULE, Variant::STRING_NAME, m_type); \
- } while (false)
+ } else \
+ ((void)0)
void Variant::_register_variant_operators() {
memset(operator_return_type_table, 0, sizeof(operator_return_type_table));
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index fd5ba57615..a72ac60536 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -40,6 +40,7 @@
[/codeblocks]
[b]Note:[/b] Arrays are always passed by reference. To get a copy of an array that can be modified independently of the original array, use [method duplicate].
[b]Note:[/b] Erasing elements while iterating over arrays is [b]not[/b] supported and will result in unpredictable behavior.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt64Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
</tutorials>
@@ -57,7 +58,30 @@
<param index="2" name="class_name" type="StringName" />
<param index="3" name="script" type="Variant" />
<description>
- Creates a typed array from the [param base] array.
+ Creates a typed array from the [param base] array. All arguments are required.
+ - [param type] is the built-in type as a [enum Variant.Type] constant, for example [constant TYPE_INT].
+ - [param class_name] is the [b]native[/b] class name, for example [Node]. If [param type] is not [constant TYPE_OBJECT], must be an empty string.
+ - [param script] is the associated script. Must be a [Script] instance or [code]null[/code].
+ Examples:
+ [codeblock]
+ class_name MyNode
+ extends Node
+
+ class MyClass:
+ pass
+
+ func _ready():
+ var a = Array([], TYPE_INT, &amp;"", null) # Array[int]
+ var b = Array([], TYPE_OBJECT, &amp;"Node", null) # Array[Node]
+ var c = Array([], TYPE_OBJECT, &amp;"Node", MyNode) # Array[MyNode]
+ var d = Array([], TYPE_OBJECT, &amp;"RefCounted", MyClass) # Array[MyClass]
+ [/codeblock]
+ [b]Note:[/b] This constructor can be useful if you want to create a typed array on the fly, but you are not required to use it. In GDScript you can use a temporary variable with the static type you need and then pass it:
+ [codeblock]
+ func _ready():
+ var a: Array[int] = []
+ some_func(a)
+ [/codeblock]
</description>
</constructor>
<constructor name="Array">
@@ -323,19 +347,19 @@
<method name="get_typed_builtin" qualifiers="const">
<return type="int" />
<description>
- Returns the [enum Variant.Type] constant for a typed array. If the [Array] is not typed, returns [constant TYPE_NIL].
+ Returns the built-in type of the typed array as a [enum Variant.Type] constant. If the array is not typed, returns [constant TYPE_NIL].
</description>
</method>
<method name="get_typed_class_name" qualifiers="const">
<return type="StringName" />
<description>
- Returns a class name of a typed [Array] of type [constant TYPE_OBJECT].
+ Returns the [b]native[/b] class name of the typed array if the built-in type is [constant TYPE_OBJECT]. Otherwise, this method returns an empty string.
</description>
</method>
<method name="get_typed_script" qualifiers="const">
<return type="Variant" />
<description>
- Returns the script associated with a typed array tied to a class name.
+ Returns the script associated with the typed array. This method returns a [Script] instance or [code]null[/code].
</description>
</method>
<method name="has" qualifiers="const" keywords="includes, contains">
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index fbe2508da3..32518e3e92 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamPlayer" inherits="Node" keywords="sound, music, song" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Plays back audio non-positionally.
+ A node for audio playback.
</brief_description>
<description>
- Plays an audio stream non-positionally.
- To play audio positionally, use [AudioStreamPlayer2D] or [AudioStreamPlayer3D] instead of [AudioStreamPlayer].
+ The [AudioStreamPlayer] node plays an audio stream non-positionally. It is ideal for user interfaces, menus, or background music.
+ To use this node, [member stream] needs to be set to a valid [AudioStream] resource. Playing more than one sound at the time is also supported, see [member max_polyphony].
+ If you need to play audio at a specific position, use [AudioStreamPlayer2D] or [AudioStreamPlayer3D] instead.
</description>
<tutorials>
<link title="Audio streams">$DOCS_URL/tutorials/audio/audio_streams.html</link>
@@ -19,82 +20,85 @@
<method name="get_playback_position">
<return type="float" />
<description>
- Returns the position in the [AudioStream] in seconds.
+ Returns the position in the [AudioStream] of the latest sound, in seconds. Returns [code]0.0[/code] if no sounds are playing.
+ [b]Note:[/b] The position is not always accurate, as the [AudioServer] does not mix audio every processed frame. To get more accurate results, add [method AudioServer.get_time_since_last_mix] to the returned position.
</description>
</method>
<method name="get_stream_playback">
<return type="AudioStreamPlayback" />
<description>
- Returns the [AudioStreamPlayback] object associated with this [AudioStreamPlayer].
+ Returns the latest [AudioStreamPlayback] of this node, usually the most recently created by [method play]. If no sounds are playing, this method fails and returns an empty playback.
</description>
</method>
<method name="has_stream_playback">
<return type="bool" />
<description>
- Returns whether the [AudioStreamPlayer] can return the [AudioStreamPlayback] object or not.
+ Returns [code]true[/code] if any sound is active, even if [member stream_paused] is set to [code]true[/code]. See also [member playing] and [method get_stream_playback].
</description>
</method>
<method name="play">
<return type="void" />
<param index="0" name="from_position" type="float" default="0.0" />
<description>
- Plays the audio from the given [param from_position], in seconds.
+ Plays a sound from the beginning, or the given [param from_position] in seconds.
</description>
</method>
<method name="seek">
<return type="void" />
<param index="0" name="to_position" type="float" />
<description>
- Sets the position from which audio will be played, in seconds.
+ Restarts all sounds to be played from the given [param to_position], in seconds. Does nothing if no sounds are playing.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
- Stops the audio.
+ Stops all sounds from this node.
</description>
</method>
</methods>
<members>
<member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false">
- If [code]true[/code], audio plays when added to scene tree.
+ If [code]true[/code], this node calls [method play] when entering the tree.
</member>
<member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&amp;&quot;Master&quot;">
- Bus on which this audio is playing.
- [b]Note:[/b] When setting this property, keep in mind that no validation is performed to see if the given name matches an existing bus. This is because audio bus layouts might be loaded after this property is set. If this given name can't be resolved at runtime, it will fall back to [code]"Master"[/code].
+ The target bus name. All sounds from this node will be playing on this bus.
+ [b]Note:[/b] At runtime, if no bus with the given name exists, all sounds will fall back on [code]"Master"[/code]. See also [method AudioServer.get_bus_name].
</member>
<member name="max_polyphony" type="int" setter="set_max_polyphony" getter="get_max_polyphony" default="1">
- The maximum number of sounds this node can play at the same time. Playing additional sounds after this value is reached will cut off the oldest sounds.
+ The maximum number of sounds this node can play at the same time. Calling [method play] after this value is reached will cut off the oldest sounds.
</member>
<member name="mix_target" type="int" setter="set_mix_target" getter="get_mix_target" enum="AudioStreamPlayer.MixTarget" default="0">
- If the audio configuration has more than two speakers, this sets the target channels. See [enum MixTarget] constants.
+ The mix target channels, as one of the [enum MixTarget] constants. Has no effect when two speakers or less are detected (see [enum AudioServer.SpeakerMode]).
</member>
<member name="pitch_scale" type="float" setter="set_pitch_scale" getter="get_pitch_scale" default="1.0">
- The pitch and the tempo of the audio, as a multiplier of the audio sample's sample rate.
+ The audio's pitch and tempo, as a multiplier of the [member stream]'s sample rate. A value of [code]2.0[/code] doubles the audio's pitch, while a value of [code]0.5[/code] halves the pitch.
</member>
<member name="playing" type="bool" setter="_set_playing" getter="is_playing" default="false">
- If [code]true[/code], audio is playing.
+ If [code]true[/code], this node is playing sounds. Setting this property has the same effect as [method play] and [method stop].
</member>
<member name="stream" type="AudioStream" setter="set_stream" getter="get_stream">
- The [AudioStream] object to be played.
+ The [AudioStream] resource to be played. Setting this property stops all currently playing sounds. If left empty, the [AudioStreamPlayer] does not work.
</member>
<member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false">
- If [code]true[/code], the playback is paused. You can resume it by setting [member stream_paused] to [code]false[/code].
+ If [code]true[/code], the sounds are paused. Setting [member stream_paused] to [code]false[/code] resumes all sounds.
+ [b]Note:[/b] This property is automatically changed when exiting or entering the tree, or this node is paused (see [member Node.process_mode]).
</member>
<member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db" default="0.0">
- Volume of sound, in dB.
+ Volume of sound, in decibel. This is an offset of the [member stream]'s volume.
+ [b]Note:[/b] To convert between decibel and linear energy (like most volume sliders do), use [method @GlobalScope.db_to_linear] and [method @GlobalScope.linear_to_db].
</member>
</members>
<signals>
<signal name="finished">
<description>
- Emitted when the audio stops playing.
+ Emitted when a sound finishes playing without interruptions. This signal is [i]not[/i] emitted when calling [method stop], or when exiting the tree while sounds are playing.
</description>
</signal>
</signals>
<constants>
<constant name="MIX_TARGET_STEREO" value="0" enum="MixTarget">
- The audio will be played only on the first channel.
+ The audio will be played only on the first channel. This is the default.
</constant>
<constant name="MIX_TARGET_SURROUND" value="1" enum="MixTarget">
The audio will be played on all surround channels.
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 72783bc5d6..5ca03e4838 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -606,14 +606,15 @@
[b]Note:[/b] For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead.
</member>
<member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false">
- If [code]true[/code], this [CanvasItem] and its [CanvasItem] child nodes are sorted according to the Y position. Nodes with a lower Y position are drawn before those with a higher Y position. If [code]false[/code], Y-sorting is disabled.
- You can nest nodes with Y-sorting. Child Y-sorted nodes are sorted in the same space as the parent Y-sort. This feature allows you to organize a scene better or divide it into multiple ones without changing your scene tree.
+ If [code]true[/code], this and child [CanvasItem] nodes with a lower Y position are rendered in front of nodes with a higher Y position. If [code]false[/code], this and child [CanvasItem] nodes are rendered normally in scene tree order.
+ With Y-sorting enabled on a parent node ('A') but disabled on a child node ('B'), the child node ('B') is sorted but its children ('C1', 'C2', etc) render together on the same Y position as the child node 'B'. This allows you to organize the render order of a scene without changing the scene tree.
+ Nodes sort relative to each other only if they are on the same [member z_index].
</member>
<member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true">
If [code]true[/code], the node's Z index is relative to its parent's Z index. If this node's Z index is 2 and its parent's effective Z index is 3, then this node's effective Z index will be 2 + 3 = 5.
</member>
<member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0">
- Z index. Controls the order in which the nodes render. A node with a higher Z index will display in front of others. Must be between [constant RenderingServer.CANVAS_ITEM_Z_MIN] and [constant RenderingServer.CANVAS_ITEM_Z_MAX] (inclusive).
+ Controls the order in which the nodes render. A node with a higher Z index will display in front of others. Must be between [constant RenderingServer.CANVAS_ITEM_Z_MIN] and [constant RenderingServer.CANVAS_ITEM_Z_MAX] (inclusive).
[b]Note:[/b] Changing the Z index of a [Control] only affects the drawing order, not the order in which input events are handled. This can be useful to implement certain UI animations, e.g. a menu where hovered items are scaled and should overlap others.
</member>
</members>
diff --git a/doc/classes/EditorExportPlatformPC.xml b/doc/classes/EditorExportPlatformPC.xml
index 3c2a27deab..def14e5955 100644
--- a/doc/classes/EditorExportPlatformPC.xml
+++ b/doc/classes/EditorExportPlatformPC.xml
@@ -4,7 +4,10 @@
Base class for the desktop platform exporter (Windows and Linux/BSD).
</brief_description>
<description>
+ The base class for the desktop platform exporters. These include Windows and Linux/BSD, but not macOS. See the classes inheriting this one for more details.
</description>
<tutorials>
+ <link title="Exporting for Windows">$DOCS_URL/tutorials/export/exporting_for_windows.html</link>
+ <link title="Exporting for Linux">$DOCS_URL/tutorials/export/exporting_for_linux.html</link>
</tutorials>
</class>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index f4ba305f8b..3e9de4f91d 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -43,7 +43,8 @@
<method name="restart">
<return type="void" />
<description>
- Restarts all the existing particles.
+ Restarts the particle emission cycle, clearing existing particles. To avoid particles vanishing from the viewport, wait for the [signal finished] signal before calling.
+ [b]Note:[/b] The [signal finished] signal is only emitted by [member one_shot] emitters.
</description>
</method>
</methods>
@@ -64,7 +65,9 @@
Particle draw order. Uses [enum DrawOrder] values.
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle unless all active particles have finished processing. Use the [signal finished] signal to be notified once all active particles finish processing.
+ [b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the [signal finished] signal during which setting this to [code]true[/code] will not restart the emission cycle.
+ [b]Tip:[/b] If your [member one_shot] emitter needs to immediately restart emitting particles once [signal finished] signal is received, consider calling [method restart] instead of setting [member emitting].
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
@@ -132,8 +135,9 @@
<signals>
<signal name="finished">
<description>
- Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
- [b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
+ Emitted when all active particles have finished processing. To immediately restart the emission cycle, call [method restart].
+ Never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
+ [b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the signal during which setting [member emitting] to [code]true[/code] will not restart the emission cycle. This delay is avoided by instead calling [method restart].
</description>
</signal>
</signals>
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index d1903b85cd..9f965a2378 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -48,7 +48,8 @@
<method name="restart">
<return type="void" />
<description>
- Restarts the particle emission, clearing existing particles.
+ Restarts the particle emission cycle, clearing existing particles. To avoid particles vanishing from the viewport, wait for the [signal finished] signal before calling.
+ [b]Note:[/b] The [signal finished] signal is only emitted by [member one_shot] emitters.
</description>
</method>
<method name="set_draw_pass_mesh">
@@ -95,7 +96,9 @@
<member name="draw_skin" type="Skin" setter="set_skin" getter="get_skin">
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle unless all active particles have finished processing. Use the [signal finished] signal to be notified once all active particles finish processing.
+ [b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the [signal finished] signal during which setting this to [code]true[/code] will not restart the emission cycle.
+ [b]Tip:[/b] If your [member one_shot] emitter needs to immediately restart emitting particles once [signal finished] signal is received, consider calling [method restart] instead of setting [member emitting].
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
@@ -157,8 +160,9 @@
<signals>
<signal name="finished">
<description>
- Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
- [b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
+ Emitted when all active particles have finished processing. To immediately emit new particles, call [method restart].
+ Never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
+ [b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the signal during which setting [member emitting] to [code]true[/code] will not restart the emission cycle. This delay is avoided by instead calling [method restart].
</description>
</signal>
</signals>
diff --git a/doc/classes/JSONRPC.xml b/doc/classes/JSONRPC.xml
index 348688f7f8..e5ee93cb93 100644
--- a/doc/classes/JSONRPC.xml
+++ b/doc/classes/JSONRPC.xml
@@ -79,15 +79,19 @@
</methods>
<constants>
<constant name="PARSE_ERROR" value="-32700" enum="ErrorCode">
+ The request could not be parsed as it was not valid by JSON standard ([method JSON.parse] failed).
</constant>
<constant name="INVALID_REQUEST" value="-32600" enum="ErrorCode">
+ A method call was requested but the request's format is not valid.
</constant>
<constant name="METHOD_NOT_FOUND" value="-32601" enum="ErrorCode">
A method call was requested but no function of that name existed in the JSONRPC subclass.
</constant>
<constant name="INVALID_PARAMS" value="-32602" enum="ErrorCode">
+ A method call was requested but the given method parameters are not valid. Not used by the built-in JSONRPC.
</constant>
<constant name="INTERNAL_ERROR" value="-32603" enum="ErrorCode">
+ An internal error occurred while processing the request. Not used by the built-in JSONRPC.
</constant>
</constants>
</class>
diff --git a/doc/classes/JavaClass.xml b/doc/classes/JavaClass.xml
index 541f23013d..ecfcaa8781 100644
--- a/doc/classes/JavaClass.xml
+++ b/doc/classes/JavaClass.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JavaClass" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Represents an object from the Java Native Interface.
</brief_description>
<description>
+ Represents an object from the Java Native Interface. It is returned from [method JavaClassWrapper.wrap].
+ [b]Note:[/b] This class only works on Android. For any other build, this class does nothing.
+ [b]Note:[/b] This class is not to be confused with [JavaScriptObject].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/JavaClassWrapper.xml b/doc/classes/JavaClassWrapper.xml
index e197b1e97e..01c3392b04 100644
--- a/doc/classes/JavaClassWrapper.xml
+++ b/doc/classes/JavaClassWrapper.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JavaClassWrapper" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Provides access to the Java Native Interface.
</brief_description>
<description>
+ The JavaClassWrapper singleton provides a way for the Godot application to send and receive data through the [url=https://developer.android.com/training/articles/perf-jni]Java Native Interface[/url] (JNI).
+ [b]Note:[/b] This singleton is only available in Android builds.
</description>
<tutorials>
</tutorials>
@@ -11,6 +14,8 @@
<return type="JavaClass" />
<param index="0" name="name" type="String" />
<description>
+ Wraps a class defined in Java, and returns it as a [JavaClass] [Object] type that Godot can interact with.
+ [b]Note:[/b] This method only works on Android. On every other platform, this method does nothing and returns an empty [JavaClass].
</description>
</method>
</methods>
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index ad96ba2490..c2156e511f 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold [Color]. Packs data tightly, so it saves memory for large array sizes.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedColorArray] versus [code]Array[Color][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index aef5ab90ac..9b62df2ada 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -6,6 +6,7 @@
<description>
An array specifically designed to hold 64-bit floating-point values (double). Packs data tightly, so it saves memory for large array sizes.
If you only need to pack 32-bit floats tightly, see [PackedFloat32Array] for a more memory-friendly alternative.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedFloat64Array] versus [code]Array[float][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index 55024341c1..cbbcdb12d7 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -6,6 +6,7 @@
<description>
An array specifically designed to hold 64-bit integer values. Packs data tightly, so it saves memory for large array sizes.
[b]Note:[/b] This type stores signed 64-bit integers, which means it can take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. [code][-9223372036854775808, 9223372036854775807][/code]. Exceeding those bounds will wrap around. If you only need to pack 32-bit integers tightly, see [PackedInt32Array] for a more memory-friendly alternative.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt32Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index f1b02272f3..5a55bed82d 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -11,6 +11,7 @@
var string = " ".join(string_array)
print(string) # "hello world"
[/codeblock]
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedStringArray] versus [code]Array[String][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
<link title="OS Test Demo">https://godotengine.org/asset-library/asset/677</link>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index c73fea9114..b6766d7a99 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold [Vector2]. Packs data tightly, so it saves memory for large array sizes.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedVector3Array] versus [code]Array[Vector2][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
<link title="2D Navigation Astar Demo">https://godotengine.org/asset-library/asset/519</link>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 89f258eaea..e610dea0a4 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold [Vector3]. Packs data tightly, so it saves memory for large array sizes.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedVector3Array] versus [code]Array[Vector3][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index c3b202e0a5..bce1a80526 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -13,7 +13,7 @@
<return type="void" />
<param index="0" name="state" type="PhysicsDirectBodyState3D" />
<description>
- Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
+ Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it is called before the standard force integration, but the [member custom_integrator] property allows you to disable the standard force integration and do fully custom force integration for a body.
</description>
</method>
<method name="apply_central_impulse">
@@ -67,7 +67,8 @@
If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awakened by an external force.
</member>
<member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false">
- If [code]true[/code], internal force integration will be disabled (like gravity or air friction) for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] function, if defined.
+ If [code]true[/code], the standard force integration (like gravity or damping) will be disabled for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] method, if that virtual method is overridden.
+ Setting this property will call the method [method PhysicsServer3D.body_set_omit_force_integration] internally.
</member>
<member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0">
The body's friction, from [code]0[/code] (frictionless) to [code]1[/code] (max friction).
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index 7051663a78..d60cc1ee6b 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -202,7 +202,7 @@
<method name="integrate_forces">
<return type="void" />
<description>
- Calls the built-in force integration code.
+ Updates the body's linear and angular velocity by applying gravity and damping for the equivalent of one physics tick.
</description>
</method>
<method name="set_constant_force">
diff --git a/doc/classes/PhysicsDirectBodyState2DExtension.xml b/doc/classes/PhysicsDirectBodyState2DExtension.xml
index 04612b461e..932c1c8352 100644
--- a/doc/classes/PhysicsDirectBodyState2DExtension.xml
+++ b/doc/classes/PhysicsDirectBodyState2DExtension.xml
@@ -14,6 +14,7 @@
<return type="void" />
<param index="0" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.add_constant_central_force].
</description>
</method>
<method name="_add_constant_force" qualifiers="virtual">
@@ -21,24 +22,28 @@
<param index="0" name="force" type="Vector2" />
<param index="1" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.add_constant_force].
</description>
</method>
<method name="_add_constant_torque" qualifiers="virtual">
<return type="void" />
<param index="0" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.add_constant_torque].
</description>
</method>
<method name="_apply_central_force" qualifiers="virtual">
<return type="void" />
<param index="0" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_central_force].
</description>
</method>
<method name="_apply_central_impulse" qualifiers="virtual">
<return type="void" />
<param index="0" name="impulse" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_central_impulse].
</description>
</method>
<method name="_apply_force" qualifiers="virtual">
@@ -46,6 +51,7 @@
<param index="0" name="force" type="Vector2" />
<param index="1" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_force].
</description>
</method>
<method name="_apply_impulse" qualifiers="virtual">
@@ -53,211 +59,249 @@
<param index="0" name="impulse" type="Vector2" />
<param index="1" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_impulse].
</description>
</method>
<method name="_apply_torque" qualifiers="virtual">
<return type="void" />
<param index="0" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_torque].
</description>
</method>
<method name="_apply_torque_impulse" qualifiers="virtual">
<return type="void" />
<param index="0" name="impulse" type="float" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.apply_torque_impulse].
</description>
</method>
<method name="_get_angular_velocity" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.angular_velocity] and its respective getter.
</description>
</method>
<method name="_get_center_of_mass" qualifiers="virtual const">
<return type="Vector2" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.center_of_mass] and its respective getter.
</description>
</method>
<method name="_get_center_of_mass_local" qualifiers="virtual const">
<return type="Vector2" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.center_of_mass_local] and its respective getter.
</description>
</method>
<method name="_get_constant_force" qualifiers="virtual const">
<return type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_constant_force].
</description>
</method>
<method name="_get_constant_torque" qualifiers="virtual const">
<return type="float" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_constant_torque].
</description>
</method>
<method name="_get_contact_collider" qualifiers="virtual const">
<return type="RID" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider].
</description>
</method>
<method name="_get_contact_collider_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider_id].
</description>
</method>
<method name="_get_contact_collider_object" qualifiers="virtual const">
<return type="Object" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider_object].
</description>
</method>
<method name="_get_contact_collider_position" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider_position].
</description>
</method>
<method name="_get_contact_collider_shape" qualifiers="virtual const">
<return type="int" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider_shape].
</description>
</method>
<method name="_get_contact_collider_velocity_at_position" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_collider_velocity_at_position].
</description>
</method>
<method name="_get_contact_count" qualifiers="virtual const">
<return type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_count].
</description>
</method>
<method name="_get_contact_impulse" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_impulse].
</description>
</method>
<method name="_get_contact_local_normal" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_local_normal].
</description>
</method>
<method name="_get_contact_local_position" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_local_position].
</description>
</method>
<method name="_get_contact_local_shape" qualifiers="virtual const">
<return type="int" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_local_shape].
</description>
</method>
<method name="_get_contact_local_velocity_at_position" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="contact_idx" type="int" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_contact_local_velocity_at_position].
</description>
</method>
<method name="_get_inverse_inertia" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.inverse_inertia] and its respective getter.
</description>
</method>
<method name="_get_inverse_mass" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.inverse_mass] and its respective getter.
</description>
</method>
<method name="_get_linear_velocity" qualifiers="virtual const">
<return type="Vector2" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.linear_velocity] and its respective getter.
</description>
</method>
<method name="_get_space_state" qualifiers="virtual">
<return type="PhysicsDirectSpaceState2D" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_space_state].
</description>
</method>
<method name="_get_step" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.step] and its respective getter.
</description>
</method>
<method name="_get_total_angular_damp" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.total_angular_damp] and its respective getter.
</description>
</method>
<method name="_get_total_gravity" qualifiers="virtual const">
<return type="Vector2" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.total_gravity] and its respective getter.
</description>
</method>
<method name="_get_total_linear_damp" qualifiers="virtual const">
<return type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.total_linear_damp] and its respective getter.
</description>
</method>
<method name="_get_transform" qualifiers="virtual const">
<return type="Transform2D" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.transform] and its respective getter.
</description>
</method>
<method name="_get_velocity_at_local_position" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="local_position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.get_velocity_at_local_position].
</description>
</method>
<method name="_integrate_forces" qualifiers="virtual">
<return type="void" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.integrate_forces].
</description>
</method>
<method name="_is_sleeping" qualifiers="virtual const">
<return type="bool" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.sleeping] and its respective getter.
</description>
</method>
<method name="_set_angular_velocity" qualifiers="virtual">
<return type="void" />
<param index="0" name="velocity" type="float" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.angular_velocity] and its respective setter.
</description>
</method>
<method name="_set_constant_force" qualifiers="virtual">
<return type="void" />
<param index="0" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.set_constant_force].
</description>
</method>
<method name="_set_constant_torque" qualifiers="virtual">
<return type="void" />
<param index="0" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsDirectBodyState2D.set_constant_torque].
</description>
</method>
<method name="_set_linear_velocity" qualifiers="virtual">
<return type="void" />
<param index="0" name="velocity" type="Vector2" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.linear_velocity] and its respective setter.
</description>
</method>
<method name="_set_sleep_state" qualifiers="virtual">
<return type="void" />
<param index="0" name="enabled" type="bool" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.sleeping] and its respective setter.
</description>
</method>
<method name="_set_transform" qualifiers="virtual">
<return type="void" />
<param index="0" name="transform" type="Transform2D" />
<description>
+ Implement to override the behavior of [member PhysicsDirectBodyState2D.transform] and its respective setter.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index 42c65763aa..e8c3f3f89d 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -202,7 +202,7 @@
<method name="integrate_forces">
<return type="void" />
<description>
- Calls the built-in force integration code.
+ Updates the body's linear and angular velocity by applying gravity and damping for the equivalent of one physics tick.
</description>
</method>
<method name="set_constant_force">
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 8be92edbad..d40326fa21 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -501,7 +501,7 @@
<return type="bool" />
<param index="0" name="body" type="RID" />
<description>
- Returns [code]true[/code] if the body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ Returns [code]true[/code] if the body is omitting the standard force integration. See [method body_set_omit_force_integration].
</description>
</method>
<method name="body_remove_collision_exception">
@@ -592,11 +592,12 @@
<param index="1" name="callable" type="Callable" />
<param index="2" name="userdata" type="Variant" default="null" />
<description>
- Sets the function used to calculate physics for the body, if that body allows it (see [method body_set_omit_force_integration]).
- The force integration function takes the following two parameters:
- 1. a [PhysicsDirectBodyState2D] [code]state[/code]: used to retrieve and modify the body's state,
- 2. a [Variant] [param userdata]: optional user data.
- [b]Note:[/b] This callback is currently not called in Godot Physics.
+ Sets the body's custom force integration callback function to [param callable]. Use an empty [Callable] ([code skip-lint]Callable()[/code]) to clear the custom callback.
+ The function [param callable] will be called every physics tick, before the standard force integration (see [method body_set_omit_force_integration]). It can be used for example to update the body's linear and angular velocity based on contact with other bodies.
+ If [param userdata] is not [code]null[/code], the function [param callable] must take the following two parameters:
+ 1. [code]state[/code]: a [PhysicsDirectBodyState2D] used to retrieve and modify the body's state,
+ 2. [code skip-lint]userdata[/code]: a [Variant]; its value will be the [param userdata] passed into this method.
+ If [param userdata] is [code]null[/code], then [param callable] must take only the [code]state[/code] parameter.
</description>
</method>
<method name="body_set_max_contacts_reported">
@@ -620,7 +621,8 @@
<param index="0" name="body" type="RID" />
<param index="1" name="enable" type="bool" />
<description>
- Sets whether the body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ Sets whether the body omits the standard force integration. If [param enable] is [code]true[/code], the body will not automatically use applied forces, torques, and damping to update the body's linear and angular velocity. In this case, [method body_set_force_integration_callback] can be used to manually update the linear and angular velocity instead.
+ This method is called when the property [member RigidBody2D.custom_integrator] is set.
</description>
</method>
<method name="body_set_param">
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index 8d9a171337..815fc742d1 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -17,6 +17,7 @@
<param index="2" name="transform" type="Transform2D" />
<param index="3" name="disabled" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.area_add_shape].
</description>
</method>
<method name="_area_attach_canvas_instance_id" qualifiers="virtual">
@@ -24,6 +25,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="id" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_attach_canvas_instance_id].
</description>
</method>
<method name="_area_attach_object_instance_id" qualifiers="virtual">
@@ -31,41 +33,48 @@
<param index="0" name="area" type="RID" />
<param index="1" name="id" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_attach_object_instance_id].
</description>
</method>
<method name="_area_clear_shapes" qualifiers="virtual">
<return type="void" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_clear_shapes].
</description>
</method>
<method name="_area_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_create].
</description>
</method>
<method name="_area_get_canvas_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_canvas_instance_id].
</description>
</method>
<method name="_area_get_collision_layer" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_collision_layer].
</description>
</method>
<method name="_area_get_collision_mask" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_collision_mask].
</description>
</method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_object_instance_id].
</description>
</method>
<method name="_area_get_param" qualifiers="virtual const">
@@ -73,6 +82,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_param].
</description>
</method>
<method name="_area_get_shape" qualifiers="virtual const">
@@ -80,12 +90,14 @@
<param index="0" name="area" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_shape].
</description>
</method>
<method name="_area_get_shape_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_shape_count].
</description>
</method>
<method name="_area_get_shape_transform" qualifiers="virtual const">
@@ -93,18 +105,21 @@
<param index="0" name="area" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_shape_transform].
</description>
</method>
<method name="_area_get_space" qualifiers="virtual const">
<return type="RID" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_space].
</description>
</method>
<method name="_area_get_transform" qualifiers="virtual const">
<return type="Transform2D" />
<param index="0" name="area" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_get_transform].
</description>
</method>
<method name="_area_remove_shape" qualifiers="virtual">
@@ -112,6 +127,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_remove_shape].
</description>
</method>
<method name="_area_set_area_monitor_callback" qualifiers="virtual">
@@ -119,6 +135,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="callback" type="Callable" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_area_monitor_callback].
</description>
</method>
<method name="_area_set_collision_layer" qualifiers="virtual">
@@ -126,6 +143,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="layer" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_collision_layer].
</description>
</method>
<method name="_area_set_collision_mask" qualifiers="virtual">
@@ -133,6 +151,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="mask" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_collision_mask].
</description>
</method>
<method name="_area_set_monitor_callback" qualifiers="virtual">
@@ -140,6 +159,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="callback" type="Callable" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_monitor_callback].
</description>
</method>
<method name="_area_set_monitorable" qualifiers="virtual">
@@ -147,6 +167,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="monitorable" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_monitorable].
</description>
</method>
<method name="_area_set_param" qualifiers="virtual">
@@ -155,6 +176,7 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
<param index="2" name="value" type="Variant" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_param].
</description>
</method>
<method name="_area_set_pickable" qualifiers="virtual">
@@ -162,6 +184,8 @@
<param index="0" name="area" type="RID" />
<param index="1" name="pickable" type="bool" />
<description>
+ If set to [code]true[/code], allows the area with the given [RID] to detect mouse inputs when the mouse cursor is hovering on it.
+ Overridable version of [PhysicsServer2D]'s internal [code]area_set_pickable[/code] method. Corresponds to [member PhysicsBody2D.input_pickable].
</description>
</method>
<method name="_area_set_shape" qualifiers="virtual">
@@ -170,6 +194,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="shape" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_shape].
</description>
</method>
<method name="_area_set_shape_disabled" qualifiers="virtual">
@@ -178,6 +203,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="disabled" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_shape_disabled].
</description>
</method>
<method name="_area_set_shape_transform" qualifiers="virtual">
@@ -186,6 +212,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="transform" type="Transform2D" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_shape_transform].
</description>
</method>
<method name="_area_set_space" qualifiers="virtual">
@@ -193,6 +220,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="space" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_space].
</description>
</method>
<method name="_area_set_transform" qualifiers="virtual">
@@ -200,6 +228,7 @@
<param index="0" name="area" type="RID" />
<param index="1" name="transform" type="Transform2D" />
<description>
+ Overridable version of [method PhysicsServer2D.area_set_transform].
</description>
</method>
<method name="_body_add_collision_exception" qualifiers="virtual">
@@ -207,6 +236,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="excepted_body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_add_collision_exception].
</description>
</method>
<method name="_body_add_constant_central_force" qualifiers="virtual">
@@ -214,6 +244,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_add_constant_central_force].
</description>
</method>
<method name="_body_add_constant_force" qualifiers="virtual">
@@ -222,6 +253,7 @@
<param index="1" name="force" type="Vector2" />
<param index="2" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_add_constant_force].
</description>
</method>
<method name="_body_add_constant_torque" qualifiers="virtual">
@@ -229,6 +261,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_add_constant_torque].
</description>
</method>
<method name="_body_add_shape" qualifiers="virtual">
@@ -238,6 +271,7 @@
<param index="2" name="transform" type="Transform2D" />
<param index="3" name="disabled" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.body_add_shape].
</description>
</method>
<method name="_body_apply_central_force" qualifiers="virtual">
@@ -245,6 +279,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_central_force].
</description>
</method>
<method name="_body_apply_central_impulse" qualifiers="virtual">
@@ -252,6 +287,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_central_impulse].
</description>
</method>
<method name="_body_apply_force" qualifiers="virtual">
@@ -260,6 +296,7 @@
<param index="1" name="force" type="Vector2" />
<param index="2" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_force].
</description>
</method>
<method name="_body_apply_impulse" qualifiers="virtual">
@@ -268,6 +305,7 @@
<param index="1" name="impulse" type="Vector2" />
<param index="2" name="position" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_impulse].
</description>
</method>
<method name="_body_apply_torque" qualifiers="virtual">
@@ -275,6 +313,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_torque].
</description>
</method>
<method name="_body_apply_torque_impulse" qualifiers="virtual">
@@ -282,6 +321,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_apply_torque_impulse].
</description>
</method>
<method name="_body_attach_canvas_instance_id" qualifiers="virtual">
@@ -289,6 +329,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="id" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_attach_canvas_instance_id].
</description>
</method>
<method name="_body_attach_object_instance_id" qualifiers="virtual">
@@ -296,12 +337,14 @@
<param index="0" name="body" type="RID" />
<param index="1" name="id" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_attach_object_instance_id].
</description>
</method>
<method name="_body_clear_shapes" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_clear_shapes].
</description>
</method>
<method name="_body_collide_shape" qualifiers="virtual">
@@ -315,89 +358,107 @@
<param index="6" name="result_max" type="int" />
<param index="7" name="result_count" type="int32_t*" />
<description>
+ Given a [param body], a [param shape], and their respective parameters, this method should return [code]true[/code] if a collision between the two would occur, with additional details passed in [param results].
+ Overridable version of [PhysicsServer2D]'s internal [code]shape_collide[/code] method. Corresponds to [method PhysicsDirectSpaceState2D.collide_shape].
</description>
</method>
<method name="_body_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_create].
</description>
</method>
<method name="_body_get_canvas_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_canvas_instance_id].
</description>
</method>
<method name="_body_get_collision_exceptions" qualifiers="virtual const">
<return type="RID[]" />
<param index="0" name="body" type="RID" />
<description>
+ Returns the [RID]s of all bodies added as collision exceptions for the given [param body]. See also [method _body_add_collision_exception] and [method _body_remove_collision_exception].
+ Overridable version of [PhysicsServer2D]'s internal [code]body_get_collision_exceptions[/code] method. Corresponds to [method PhysicsBody2D.get_collision_exceptions].
</description>
</method>
<method name="_body_get_collision_layer" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_collision_layer].
</description>
</method>
<method name="_body_get_collision_mask" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_collision_mask].
</description>
</method>
<method name="_body_get_collision_priority" qualifiers="virtual const">
<return type="float" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_collision_priority].
</description>
</method>
<method name="_body_get_constant_force" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_constant_force].
</description>
</method>
<method name="_body_get_constant_torque" qualifiers="virtual const">
<return type="float" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_constant_torque].
</description>
</method>
<method name="_body_get_contacts_reported_depth_threshold" qualifiers="virtual const">
<return type="float" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [PhysicsServer2D]'s internal [code]body_get_contacts_reported_depth_threshold[/code] method.
+ [b]Note:[/b] This method is currently unused by Godot's default physics implementation.
</description>
</method>
<method name="_body_get_continuous_collision_detection_mode" qualifiers="virtual const">
<return type="int" enum="PhysicsServer2D.CCDMode" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_continuous_collision_detection_mode].
</description>
</method>
<method name="_body_get_direct_state" qualifiers="virtual">
<return type="PhysicsDirectBodyState2D" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_direct_state].
</description>
</method>
<method name="_body_get_max_contacts_reported" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_max_contacts_reported].
</description>
</method>
<method name="_body_get_mode" qualifiers="virtual const">
<return type="int" enum="PhysicsServer2D.BodyMode" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_mode].
</description>
</method>
<method name="_body_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_object_instance_id].
</description>
</method>
<method name="_body_get_param" qualifiers="virtual const">
@@ -405,6 +466,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_param].
</description>
</method>
<method name="_body_get_shape" qualifiers="virtual const">
@@ -412,12 +474,14 @@
<param index="0" name="body" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_shape].
</description>
</method>
<method name="_body_get_shape_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_shape_count].
</description>
</method>
<method name="_body_get_shape_transform" qualifiers="virtual const">
@@ -425,12 +489,14 @@
<param index="0" name="body" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_shape_transform].
</description>
</method>
<method name="_body_get_space" qualifiers="virtual const">
<return type="RID" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_space].
</description>
</method>
<method name="_body_get_state" qualifiers="virtual const">
@@ -438,12 +504,14 @@
<param index="0" name="body" type="RID" />
<param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
<description>
+ Overridable version of [method PhysicsServer2D.body_get_state].
</description>
</method>
<method name="_body_is_omitting_force_integration" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_is_omitting_force_integration].
</description>
</method>
<method name="_body_remove_collision_exception" qualifiers="virtual">
@@ -451,6 +519,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="excepted_body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_remove_collision_exception].
</description>
</method>
<method name="_body_remove_shape" qualifiers="virtual">
@@ -458,12 +527,14 @@
<param index="0" name="body" type="RID" />
<param index="1" name="shape_idx" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_remove_shape].
</description>
</method>
<method name="_body_reset_mass_properties" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_reset_mass_properties].
</description>
</method>
<method name="_body_set_axis_velocity" qualifiers="virtual">
@@ -471,6 +542,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="axis_velocity" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_axis_velocity].
</description>
</method>
<method name="_body_set_collision_layer" qualifiers="virtual">
@@ -478,6 +550,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="layer" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_collision_layer].
</description>
</method>
<method name="_body_set_collision_mask" qualifiers="virtual">
@@ -485,6 +558,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="mask" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_collision_mask].
</description>
</method>
<method name="_body_set_collision_priority" qualifiers="virtual">
@@ -492,6 +566,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="priority" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_collision_priority].
</description>
</method>
<method name="_body_set_constant_force" qualifiers="virtual">
@@ -499,6 +574,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector2" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_constant_force].
</description>
</method>
<method name="_body_set_constant_torque" qualifiers="virtual">
@@ -506,6 +582,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="torque" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_constant_torque].
</description>
</method>
<method name="_body_set_contacts_reported_depth_threshold" qualifiers="virtual">
@@ -513,6 +590,8 @@
<param index="0" name="body" type="RID" />
<param index="1" name="threshold" type="float" />
<description>
+ Overridable version of [PhysicsServer2D]'s internal [code]body_set_contacts_reported_depth_threshold[/code] method.
+ [b]Note:[/b] This method is currently unused by Godot's default physics implementation.
</description>
</method>
<method name="_body_set_continuous_collision_detection_mode" qualifiers="virtual">
@@ -520,6 +599,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_continuous_collision_detection_mode].
</description>
</method>
<method name="_body_set_force_integration_callback" qualifiers="virtual">
@@ -528,6 +608,7 @@
<param index="1" name="callable" type="Callable" />
<param index="2" name="userdata" type="Variant" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_force_integration_callback].
</description>
</method>
<method name="_body_set_max_contacts_reported" qualifiers="virtual">
@@ -535,6 +616,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="amount" type="int" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_max_contacts_reported].
</description>
</method>
<method name="_body_set_mode" qualifiers="virtual">
@@ -542,6 +624,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_mode].
</description>
</method>
<method name="_body_set_omit_force_integration" qualifiers="virtual">
@@ -549,6 +632,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="enable" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_omit_force_integration].
</description>
</method>
<method name="_body_set_param" qualifiers="virtual">
@@ -557,6 +641,7 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
<param index="2" name="value" type="Variant" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_param].
</description>
</method>
<method name="_body_set_pickable" qualifiers="virtual">
@@ -564,6 +649,8 @@
<param index="0" name="body" type="RID" />
<param index="1" name="pickable" type="bool" />
<description>
+ If set to [code]true[/code], allows the body with the given [RID] to detect mouse inputs when the mouse cursor is hovering on it.
+ Overridable version of [PhysicsServer2D]'s internal [code]body_set_pickable[/code] method. Corresponds to [member PhysicsBody2D.input_pickable].
</description>
</method>
<method name="_body_set_shape" qualifiers="virtual">
@@ -572,6 +659,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="shape" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_shape].
</description>
</method>
<method name="_body_set_shape_as_one_way_collision" qualifiers="virtual">
@@ -581,6 +669,7 @@
<param index="2" name="enable" type="bool" />
<param index="3" name="margin" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_shape_as_one_way_collision].
</description>
</method>
<method name="_body_set_shape_disabled" qualifiers="virtual">
@@ -589,6 +678,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="disabled" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_shape_disabled].
</description>
</method>
<method name="_body_set_shape_transform" qualifiers="virtual">
@@ -597,6 +687,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="transform" type="Transform2D" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_shape_transform].
</description>
</method>
<method name="_body_set_space" qualifiers="virtual">
@@ -604,6 +695,7 @@
<param index="0" name="body" type="RID" />
<param index="1" name="space" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_space].
</description>
</method>
<method name="_body_set_state" qualifiers="virtual">
@@ -612,6 +704,7 @@
<param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
<param index="2" name="value" type="Variant" />
<description>
+ Overridable version of [method PhysicsServer2D.body_set_state].
</description>
</method>
<method name="_body_set_state_sync_callback" qualifiers="virtual">
@@ -619,6 +712,8 @@
<param index="0" name="body" type="RID" />
<param index="1" name="callable" type="Callable" />
<description>
+ Assigns the [param body] to call the given [param callable] during the synchronization phase of the loop, before [method _step] is called. See also [method _sync].
+ Overridable version of [PhysicsServer2D]'s internal [code]body_set_state_sync_callback[/code] method.
</description>
</method>
<method name="_body_test_motion" qualifiers="virtual const">
@@ -631,26 +726,31 @@
<param index="5" name="recovery_as_collision" type="bool" />
<param index="6" name="result" type="PhysicsServer2DExtensionMotionResult*" />
<description>
+ Overridable version of [method PhysicsServer2D.body_test_motion]. Unlike the exposed implementation, this method does not receive all of the arguments inside a [PhysicsTestMotionParameters2D].
</description>
</method>
<method name="_capsule_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.capsule_shape_create].
</description>
</method>
<method name="_circle_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.circle_shape_create].
</description>
</method>
<method name="_concave_polygon_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.concave_polygon_shape_create].
</description>
</method>
<method name="_convex_polygon_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.convex_polygon_shape_create].
</description>
</method>
<method name="_damped_spring_joint_get_param" qualifiers="virtual const">
@@ -658,6 +758,7 @@
<param index="0" name="joint" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
<description>
+ Overridable version of [method PhysicsServer2D.damped_spring_joint_get_param].
</description>
</method>
<method name="_damped_spring_joint_set_param" qualifiers="virtual">
@@ -666,54 +767,69 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
<param index="2" name="value" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.damped_spring_joint_set_param].
</description>
</method>
<method name="_end_sync" qualifiers="virtual">
<return type="void" />
<description>
+ Called to indicate that the physics server has stopped synchronizing. It is in the loop's iteration/physics phase, and can access physics objects even if running on a separate thread. See also [method _sync].
+ Overridable version of [PhysicsServer2D]'s internal [code]end_sync[/code] method.
</description>
</method>
<method name="_finish" qualifiers="virtual">
<return type="void" />
<description>
+ Called when the main loop finalizes to shut down the physics server. See also [method MainLoop._finalize] and [method _init].
+ Overridable version of [PhysicsServer2D]'s internal [code]finish[/code] method.
</description>
</method>
<method name="_flush_queries" qualifiers="virtual">
<return type="void" />
<description>
+ Called every physics step before [method _step] to process all remaining queries.
+ Overridable version of [PhysicsServer2D]'s internal [code]flush_queries[/code] method.
</description>
</method>
<method name="_free_rid" qualifiers="virtual">
<return type="void" />
<param index="0" name="rid" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.free_rid].
</description>
</method>
<method name="_get_process_info" qualifiers="virtual">
<return type="int" />
<param index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo" />
<description>
+ Overridable version of [method PhysicsServer2D.get_process_info].
</description>
</method>
<method name="_init" qualifiers="virtual">
<return type="void" />
<description>
+ Called when the main loop is initialized and creates a new instance of this physics server. See also [method MainLoop._initialize] and [method _finish].
+ Overridable version of [PhysicsServer2D]'s internal [code]init[/code] method.
</description>
</method>
<method name="_is_flushing_queries" qualifiers="virtual const">
<return type="bool" />
<description>
+ Overridable method that should return [code]true[/code] when the physics server is processing queries. See also [method _flush_queries].
+ Overridable version of [PhysicsServer2D]'s internal [code]is_flushing_queries[/code] method.
</description>
</method>
<method name="_joint_clear" qualifiers="virtual">
<return type="void" />
<param index="0" name="joint" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_clear].
</description>
</method>
<method name="_joint_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_create].
</description>
</method>
<method name="_joint_disable_collisions_between_bodies" qualifiers="virtual">
@@ -721,6 +837,7 @@
<param index="0" name="joint" type="RID" />
<param index="1" name="disable" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_disable_collisions_between_bodies].
</description>
</method>
<method name="_joint_get_param" qualifiers="virtual const">
@@ -728,18 +845,21 @@
<param index="0" name="joint" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_get_param].
</description>
</method>
<method name="_joint_get_type" qualifiers="virtual const">
<return type="int" enum="PhysicsServer2D.JointType" />
<param index="0" name="joint" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_get_type].
</description>
</method>
<method name="_joint_is_disabled_collisions_between_bodies" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="joint" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_is_disabled_collisions_between_bodies].
</description>
</method>
<method name="_joint_make_damped_spring" qualifiers="virtual">
@@ -750,6 +870,7 @@
<param index="3" name="body_a" type="RID" />
<param index="4" name="body_b" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_make_damped_spring].
</description>
</method>
<method name="_joint_make_groove" qualifiers="virtual">
@@ -761,6 +882,7 @@
<param index="4" name="body_a" type="RID" />
<param index="5" name="body_b" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_make_groove].
</description>
</method>
<method name="_joint_make_pin" qualifiers="virtual">
@@ -770,6 +892,7 @@
<param index="2" name="body_a" type="RID" />
<param index="3" name="body_b" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_make_pin].
</description>
</method>
<method name="_joint_set_param" qualifiers="virtual">
@@ -778,6 +901,7 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
<param index="2" name="value" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.joint_set_param].
</description>
</method>
<method name="_pin_joint_get_flag" qualifiers="virtual const">
@@ -785,6 +909,7 @@
<param index="0" name="joint" type="RID" />
<param index="1" name="flag" type="int" enum="PhysicsServer2D.PinJointFlag" />
<description>
+ Overridable version of [method PhysicsServer2D.pin_joint_get_flag].
</description>
</method>
<method name="_pin_joint_get_param" qualifiers="virtual const">
@@ -792,6 +917,7 @@
<param index="0" name="joint" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
<description>
+ Overridable version of [method PhysicsServer2D.pin_joint_get_param].
</description>
</method>
<method name="_pin_joint_set_flag" qualifiers="virtual">
@@ -800,6 +926,7 @@
<param index="1" name="flag" type="int" enum="PhysicsServer2D.PinJointFlag" />
<param index="2" name="enabled" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.pin_joint_set_flag].
</description>
</method>
<method name="_pin_joint_set_param" qualifiers="virtual">
@@ -808,27 +935,32 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
<param index="2" name="value" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.pin_joint_set_param].
</description>
</method>
<method name="_rectangle_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.rectangle_shape_create].
</description>
</method>
<method name="_segment_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.segment_shape_create].
</description>
</method>
<method name="_separation_ray_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.separation_ray_shape_create].
</description>
</method>
<method name="_set_active" qualifiers="virtual">
<return type="void" />
<param index="0" name="active" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.set_active].
</description>
</method>
<method name="_shape_collide" qualifiers="virtual">
@@ -843,24 +975,30 @@
<param index="7" name="result_max" type="int" />
<param index="8" name="result_count" type="int32_t*" />
<description>
+ Given two shapes and their parameters, should return [code]true[/code] if a collision between the two would occur, with additional details passed in [param results].
+ Overridable version of [PhysicsServer2D]'s internal [code]shape_collide[/code] method. Corresponds to [method PhysicsDirectSpaceState2D.collide_shape].
</description>
</method>
<method name="_shape_get_custom_solver_bias" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shape" type="RID" />
<description>
+ Should return the custom solver bias of the given [param shape], which defines how much bodies are forced to separate on contact when this shape is involved.
+ Overridable version of [PhysicsServer2D]'s internal [code]shape_get_custom_solver_bias[/code] method. Corresponds to [member Shape2D.custom_solver_bias].
</description>
</method>
<method name="_shape_get_data" qualifiers="virtual const">
<return type="Variant" />
<param index="0" name="shape" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.shape_get_data].
</description>
</method>
<method name="_shape_get_type" qualifiers="virtual const">
<return type="int" enum="PhysicsServer2D.ShapeType" />
<param index="0" name="shape" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.shape_get_type].
</description>
</method>
<method name="_shape_set_custom_solver_bias" qualifiers="virtual">
@@ -868,6 +1006,8 @@
<param index="0" name="shape" type="RID" />
<param index="1" name="bias" type="float" />
<description>
+ Should set the custom solver bias for the given [param shape]. It defines how much bodies are forced to separate on contact.
+ Overridable version of [PhysicsServer2D]'s internal [code]shape_get_custom_solver_bias[/code] method. Corresponds to [member Shape2D.custom_solver_bias].
</description>
</method>
<method name="_shape_set_data" qualifiers="virtual">
@@ -875,29 +1015,36 @@
<param index="0" name="shape" type="RID" />
<param index="1" name="data" type="Variant" />
<description>
+ Overridable version of [method PhysicsServer2D.shape_set_data].
</description>
</method>
<method name="_space_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.space_create].
</description>
</method>
<method name="_space_get_contact_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="space" type="RID" />
<description>
+ Should return how many contacts have occurred during the last physics step in the given [param space]. See also [method _space_get_contacts] and [method _space_set_debug_contacts].
+ Overridable version of [PhysicsServer2D]'s internal [code]space_get_contact_count[/code] method.
</description>
</method>
<method name="_space_get_contacts" qualifiers="virtual const">
<return type="PackedVector2Array" />
<param index="0" name="space" type="RID" />
<description>
+ Should return the positions of all contacts that have occurred during the last physics step in the given [param space]. See also [method _space_get_contact_count] and [method _space_set_debug_contacts].
+ Overridable version of [PhysicsServer2D]'s internal [code]space_get_contacts[/code] method.
</description>
</method>
<method name="_space_get_direct_state" qualifiers="virtual">
<return type="PhysicsDirectSpaceState2D" />
<param index="0" name="space" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.space_get_direct_state].
</description>
</method>
<method name="_space_get_param" qualifiers="virtual const">
@@ -905,12 +1052,14 @@
<param index="0" name="space" type="RID" />
<param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
<description>
+ Overridable version of [method PhysicsServer2D.space_get_param].
</description>
</method>
<method name="_space_is_active" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="space" type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.space_is_active].
</description>
</method>
<method name="_space_set_active" qualifiers="virtual">
@@ -918,6 +1067,7 @@
<param index="0" name="space" type="RID" />
<param index="1" name="active" type="bool" />
<description>
+ Overridable version of [method PhysicsServer2D.space_set_active].
</description>
</method>
<method name="_space_set_debug_contacts" qualifiers="virtual">
@@ -925,6 +1075,8 @@
<param index="0" name="space" type="RID" />
<param index="1" name="max_contacts" type="int" />
<description>
+ Used internally to allow the given [param space] to store contact points, up to [param max_contacts]. This is automatically set for the main [World2D]'s space when [member SceneTree.debug_collisions_hint] is [code]true[/code], or by checking "Visible Collision Shapes" in the editor. Only works in debug builds.
+ Overridable version of [PhysicsServer2D]'s internal [code]space_set_debug_contacts[/code] method.
</description>
</method>
<method name="_space_set_param" qualifiers="virtual">
@@ -933,34 +1085,42 @@
<param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
<param index="2" name="value" type="float" />
<description>
+ Overridable version of [method PhysicsServer2D.space_set_param].
</description>
</method>
<method name="_step" qualifiers="virtual">
<return type="void" />
<param index="0" name="step" type="float" />
<description>
+ Called every physics step to process the physics simulation. [param step] is the time elapsed since the last physics step, in seconds. It is usually the same as [method Node.get_physics_process_delta_time].
+ Overridable version of [PhysicsServer2D]'s internal [code skip-lint]step[/code] method.
</description>
</method>
<method name="_sync" qualifiers="virtual">
<return type="void" />
<description>
+ Called to indicate that the physics server is synchronizing and cannot access physics states if running on a separate thread. See also [method _end_sync].
+ Overridable version of [PhysicsServer2D]'s internal [code]sync[/code] method.
</description>
</method>
<method name="_world_boundary_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
+ Overridable version of [method PhysicsServer2D.world_boundary_shape_create].
</description>
</method>
<method name="body_test_motion_is_excluding_body" qualifiers="const">
<return type="bool" />
<param index="0" name="body" type="RID" />
<description>
+ Returns [code]true[/code] if the body with the given [RID] is being excluded from [method _body_test_motion]. See also [method Object.get_instance_id].
</description>
</method>
<method name="body_test_motion_is_excluding_object" qualifiers="const">
<return type="bool" />
<param index="0" name="object" type="int" />
<description>
+ Returns [code]true[/code] if the object with the given instance ID is being excluded from [method _body_test_motion]. See also [method Object.get_instance_id].
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index e40d73862b..7dcb185834 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -482,7 +482,7 @@
<return type="bool" />
<param index="0" name="body" type="RID" />
<description>
- Returns whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ Returns [code]true[/code] if the body is omitting the standard force integration. See [method body_set_omit_force_integration].
</description>
</method>
<method name="body_remove_collision_exception">
@@ -582,9 +582,12 @@
<param index="1" name="callable" type="Callable" />
<param index="2" name="userdata" type="Variant" default="null" />
<description>
- Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]). The force integration function takes 2 arguments:
- - [code]state[/code] — [PhysicsDirectBodyState3D] used to retrieve and modify the body's state.
- - [code skip-lint]userdata[/code] — optional user data passed to [method body_set_force_integration_callback].
+ Sets the body's custom force integration callback function to [param callable]. Use an empty [Callable] ([code skip-lint]Callable()[/code]) to clear the custom callback.
+ The function [param callable] will be called every physics tick, before the standard force integration (see [method body_set_omit_force_integration]). It can be used for example to update the body's linear and angular velocity based on contact with other bodies.
+ If [param userdata] is not [code]null[/code], the function [param callable] must take the following two parameters:
+ 1. [code]state[/code]: a [PhysicsDirectBodyState3D], used to retrieve and modify the body's state,
+ 2. [code skip-lint]userdata[/code]: a [Variant]; its value will be the [param userdata] passed into this method.
+ If [param userdata] is [code]null[/code], then [param callable] must take only the [code]state[/code] parameter.
</description>
</method>
<method name="body_set_max_contacts_reported">
@@ -608,7 +611,8 @@
<param index="0" name="body" type="RID" />
<param index="1" name="enable" type="bool" />
<description>
- Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ Sets whether the body omits the standard force integration. If [param enable] is [code]true[/code], the body will not automatically use applied forces, torques, and damping to update the body's linear and angular velocity. In this case, [method body_set_force_integration_callback] can be used to manually update the linear and angular velocity instead.
+ This method is called when the property [member RigidBody3D.custom_integrator] is set.
</description>
</method>
<method name="body_set_param">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4d3e838bb1..bc06cc18a7 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -323,6 +323,11 @@
If [code]true[/code], disables printing to standard output. This is equivalent to starting the editor or project with the [code]--quiet[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. See also [member application/run/disable_stderr].
Changes to this setting will only be applied upon restarting the application.
</member>
+ <member name="application/run/enable_alt_space_menu" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], allows the [kbd]Alt + Space[/kbd] keys to display the window menu. This menu allows the user to perform various window management operations such as moving, resizing, or minimizing the window.
+ [b]Note:[/b] When the menu is displayed, project execution will pause until the menu is [i]fully[/i] closed due to Windows behavior. Consider this when enabling this setting in a networked multiplayer game. The menu is only considered fully closed when an option is selected, when the user clicks outside, or when [kbd]Escape[/kbd] is pressed after bringing up the window menu [i]and[/i] another key is pressed afterwards.
+ [b]Note:[/b] This setting is implemented only on Windows.
+ </member>
<member name="application/run/flush_stdout_on_print" type="bool" setter="" getter="" default="false">
If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging.
When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally").
@@ -2727,6 +2732,10 @@
<member name="rendering/rendering_device/driver.windows" type="String" setter="" getter="">
Windows override for [member rendering/rendering_device/driver].
</member>
+ <member name="rendering/rendering_device/pipeline_cache/enable" type="bool" setter="" getter="" default="true">
+ Enable the pipeline cache that is saved to disk if the graphics API supports it.
+ [b]Note:[/b] This property is unable to control the pipeline caching the GPU driver itself does. Only turn this off along with deleting the contents of the driver's cache if you wish to simulate the experience a user will get when starting the game for the first time.
+ </member>
<member name="rendering/rendering_device/pipeline_cache/save_chunk_size_mb" type="float" setter="" getter="" default="3.0">
Determines at which interval pipeline cache is saved to disk. The lower the value, the more often it is saved.
</member>
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index 31daaab417..16643b0a71 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -56,6 +56,21 @@
<return type="int" />
<description>
Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ To get the intersected shape node, for a [CollisionObject2D] target, use:
+ [codeblocks]
+ [gdscript]
+ var target = get_collider() # A CollisionObject2D.
+ var shape_id = get_collider_shape() # The shape index in the collider.
+ var owner_id = target.shape_find_owner(shape_id) # The owner ID in the collider.
+ var shape = target.shape_owner_get_owner(owner_id)
+ [/gdscript]
+ [csharp]
+ var target = (CollisionObject2D)GetCollider(); // A CollisionObject2D.
+ var shapeId = GetColliderShape(); // The shape index in the collider.
+ var ownerId = target.ShapeFindOwner(shapeId); // The owner ID in the collider.
+ var shape = target.ShapeOwnerGetOwner(ownerId);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index f9f94e5cfc..6a4c40d227 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -57,6 +57,21 @@
<return type="int" />
<description>
Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ To get the intersected shape node, for a [CollisionObject3D] target, use:
+ [codeblocks]
+ [gdscript]
+ var target = get_collider() # A CollisionObject3D.
+ var shape_id = get_collider_shape() # The shape index in the collider.
+ var owner_id = target.shape_find_owner(shape_id) # The owner ID in the collider.
+ var shape = target.shape_owner_get_owner(owner_id)
+ [/gdscript]
+ [csharp]
+ var target = (CollisionObject3D)GetCollider(); // A CollisionObject3D.
+ var shapeId = GetColliderShape(); // The shape index in the collider.
+ var ownerId = target.ShapeFindOwner(shapeId); // The owner ID in the collider.
+ var shape = target.ShapeOwnerGetOwner(ownerId);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_collision_face_index" qualifiers="const">
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 33cd831175..36abde36b4 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -2129,8 +2129,10 @@
Represents the size of the [enum BlendOperation] enum.
</constant>
<constant name="DYNAMIC_STATE_LINE_WIDTH" value="1" enum="PipelineDynamicStateFlags" is_bitfield="true">
+ Allows dynamically changing the width of rendering lines.
</constant>
<constant name="DYNAMIC_STATE_DEPTH_BIAS" value="2" enum="PipelineDynamicStateFlags" is_bitfield="true">
+ Allows dynamically changing the depth bias.
</constant>
<constant name="DYNAMIC_STATE_BLEND_CONSTANTS" value="4" enum="PipelineDynamicStateFlags" is_bitfield="true">
</constant>
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index 95fbee4a24..9cfc2c532d 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -79,6 +79,7 @@
Returns an empty resource if no [ResourceFormatLoader] could handle the file.
GDScript has a simplified [method @GDScript.load] built-in method which can be used in most situations, leaving the use of [ResourceLoader] for more advanced scenarios.
[b]Note:[/b] If [member ProjectSettings.editor/export/convert_text_resources_to_binary] is [code]true[/code], [method @GDScript.load] will not be able to read converted files in an exported project. If you rely on run-time loading of files present within the PCK, set [member ProjectSettings.editor/export/convert_text_resources_to_binary] to [code]false[/code].
+ [b]Note:[/b] Relative paths will be prefixed with [code]"res://"[/code] before loading, to avoid unexpected results make sure your paths are absolute.
</description>
</method>
<method name="load_threaded_get">
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 269ead1298..e16c83f871 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -19,7 +19,7 @@
<return type="void" />
<param index="0" name="state" type="PhysicsDirectBodyState2D" />
<description>
- Allows you to read and safely modify the simulation state for the object. Use this instead of [method Node._physics_process] if you need to directly change the body's [code]position[/code] or other physics properties. By default, it works in addition to the usual physics behavior, but [member custom_integrator] allows you to disable the default behavior and write custom force integration for a body.
+ Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it is called before the standard force integration, but the [member custom_integrator] property allows you to disable the standard force integration and do fully custom force integration for a body.
</description>
</method>
<method name="add_constant_central_force">
@@ -159,7 +159,8 @@
Continuous collision detection tries to predict where a moving body will collide instead of moving it and correcting its movement after collision. Continuous collision detection is slower, but more precise and misses fewer collisions with small, fast-moving objects. Raycasting and shapecasting methods are available. See [enum CCDMode] for details.
</member>
<member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false">
- If [code]true[/code], internal force integration is disabled for this body. Aside from collision response, the body will only move as determined by the [method _integrate_forces] function.
+ If [code]true[/code], the standard force integration (like gravity or damping) will be disabled for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] method, if that virtual method is overridden.
+ Setting this property will call the method [method PhysicsServer2D.body_set_omit_force_integration] internally.
</member>
<member name="freeze" type="bool" setter="set_freeze_enabled" getter="is_freeze_enabled" default="false">
If [code]true[/code], the body is frozen. Gravity and forces are not applied anymore.
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index c507a7c39a..715509a30e 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -20,7 +20,7 @@
<return type="void" />
<param index="0" name="state" type="PhysicsDirectBodyState3D" />
<description>
- Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
+ Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it is called before the standard force integration, but the [member custom_integrator] property allows you to disable the standard force integration and do fully custom force integration for a body.
</description>
</method>
<method name="add_constant_central_force">
@@ -166,7 +166,8 @@
Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided. Continuous collision detection is more precise, and misses fewer impacts by small, fast-moving objects. Not using continuous collision detection is faster to compute, but can miss small, fast-moving objects.
</member>
<member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false">
- If [code]true[/code], internal force integration will be disabled (like gravity or air friction) for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] function, if defined.
+ If [code]true[/code], the standard force integration (like gravity or damping) will be disabled for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] method, if that virtual method is overridden.
+ Setting this property will call the method [method PhysicsServer3D.body_set_omit_force_integration] internally.
</member>
<member name="freeze" type="bool" setter="set_freeze_enabled" getter="is_freeze_enabled" default="false">
If [code]true[/code], the body is frozen. Gravity and forces are not applied anymore.
diff --git a/doc/classes/ShapeCast2D.xml b/doc/classes/ShapeCast2D.xml
index d71c9ce13a..576bd62cc3 100644
--- a/doc/classes/ShapeCast2D.xml
+++ b/doc/classes/ShapeCast2D.xml
@@ -48,6 +48,7 @@
<return type="float" />
<description>
The fraction from the [ShapeCast2D]'s origin to its [member target_position] (between 0 and 1) of how far the shape must move to trigger a collision.
+ In ideal conditions this would be the same as [method get_closest_collision_safe_fraction], however shape casting is calculated in discrete steps, so the precise point of collision can occur between two calculated positions.
</description>
</method>
<method name="get_collider" qualifiers="const">
diff --git a/doc/classes/ShapeCast3D.xml b/doc/classes/ShapeCast3D.xml
index ff057e8c70..2c6efe2ebe 100644
--- a/doc/classes/ShapeCast3D.xml
+++ b/doc/classes/ShapeCast3D.xml
@@ -48,6 +48,7 @@
<return type="float" />
<description>
The fraction from the [ShapeCast3D]'s origin to its [member target_position] (between 0 and 1) of how far the shape must move to trigger a collision.
+ In ideal conditions this would be the same as [method get_closest_collision_safe_fraction], however shape casting is calculated in discrete steps, so the precise point of collision can occur between two calculated positions.
</description>
</method>
<method name="get_collider" qualifiers="const">
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 3ed29668e4..b5bb4e3639 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -83,6 +83,14 @@
Returns the texture of the group at [param group_idx] that will be the drawing group background image in the [BoneMap] editor.
</description>
</method>
+ <method name="is_required" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="bone_idx" type="int" />
+ <description>
+ Returns whether the bone at [param bone_idx] is required for retargeting.
+ This value is used by the bone map editor. If this method returns [code]true[/code], and no bone is assigned, the handle color will be red on the bone map editor.
+ </description>
+ </method>
<method name="set_bone_name">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -141,6 +149,14 @@
Sets the reference pose transform for bone [param bone_idx].
</description>
</method>
+ <method name="set_required">
+ <return type="void" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="required" type="bool" />
+ <description>
+ Sets the required status for bone [param bone_idx] to [param required].
+ </description>
+ </method>
<method name="set_tail_direction">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml
index 49b362041b..8930514492 100644
--- a/doc/classes/SliderJoint3D.xml
+++ b/doc/classes/SliderJoint3D.xml
@@ -13,6 +13,7 @@
<return type="float" />
<param index="0" name="param" type="int" enum="SliderJoint3D.Param" />
<description>
+ Returns the value of the given parameter (see [enum Param] constants).
</description>
</method>
<method name="set_param">
@@ -20,6 +21,7 @@
<param index="0" name="param" type="int" enum="SliderJoint3D.Param" />
<param index="1" name="value" type="float" />
<description>
+ Assigns [param value] to the given parameter (see [enum Param] constants).
</description>
</method>
</methods>
@@ -96,70 +98,70 @@
</members>
<constants>
<constant name="PARAM_LINEAR_LIMIT_UPPER" value="0" enum="Param">
- The maximum difference between the pivot points on their X axis before damping happens.
+ Constant for accessing [member linear_limit/upper_distance]. The maximum difference between the pivot points on their X axis before damping happens.
</constant>
<constant name="PARAM_LINEAR_LIMIT_LOWER" value="1" enum="Param">
- The minimum difference between the pivot points on their X axis before damping happens.
+ Constant for accessing [member linear_limit/lower_distance]. The minimum difference between the pivot points on their X axis before damping happens.
</constant>
<constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2" enum="Param">
- A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
+ Constant for accessing [member linear_limit/softness]. A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
</constant>
<constant name="PARAM_LINEAR_LIMIT_RESTITUTION" value="3" enum="Param">
- The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
+ Constant for accessing [member linear_limit/restitution]. The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
</constant>
<constant name="PARAM_LINEAR_LIMIT_DAMPING" value="4" enum="Param">
- The amount of damping once the slider limits are surpassed.
+ Constant for accessing [member linear_limit/damping]. The amount of damping once the slider limits are surpassed.
</constant>
<constant name="PARAM_LINEAR_MOTION_SOFTNESS" value="5" enum="Param">
- A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
+ Constant for accessing [member linear_motion/softness]. A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
</constant>
<constant name="PARAM_LINEAR_MOTION_RESTITUTION" value="6" enum="Param">
- The amount of restitution inside the slider limits.
+ Constant for accessing [member linear_motion/restitution]. The amount of restitution inside the slider limits.
</constant>
<constant name="PARAM_LINEAR_MOTION_DAMPING" value="7" enum="Param">
- The amount of damping inside the slider limits.
+ Constant for accessing [member linear_motion/damping]. The amount of damping inside the slider limits.
</constant>
<constant name="PARAM_LINEAR_ORTHOGONAL_SOFTNESS" value="8" enum="Param">
- A factor applied to the movement across axes orthogonal to the slider.
+ Constant for accessing [member linear_ortho/softness]. A factor applied to the movement across axes orthogonal to the slider.
</constant>
<constant name="PARAM_LINEAR_ORTHOGONAL_RESTITUTION" value="9" enum="Param">
- The amount of restitution when movement is across axes orthogonal to the slider.
+ Constant for accessing [member linear_motion/restitution]. The amount of restitution when movement is across axes orthogonal to the slider.
</constant>
<constant name="PARAM_LINEAR_ORTHOGONAL_DAMPING" value="10" enum="Param">
- The amount of damping when movement is across axes orthogonal to the slider.
+ Constant for accessing [member linear_motion/damping]. The amount of damping when movement is across axes orthogonal to the slider.
</constant>
<constant name="PARAM_ANGULAR_LIMIT_UPPER" value="11" enum="Param">
- The upper limit of rotation in the slider.
+ Constant for accessing [member angular_limit/upper_angle]. The upper limit of rotation in the slider.
</constant>
<constant name="PARAM_ANGULAR_LIMIT_LOWER" value="12" enum="Param">
- The lower limit of rotation in the slider.
+ Constant for accessing [member angular_limit/lower_angle]. The lower limit of rotation in the slider.
</constant>
<constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="13" enum="Param">
- A factor applied to the all rotation once the limit is surpassed.
+ Constant for accessing [member angular_limit/softness]. A factor applied to the all rotation once the limit is surpassed.
</constant>
<constant name="PARAM_ANGULAR_LIMIT_RESTITUTION" value="14" enum="Param">
- The amount of restitution of the rotation when the limit is surpassed.
+ Constant for accessing [member angular_limit/restitution]. The amount of restitution of the rotation when the limit is surpassed.
</constant>
<constant name="PARAM_ANGULAR_LIMIT_DAMPING" value="15" enum="Param">
- The amount of damping of the rotation when the limit is surpassed.
+ Constant for accessing [member angular_limit/damping]. The amount of damping of the rotation when the limit is surpassed.
</constant>
<constant name="PARAM_ANGULAR_MOTION_SOFTNESS" value="16" enum="Param">
- A factor applied to the all rotation in the limits.
+ Constant for accessing [member angular_motion/softness]. A factor applied to the all rotation in the limits.
</constant>
<constant name="PARAM_ANGULAR_MOTION_RESTITUTION" value="17" enum="Param">
- The amount of restitution of the rotation in the limits.
+ Constant for accessing [member angular_motion/restitution]. The amount of restitution of the rotation in the limits.
</constant>
<constant name="PARAM_ANGULAR_MOTION_DAMPING" value="18" enum="Param">
- The amount of damping of the rotation in the limits.
+ Constant for accessing [member angular_motion/damping]. The amount of damping of the rotation in the limits.
</constant>
<constant name="PARAM_ANGULAR_ORTHOGONAL_SOFTNESS" value="19" enum="Param">
- A factor applied to the all rotation across axes orthogonal to the slider.
+ Constant for accessing [member angular_ortho/softness]. A factor applied to the all rotation across axes orthogonal to the slider.
</constant>
<constant name="PARAM_ANGULAR_ORTHOGONAL_RESTITUTION" value="20" enum="Param">
- The amount of restitution of the rotation across axes orthogonal to the slider.
+ Constant for accessing [member angular_ortho/restitution]. The amount of restitution of the rotation across axes orthogonal to the slider.
</constant>
<constant name="PARAM_ANGULAR_ORTHOGONAL_DAMPING" value="21" enum="Param">
- The amount of damping of the rotation across axes orthogonal to the slider.
+ Constant for accessing [member angular_ortho/damping]. The amount of damping of the rotation across axes orthogonal to the slider.
</constant>
<constant name="PARAM_MAX" value="22" enum="Param">
Represents the size of the [enum Param] enum.
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 7592342602..a33a1aea41 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -255,6 +255,13 @@
print("User {id} is {name}.".format([["id", 42], ["name", "Godot"]]))
[/codeblock]
See also the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format string[/url] tutorial.
+ [b]Note:[/b] The replacement of placeholders is not done all at once, instead each placeholder is replaced in the order they are passed, this means that if one of the replacement strings contains a key it will also be replaced. This can be very powerful, but can also cause unexpected results if you are not careful. If you do not need to perform replacement in the replacement strings, make sure your replacements do not contain placeholders to ensure reliable results.
+ [codeblock]
+ print("{0} {1}".format(["{1}", "x"])) # Prints "x x".
+ print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}".
+ print("{foo} {bar}".format({"foo": "{bar}", "bar": "baz"})) # Prints "baz baz".
+ print("{foo} {bar}".format({"bar": "baz", "foo": "{bar}"})) # Prints "{bar} baz".
+ [/codeblock]
[b]Note:[/b] In C#, it's recommended to [url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated]interpolate strings with "$"[/url], instead.
</description>
</method>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index cd70316aa9..c0cd7f79e7 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1736,6 +1736,16 @@
[b]Note:[/b] The result may be longer or shorter than the original.
</description>
</method>
+ <method name="string_to_title" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
+ <description>
+ Returns the string converted to title case.
+ [b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]).
+ [b]Note:[/b] The result may be longer or shorter than the original.
+ </description>
+ </method>
<method name="string_to_upper" qualifiers="const">
<return type="String" />
<param index="0" name="string" type="String" />
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 9b7fc42ddf..06a0daece6 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -1913,6 +1913,15 @@
Returns the string converted to lowercase.
</description>
</method>
+ <method name="_string_to_title" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
+ <description>
+ [b]Optional.[/b]
+ Returns the string converted to title case.
+ </description>
+ </method>
<method name="_string_to_upper" qualifiers="virtual const">
<return type="String" />
<param index="0" name="string" type="String" />
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 3d36eafb08..e197f7748c 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -112,7 +112,8 @@
<return type="void" />
<param index="0" name="object" type="Object" />
<description>
- Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources.
+ Register a reference to an object that will be erased if the "do" history is deleted. This is useful for objects added by the "do" action and removed by the "undo" action.
+ When the "do" history is deleted, if the object is a [RefCounted], it will be unreferenced. Otherwise, it will be freed. Do not use for resources.
[codeblock]
var node = Node2D.new()
undo_redo.create_action("Add node")
@@ -143,7 +144,8 @@
<return type="void" />
<param index="0" name="object" type="Object" />
<description>
- Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!).
+ Register a reference to an object that will be erased if the "undo" history is deleted. This is useful for objects added by the "undo" action and removed by the "do" action.
+ When the "undo" history is deleted, if the object is a [RefCounted], it will be unreferenced. Otherwise, it will be freed. Do not use for resources.
[codeblock]
var node = $Node2D
undo_redo.create_action("Remove node")
@@ -272,10 +274,10 @@
Makes "do"/"undo" operations stay in separate actions.
</constant>
<constant name="MERGE_ENDS" value="1" enum="MergeMode">
- Makes so that the action's "undo" operations are from the first action created and the "do" operations are from the last subsequent action with the same name.
+ Merges this action with the previous one if they have the same name. Keeps only the first action's "undo" operations and the last action's "do" operations. Useful for sequential changes to a single value.
</constant>
<constant name="MERGE_ALL" value="2" enum="MergeMode">
- Makes subsequent actions with the same name be merged into one.
+ Merges this action with the previous one if they have the same name.
</constant>
</constants>
</class>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index f33076a92f..03a7a9a98f 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -132,7 +132,7 @@
<param index="0" name="with" type="Vector2" />
<description>
Returns the 2D analog of the cross product for this vector and [param with].
- This is the signed area of the parallelogram formed by the two vectors. If the second vector is clockwise from the first vector, then the cross product is the positive area. If counter-clockwise, the cross product is the negative area.
+ This is the signed area of the parallelogram formed by the two vectors. If the second vector is clockwise from the first vector, then the cross product is the positive area. If counter-clockwise, the cross product is the negative area. If the two vectors are parallel this returns zero, making it useful for testing if two vectors are parallel.
[b]Note:[/b] Cross product is not defined in 2D mathematically. This method embeds the 2D vectors in the XY plane of 3D space and uses their cross product's Z component as the analog.
</description>
</method>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 872534fd89..ba6aa6872a 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -108,6 +108,7 @@
<param index="0" name="with" type="Vector3" />
<description>
Returns the cross product of this vector and [param with].
+ This returns a vector perpendicular to both this and [param with], which would be the normal vector of the plane defined by the two vectors. As there are two such vectors, in opposite directions, this method returns the vector defined by a right-handed coordinate system. If the two vectors are parallel this returns an empty vector, making it useful for testing if two vectors are parallel.
</description>
</method>
<method name="cubic_interpolate" qualifiers="const">
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index dcc817427b..8626e12a69 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -347,12 +347,17 @@
Sets the screen-space antialiasing method used. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry.
</member>
<member name="sdf_oversize" type="int" setter="set_sdf_oversize" getter="get_sdf_oversize" enum="Viewport.SDFOversize" default="1">
+ Controls how much of the original viewport's size should be covered by the 2D signed distance field. This SDF can be sampled in [CanvasItem] shaders and is also used for [GPUParticles2D] collision. Higher values allow portions of occluders located outside the viewport to still be taken into account in the generated signed distance field, at the cost of performance. If you notice particles falling through [LightOccluder2D]s as the occluders leave the viewport, increase this setting.
+ The percentage is added on each axis and on both sides. For example, with the default [constant SDF_OVERSIZE_120_PERCENT], the signed distance field will cover 20% of the viewport's size outside the viewport on each side (top, right, bottom, left).
</member>
<member name="sdf_scale" type="int" setter="set_sdf_scale" getter="get_sdf_scale" enum="Viewport.SDFScale" default="1">
+ The resolution scale to use for the 2D signed distance field. Higher values lead to a more precise and more stable signed distance field as the camera moves, at the cost of performance.
</member>
<member name="snap_2d_transforms_to_pixel" type="bool" setter="set_snap_2d_transforms_to_pixel" getter="is_snap_2d_transforms_to_pixel_enabled" default="false">
+ If [code]true[/code], [CanvasItem] nodes will internally snap to full pixels. Their position can still be sub-pixel, but the decimals will not have effect. This can lead to a crisper appearance at the cost of less smooth movement, especially when [Camera2D] smoothing is enabled.
</member>
<member name="snap_2d_vertices_to_pixel" type="bool" setter="set_snap_2d_vertices_to_pixel" getter="is_snap_2d_vertices_to_pixel_enabled" default="false">
+ If [code]true[/code], vertices of [CanvasItem] nodes will snap to full pixels. Only affects the final vertex positions, not the transforms. This can lead to a crisper appearance at the cost of less smooth movement, especially when [Camera2D] smoothing is enabled.
</member>
<member name="texture_mipmap_bias" type="float" setter="set_texture_mipmap_bias" getter="get_texture_mipmap_bias" default="0.0">
Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close).
@@ -515,14 +520,16 @@
Objects are displayed without light information.
</constant>
<constant name="DEBUG_DRAW_LIGHTING" value="2" enum="DebugDraw">
+ Objects are displayed without textures and only with lighting information.
</constant>
<constant name="DEBUG_DRAW_OVERDRAW" value="3" enum="DebugDraw">
Objects are displayed semi-transparent with additive blending so you can see where they are drawing over top of one another. A higher overdraw means you are wasting performance on drawing pixels that are being hidden behind others.
</constant>
<constant name="DEBUG_DRAW_WIREFRAME" value="4" enum="DebugDraw">
- Objects are displayed in wireframe style.
+ Objects are displayed as wireframe models.
</constant>
<constant name="DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="DebugDraw">
+ Objects are displayed without lighting information and their textures replaced by normal mapping.
</constant>
<constant name="DEBUG_DRAW_VOXEL_GI_ALBEDO" value="6" enum="DebugDraw">
Objects are displayed with only the albedo value from [VoxelGI]s.
@@ -540,6 +547,7 @@
Draws the shadow atlas that stores shadows from [DirectionalLight3D]s in the upper left quadrant of the [Viewport].
</constant>
<constant name="DEBUG_DRAW_SCENE_LUMINANCE" value="11" enum="DebugDraw">
+ Draws the scene luminance buffer (if available) in the upper left quadrant of the [Viewport].
</constant>
<constant name="DEBUG_DRAW_SSAO" value="12" enum="DebugDraw">
Draws the screen-space ambient occlusion texture instead of the scene so that you can clearly see how it is affecting objects. In order for this display mode to work, you must have [member Environment.ssao_enabled] set in your [WorldEnvironment].
@@ -554,24 +562,36 @@
Draws the decal atlas used by [Decal]s and light projector textures in the upper left quadrant of the [Viewport].
</constant>
<constant name="DEBUG_DRAW_SDFGI" value="16" enum="DebugDraw">
+ Draws the cascades used to render signed distance field global illumination (SDFGI).
+ Does nothing if the current environment's [member Environment.sdfgi_enabled] is [code]false[/code] or SDFGI is not supported on the platform.
</constant>
<constant name="DEBUG_DRAW_SDFGI_PROBES" value="17" enum="DebugDraw">
+ Draws the probes used for signed distance field global illumination (SDFGI).
+ Does nothing if the current environment's [member Environment.sdfgi_enabled] is [code]false[/code] or SDFGI is not supported on the platform.
</constant>
<constant name="DEBUG_DRAW_GI_BUFFER" value="18" enum="DebugDraw">
+ Draws the buffer used for global illumination (GI).
</constant>
<constant name="DEBUG_DRAW_DISABLE_LOD" value="19" enum="DebugDraw">
+ Draws all of the objects at their highest polycount, without low level of detail (LOD).
</constant>
<constant name="DEBUG_DRAW_CLUSTER_OMNI_LIGHTS" value="20" enum="DebugDraw">
+ Draws the cluster used by [OmniLight3D] nodes to optimize light rendering.
</constant>
<constant name="DEBUG_DRAW_CLUSTER_SPOT_LIGHTS" value="21" enum="DebugDraw">
+ Draws the cluster used by [SpotLight3D] nodes to optimize light rendering.
</constant>
<constant name="DEBUG_DRAW_CLUSTER_DECALS" value="22" enum="DebugDraw">
+ Draws the cluster used by [Decal] nodes to optimize decal rendering.
</constant>
<constant name="DEBUG_DRAW_CLUSTER_REFLECTION_PROBES" value="23" enum="DebugDraw">
+ Draws the cluster used by [ReflectionProbe] nodes to optimize decal rendering.
</constant>
<constant name="DEBUG_DRAW_OCCLUDERS" value="24" enum="DebugDraw">
+ Draws the buffer used for occlusion culling.
</constant>
<constant name="DEBUG_DRAW_MOTION_VECTORS" value="25" enum="DebugDraw">
+ Draws vector lines over the viewport to indicate the movement of pixels between frames.
</constant>
<constant name="DEBUG_DRAW_INTERNAL_BUFFER" value="26" enum="DebugDraw">
Draws the internal resolution buffer of the scene before post-processing is applied.
@@ -591,7 +611,7 @@
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX" value="4" enum="DefaultCanvasItemTextureFilter">
- Max value for [enum DefaultCanvasItemTextureFilter] enum.
+ Represents the size of the [enum DefaultCanvasItemTextureFilter] enum.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED" value="0" enum="DefaultCanvasItemTextureRepeat">
Disables textures repeating. Instead, when reading UVs outside the 0-1 range, the value will be clamped to the edge of the texture, resulting in a stretched out look at the borders of the texture.
@@ -603,34 +623,43 @@
Flip the texture when repeating so that the edge lines up instead of abruptly changing.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX" value="3" enum="DefaultCanvasItemTextureRepeat">
- Max value for [enum DefaultCanvasItemTextureRepeat] enum.
+ Represents the size of the [enum DefaultCanvasItemTextureRepeat] enum.
</constant>
<constant name="SDF_OVERSIZE_100_PERCENT" value="0" enum="SDFOversize">
+ The signed distance field only covers the viewport's own rectangle.
</constant>
<constant name="SDF_OVERSIZE_120_PERCENT" value="1" enum="SDFOversize">
+ The signed distance field is expanded to cover 20% of the viewport's size around the borders.
</constant>
<constant name="SDF_OVERSIZE_150_PERCENT" value="2" enum="SDFOversize">
+ The signed distance field is expanded to cover 50% of the viewport's size around the borders.
</constant>
<constant name="SDF_OVERSIZE_200_PERCENT" value="3" enum="SDFOversize">
+ The signed distance field is expanded to cover 100% (double) of the viewport's size around the borders.
</constant>
<constant name="SDF_OVERSIZE_MAX" value="4" enum="SDFOversize">
+ Represents the size of the [enum SDFOversize] enum.
</constant>
<constant name="SDF_SCALE_100_PERCENT" value="0" enum="SDFScale">
+ The signed distance field is rendered at full resolution.
</constant>
<constant name="SDF_SCALE_50_PERCENT" value="1" enum="SDFScale">
+ The signed distance field is rendered at half the resolution of this viewport.
</constant>
<constant name="SDF_SCALE_25_PERCENT" value="2" enum="SDFScale">
+ The signed distance field is rendered at a quarter the resolution of this viewport.
</constant>
<constant name="SDF_SCALE_MAX" value="3" enum="SDFScale">
+ Represents the size of the [enum SDFScale] enum.
</constant>
<constant name="VRS_DISABLED" value="0" enum="VRSMode">
- VRS is disabled.
+ Variable Rate Shading is disabled.
</constant>
<constant name="VRS_TEXTURE" value="1" enum="VRSMode">
- VRS uses a texture. Note, for stereoscopic use a texture atlas with a texture for each view.
+ Variable Rate Shading uses a texture. Note, for stereoscopic use a texture atlas with a texture for each view.
</constant>
<constant name="VRS_XR" value="2" enum="VRSMode">
- VRS texture is supplied by the primary [XRInterface].
+ Variable Rate Shading's texture is supplied by the primary [XRInterface].
</constant>
<constant name="VRS_MAX" value="3" enum="VRSMode">
Represents the size of the [enum VRSMode] enum.
diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml
index e12933d64b..245cc37267 100644
--- a/doc/classes/ViewportTexture.xml
+++ b/doc/classes/ViewportTexture.xml
@@ -4,9 +4,10 @@
Provides the content of a [Viewport] as a dynamic texture.
</brief_description>
<description>
- Provides the content of a [Viewport] as a dynamic [Texture2D]. This can be used to mix controls, 2D game objects, and 3D game objects in the same scene.
- To create a [ViewportTexture] in code, use the [method Viewport.get_texture] method on the target viewport.
+ A [ViewportTexture] provides the content of a [Viewport] as a dynamic [Texture2D]. This can be used to combine the rendering of [Control], [Node2D] and [Node3D] nodes. For example, you can use this texture to display a 3D scene inside a [TextureRect], or a 2D overlay in a [Sprite3D].
+ To get a [ViewportTexture] in code, use the [method Viewport.get_texture] method on the target viewport.
[b]Note:[/b] A [ViewportTexture] is always local to its scene (see [member Resource.resource_local_to_scene]). If the scene root is not ready, it may return incorrect data (see [signal Node.ready]).
+ [b]Note:[/b] Instantiating scenes containing a high-resolution [ViewportTexture] may cause noticeable stutter.
</description>
<tutorials>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
@@ -16,8 +17,8 @@
</tutorials>
<members>
<member name="viewport_path" type="NodePath" setter="set_viewport_path_in_scene" getter="get_viewport_path_in_scene" default="NodePath(&quot;&quot;)">
- The path to the [Viewport] node to display. This is relative to the scene root, not to the node that uses the texture.
- [b]Note:[/b] In the editor, this path is automatically updated when the target viewport or one of its ancestors is renamed or moved. At runtime, the path may not be able to automatically update due to the inability to determine the scene root.
+ The path to the [Viewport] node to display. This is relative to the local scene root (see [method Resource.get_local_scene]), [b]not[/b] to the nodes that use this texture.
+ [b]Note:[/b] In the editor, this path is automatically updated when the target viewport or one of its ancestors is renamed or moved. At runtime, this path may not automatically update if the scene root cannot be found.
</member>
</members>
</class>
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index d7d77c6b8f..eebba6b00d 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -1064,7 +1064,11 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i
for (int j = 0; j < sc; j++) {
LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
- ERR_CONTINUE(!sli);
+ if (!sli) {
+ // Found a released light instance.
+ found_used_idx = j;
+ break;
+ }
if (sli->last_scene_pass != RasterizerSceneGLES3::get_singleton()->get_scene_pass()) {
// Was just allocated, don't kill it so soon, wait a bit.
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 516b8f3d74..51e1c27070 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1367,6 +1367,10 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
String f = ProjectSettings::get_singleton()->localize_path(p_file);
+ // Note: Only checks if base directory is case sensitive.
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ bool fs_case_sensitive = dir->is_case_sensitive("res://");
+
if (!f.begins_with("res://")) {
return false;
}
@@ -1390,9 +1394,16 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
int idx = -1;
for (int j = 0; j < fs->get_subdir_count(); j++) {
- if (fs->get_subdir(j)->get_name() == path[i]) {
- idx = j;
- break;
+ if (fs_case_sensitive) {
+ if (fs->get_subdir(j)->get_name() == path[i]) {
+ idx = j;
+ break;
+ }
+ } else {
+ if (fs->get_subdir(j)->get_name().to_lower() == path[i].to_lower()) {
+ idx = j;
+ break;
+ }
}
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 022cf82426..bba1939f72 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -3471,7 +3471,9 @@ EditorHelpHighlighter::HighlightData EditorHelpHighlighter::_get_highlight_data(
}
text_edits[p_language]->set_text(p_source);
- scripts[p_language]->set_source_code(p_source);
+ if (scripts[p_language].is_valid()) { // See GH-89610.
+ scripts[p_language]->set_source_code(p_source);
+ }
highlighters[p_language]->_update_cache();
HighlightData result;
@@ -3561,16 +3563,18 @@ EditorHelpHighlighter::EditorHelpHighlighter() {
#ifdef MODULE_MONO_ENABLED
TextEdit *csharp_text_edit = memnew(TextEdit);
- Ref<CSharpScript> csharp;
- csharp.instantiate();
+ // See GH-89610.
+ //Ref<CSharpScript> csharp;
+ //csharp.instantiate();
Ref<EditorStandardSyntaxHighlighter> csharp_highlighter;
csharp_highlighter.instantiate();
csharp_highlighter->set_text_edit(csharp_text_edit);
- csharp_highlighter->_set_edited_resource(csharp);
+ //csharp_highlighter->_set_edited_resource(csharp);
+ csharp_highlighter->_set_script_language(CSharpLanguage::get_singleton());
text_edits[LANGUAGE_CSHARP] = csharp_text_edit;
- scripts[LANGUAGE_CSHARP] = csharp;
+ //scripts[LANGUAGE_CSHARP] = csharp;
highlighters[LANGUAGE_CSHARP] = csharp_highlighter;
#endif
}
@@ -3578,14 +3582,10 @@ EditorHelpHighlighter::EditorHelpHighlighter() {
EditorHelpHighlighter::~EditorHelpHighlighter() {
#ifdef MODULE_GDSCRIPT_ENABLED
memdelete(text_edits[LANGUAGE_GDSCRIPT]);
- scripts[LANGUAGE_GDSCRIPT].unref();
- highlighters[LANGUAGE_GDSCRIPT].unref();
#endif
#ifdef MODULE_MONO_ENABLED
memdelete(text_edits[LANGUAGE_CSHARP]);
- scripts[LANGUAGE_CSHARP].unref();
- highlighters[LANGUAGE_CSHARP].unref();
#endif
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6f984f6fab..1c079bfca2 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5324,7 +5324,7 @@ bool EditorNode::is_distraction_free_mode_enabled() const {
return distraction_free->is_pressed();
}
-Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
+Dictionary EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
Control *drag_control = memnew(Control);
TextureRect *drag_preview = memnew(TextureRect);
Label *label = memnew(Label);
@@ -5364,7 +5364,7 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
return drag_data;
}
-Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from) {
+Dictionary EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from) {
bool has_folder = false;
bool has_file = false;
for (int i = 0; i < p_paths.size(); i++) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 8bcf29811d..96acc8bf46 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -870,8 +870,8 @@ public:
bool is_exiting() const { return exiting; }
- Variant drag_resource(const Ref<Resource> &p_res, Control *p_from);
- Variant drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from);
+ Dictionary drag_resource(const Ref<Resource> &p_res, Control *p_from);
+ Dictionary drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from);
void add_tool_menu_item(const String &p_name, const Callable &p_callback);
void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu);
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index a6c7d6b617..c59c221e02 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -328,6 +328,7 @@ void EditorPropertyArray::update_property() {
memdelete(container);
button_add_item = nullptr;
container = nullptr;
+ slots.clear();
}
return;
}
@@ -483,9 +484,10 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
}
Dictionary drag_data = p_drag_data;
+ const String drop_type = drag_data.get("type", "");
- if (drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
+ if (drop_type == "files") {
+ PackedStringArray files = drag_data["files"];
for (int i = 0; i < files.size(); i++) {
const String &file = files[i];
@@ -504,6 +506,56 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
return true;
}
+ if (drop_type == "nodes") {
+ Array node_paths = drag_data["nodes"];
+
+ PackedStringArray allowed_subtype_array;
+ if (allowed_type == "NodePath") {
+ if (subtype_hint_string == "NodePath") {
+ return true;
+ } else {
+ for (int j = 0; j < subtype_hint_string.get_slice_count(","); j++) {
+ String ast = subtype_hint_string.get_slice(",", j).strip_edges();
+ allowed_subtype_array.append(ast);
+ }
+ }
+ }
+
+ bool is_drop_allowed = true;
+
+ for (int i = 0; i < node_paths.size(); i++) {
+ const Node *dropped_node = get_node_or_null(node_paths[i]);
+ ERR_FAIL_NULL_V_MSG(dropped_node, false, "Could not get the dropped node by its path.");
+
+ if (allowed_type != "NodePath") {
+ if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type)) {
+ // Fail if one of the nodes is not of allowed type.
+ return false;
+ }
+ }
+
+ // The array of NodePaths is restricted to specific types using @export_node_path().
+ if (allowed_type == "NodePath" && subtype_hint_string != "NodePath") {
+ if (!allowed_subtype_array.has(dropped_node->get_class_name())) {
+ // The dropped node type was not found in the allowed subtype array, we must check if it inherits one of them.
+ for (const String &ast : allowed_subtype_array) {
+ if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast)) {
+ is_drop_allowed = true;
+ break;
+ } else {
+ is_drop_allowed = false;
+ }
+ }
+ if (!is_drop_allowed) {
+ break;
+ }
+ }
+ }
+ }
+
+ return is_drop_allowed;
+ }
+
return false;
}
@@ -515,18 +567,18 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
ERR_FAIL_COND(!_is_drop_valid(p_data));
Dictionary drag_data = p_data;
+ const String drop_type = drag_data.get("type", "");
+ Variant array = object->get_array();
- if (drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
-
- Variant array = object->get_array();
+ // Handle the case where array is not initialized yet.
+ if (!array.is_array()) {
+ initialize_array(array);
+ } else {
+ array = array.duplicate();
+ }
- // Handle the case where array is not initialized yet.
- if (!array.is_array()) {
- initialize_array(array);
- } else {
- array = array.duplicate();
- }
+ if (drop_type == "files") {
+ PackedStringArray files = drag_data["files"];
// Loop the file array and add to existing array.
for (int i = 0; i < files.size(); i++) {
@@ -540,6 +592,33 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
emit_changed(get_edited_property(), array);
}
+
+ if (drop_type == "nodes") {
+ Array node_paths = drag_data["nodes"];
+ Node *base_node = get_base_node();
+
+ for (int i = 0; i < node_paths.size(); i++) {
+ const NodePath &path = node_paths[i];
+
+ if (subtype == Variant::OBJECT) {
+ array.call("push_back", get_node(path));
+ } else if (subtype == Variant::NODE_PATH) {
+ array.call("push_back", base_node->get_path().rel_path_to(path));
+ }
+ }
+
+ emit_changed(get_edited_property(), array);
+ }
+}
+
+Node *EditorPropertyArray::get_base_node() {
+ Node *base_node = Object::cast_to<Node>(InspectorDock::get_inspector_singleton()->get_edited_object());
+
+ if (!base_node) {
+ base_node = get_tree()->get_edited_scene_root();
+ }
+
+ return base_node;
}
void EditorPropertyArray::_notification(int p_what) {
@@ -586,7 +665,7 @@ void EditorPropertyArray::_edit_pressed() {
Variant array = get_edited_property_value();
if (!array.is_array() && edit->is_pressed()) {
initialize_array(array);
- get_edited_object()->set(get_edited_property(), array);
+ emit_changed(get_edited_property(), array);
}
get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
@@ -867,7 +946,7 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint) {
void EditorPropertyDictionary::update_property() {
Variant updated_val = get_edited_property_value();
- if (updated_val.get_type() == Variant::NIL) {
+ if (updated_val.get_type() != Variant::DICTIONARY) {
edit->set_text(TTR("Dictionary (Nil)")); // This provides symmetry with the array property.
edit->set_pressed(false);
if (container) {
@@ -875,6 +954,7 @@ void EditorPropertyDictionary::update_property() {
memdelete(container);
button_add_item = nullptr;
container = nullptr;
+ slots.clear();
}
return;
}
@@ -1021,7 +1101,7 @@ void EditorPropertyDictionary::_edit_pressed() {
Variant prop_val = get_edited_property_value();
if (prop_val.get_type() == Variant::NIL && edit->is_pressed()) {
VariantInternal::initialize(&prop_val, Variant::DICTIONARY);
- get_edited_object()->set(get_edited_property(), prop_val);
+ emit_changed(get_edited_property(), prop_val);
}
get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index b1bf45f1b7..dae0fc52a6 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -135,6 +135,8 @@ class EditorPropertyArray : public EditorProperty {
void _reorder_button_up();
void _create_new_property_slot();
+ Node *get_base_node();
+
protected:
Ref<EditorPropertyArrayObject> object;
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 1cb71aa933..eee589489d 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -615,6 +615,13 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
}
bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
+ {
+ const ObjectID source_picker = p_drag_data.get("source_picker", ObjectID());
+ if (source_picker == get_instance_id()) {
+ return false;
+ }
+ }
+
if (base_type.is_empty()) {
return true;
}
@@ -670,7 +677,9 @@ bool EditorResourcePicker::_is_type_valid(const String &p_type_name, const HashS
Variant EditorResourcePicker::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (edited_resource.is_valid()) {
- return EditorNode::get_singleton()->drag_resource(edited_resource, p_from);
+ Dictionary drag_data = EditorNode::get_singleton()->drag_resource(edited_resource, p_from);
+ drag_data["source_picker"] = get_instance_id();
+ return drag_data;
}
return Variant();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 4521f4d3ff..233f20a8b3 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -576,9 +576,9 @@ void FileSystemDock::_notification(int p_what) {
if ((String(dd["favorite"]) == "all")) {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
}
- } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) {
+ } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs")) {
tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM | Tree::DROP_MODE_INBETWEEN);
- } else if ((String(dd["type"]) == "nodes")) {
+ } else if ((String(dd["type"]) == "nodes") || (String(dd["type"]) == "resource")) {
holding_branch = true;
TreeItem *item = tree->get_next_selected(tree->get_root());
while (item) {
@@ -1561,10 +1561,42 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
}
void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const {
- // Update the paths in ResourceUID, so that UIDs remain valid.
- for (const KeyValue<String, ResourceUID::ID> &pair : p_uids) {
- if (p_renames.has(pair.key)) {
- ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]);
+ for (const KeyValue<String, String> &pair : p_renames) {
+ // Update UID path.
+ const String &old_path = pair.key;
+ const String &new_path = pair.value;
+
+ const HashMap<String, ResourceUID::ID>::ConstIterator I = p_uids.find(old_path);
+ if (I) {
+ ResourceUID::get_singleton()->set_id(I->value, new_path);
+ }
+
+ ScriptServer::remove_global_class_by_path(old_path);
+
+ int index = -1;
+ EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->find_file(old_path, &index);
+
+ if (!efd || index < 0) {
+ // The file was removed.
+ continue;
+ }
+
+ // Update paths for global classes.
+ if (!efd->get_file_script_class_name(index).is_empty()) {
+ String lang;
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ if (ScriptServer::get_language(i)->handles_global_class_type(efd->get_file_type(index))) {
+ lang = ScriptServer::get_language(i)->get_name();
+ break;
+ }
+ }
+ if (lang.is_empty()) {
+ continue; // No language found that can handle this global class.
+ }
+
+ ScriptServer::add_global_class(efd->get_file_script_class_name(index), efd->get_file_script_class_extends(index), lang, new_path);
+ EditorNode::get_editor_data().script_class_set_icon_path(efd->get_file_script_class_name(index), efd->get_file_script_class_icon_path(index));
+ EditorNode::get_editor_data().script_class_set_name(new_path, efd->get_file_script_class_name(index));
}
}
@@ -1583,10 +1615,13 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str
if (p_renames.has(base_path)) {
base_path = p_renames[base_path];
+ r->set_path(base_path + extra_path);
}
-
- r->set_path(base_path + extra_path);
}
+
+ ScriptServer::save_global_classes();
+ EditorNode::get_editor_data().script_class_save_icon_paths();
+ EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated"));
}
void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const {
@@ -1710,6 +1745,13 @@ void FileSystemDock::_make_scene_confirm() {
}
void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) {
+ const Ref<Script> &scr = p_resource;
+ if (scr.is_valid()) {
+ ScriptServer::remove_global_class_by_path(scr->get_path());
+ ScriptServer::save_global_classes();
+ EditorNode::get_editor_data().script_class_save_icon_paths();
+ EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated"));
+ }
emit_signal(SNAME("resource_removed"), p_resource);
}
@@ -2757,7 +2799,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
String to_dir;
bool favorite;
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
- return !to_dir.is_empty();
+ return !favorite;
}
if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) {
@@ -2872,7 +2914,12 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
Ref<Resource> res = drag_data["resource"];
String to_dir;
bool favorite;
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
+ if (to_dir.is_empty()) {
+ to_dir = get_current_directory();
+ }
+
if (res.is_valid() && !to_dir.is_empty()) {
EditorNode::get_singleton()->push_item(res.ptr());
EditorNode::get_singleton()->save_resource_as(res, to_dir);
@@ -2918,7 +2965,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
if (drag_data.has("type") && String(drag_data["type"]) == "nodes") {
String to_dir;
bool favorite;
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
+ if (to_dir.is_empty()) {
+ to_dir = get_current_directory();
+ }
SceneTreeDock::get_singleton()->save_branch_to_file(to_dir);
}
}
@@ -2931,6 +2982,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
if (p_from == files) {
int pos = files->get_item_at_position(p_point, true);
if (pos == -1) {
+ target = get_current_directory();
return;
}
@@ -3454,37 +3506,41 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && holding_branch) {
- const int item_idx = files->get_item_at_position(mm->get_position());
+ const int item_idx = files->get_item_at_position(mm->get_position(), true);
+ files->deselect_all();
+ String fpath;
if (item_idx != -1) {
- files->deselect_all();
- String fpath = files->get_item_metadata(item_idx);
+ fpath = files->get_item_metadata(item_idx);
if (fpath.ends_with("/") || fpath == "res://") {
files->select(item_idx);
}
+ } else {
+ fpath = get_current_directory();
+ }
- TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
- while (deselect_item) {
- deselect_item->deselect(0);
- deselect_item = tree->get_next_selected(deselect_item);
+ TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
+ while (deselect_item) {
+ deselect_item->deselect(0);
+ deselect_item = tree->get_next_selected(deselect_item);
+ }
+
+ // Try to select the corresponding tree item.
+ TreeItem *tree_item = (item_idx != -1) ? tree->get_item_with_text(files->get_item_text(item_idx)) : nullptr;
+
+ if (tree_item) {
+ tree_item->select(0);
+ } else {
+ // Find parent folder.
+ fpath = fpath.substr(0, fpath.rfind("/") + 1);
+ if (fpath.size() > String("res://").size()) {
+ fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
+ const int slash_idx = fpath.rfind("/");
+ fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
}
- // Try to select the corresponding tree item.
- TreeItem *tree_item = tree->get_item_with_text(files->get_item_text(item_idx));
+ tree_item = tree->get_item_with_text(fpath);
if (tree_item) {
tree_item->select(0);
- } else {
- // Find parent folder.
- fpath = fpath.substr(0, fpath.rfind("/") + 1);
- if (fpath.size() > String("res://").size()) {
- fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
- const int slash_idx = fpath.rfind("/");
- fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
- }
-
- tree_item = tree->get_item_with_text(fpath);
- if (tree_item) {
- tree_item->select(0);
- }
}
}
}
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index bec13b710d..c4e38b327a 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -157,10 +157,14 @@ void GroupsEditor::_update_groups() {
_load_scene_groups(scene_root_node);
- for (const KeyValue<StringName, bool> &E : scene_groups) {
- if (global_groups.has(E.key)) {
- scene_groups.erase(E.key);
+ for (HashMap<StringName, bool>::Iterator E = scene_groups.begin(); E;) {
+ HashMap<StringName, bool>::Iterator next = E;
+ ++next;
+
+ if (global_groups.has(E->key)) {
+ scene_groups.erase(E->key);
}
+ E = next;
}
updating_groups = false;
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 0dd75ea033..221061f9f7 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -897,6 +897,14 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_
}
}
+void SceneTreeEditor::_tree_scroll_to_item(ObjectID p_item_id) {
+ ERR_FAIL_NULL(tree);
+ TreeItem *item = Object::cast_to<TreeItem>(ObjectDB::get_instance(p_item_id));
+ if (item) {
+ tree->scroll_to_item(item, true);
+ }
+}
+
void SceneTreeEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -942,7 +950,8 @@ void SceneTreeEditor::_notification(int p_what) {
if (item) {
// Must wait until tree is properly sized before scrolling.
- callable_mp(tree, &Tree::scroll_to_item).call_deferred(item, true);
+ ObjectID item_id = item->get_instance_id();
+ callable_mp(this, &SceneTreeEditor::_tree_scroll_to_item).call_deferred(item_id);
}
}
} break;
diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h
index c1abdcef8b..b4d9644f16 100644
--- a/editor/gui/scene_tree_editor.h
+++ b/editor/gui/scene_tree_editor.h
@@ -123,6 +123,7 @@ class SceneTreeEditor : public Control {
void _set_item_custom_color(TreeItem *p_item, Color p_color);
void _update_node_tooltip(Node *p_node, TreeItem *p_item);
void _queue_update_node_tooltip(Node *p_node, TreeItem *p_item);
+ void _tree_scroll_to_item(ObjectID p_item_id);
void _selection_changed();
Node *get_scene_node() const;
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index d56b426c86..d2705ac98a 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -122,11 +122,12 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
if (!key.is_empty()) {
ERR_CONTINUE_MSG(line.size() != locales.size() + (int)skipped_locales.size() + 1, vformat("Error importing CSV translation: expected %d locale(s), but the '%s' key has %d locale(s).", locales.size(), key, line.size() - 1));
+ int write_index = 0; // Keep track of translations written in case some locales are skipped.
for (int i = 1; i < line.size(); i++) {
if (skipped_locales.has(i)) {
continue;
}
- translations.write[i - 1]->add_message(key, line[i].c_unescape());
+ translations.write[write_index++]->add_message(key, line[i].c_unescape());
}
}
} while (!f->eof_reached());
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 4c02d82caa..e67f3bd596 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -421,7 +421,7 @@ void BoneMapper::recreate_editor() {
for (int i = 0; i < len; i++) {
if (profile->get_group(i) == profile->get_group_name(current_group_idx)) {
- BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), profile->is_require(i), current_bone_idx == i));
+ BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), profile->is_required(i), current_bone_idx == i));
mb->connect("pressed", callable_mp(this, &BoneMapper::set_current_bone_idx).bind(i), CONNECT_DEFERRED);
mb->set_h_grow_direction(GROW_DIRECTION_BOTH);
mb->set_v_grow_direction(GROW_DIRECTION_BOTH);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 7e271bb68e..d09e4fd3db 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -4519,7 +4519,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
Ref<BaseMaterial3D> base_mat = res;
Ref<ShaderMaterial> shader_mat = res;
- if (base_mat.is_null() && !shader_mat.is_null()) {
+ if (base_mat.is_null() && shader_mat.is_null()) {
continue;
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index eeb84cb79e..6c63d9ff0d 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -137,12 +137,22 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
}
}
- const Ref<Script> scr = _get_edited_resource();
- if (scr.is_valid()) {
+ const ScriptLanguage *scr_lang = script_language;
+ StringName instance_base;
+
+ if (scr_lang == nullptr) {
+ const Ref<Script> scr = _get_edited_resource();
+ if (scr.is_valid()) {
+ scr_lang = scr->get_language();
+ instance_base = scr->get_instance_base_type();
+ }
+ }
+
+ if (scr_lang != nullptr) {
/* Core types. */
const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
List<String> core_types;
- scr->get_language()->get_core_type_words(&core_types);
+ scr_lang->get_core_type_words(&core_types);
for (const String &E : core_types) {
highlighter->add_keyword_color(E, basetype_color);
}
@@ -151,9 +161,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
List<String> keywords;
- scr->get_language()->get_reserved_words(&keywords);
+ scr_lang->get_reserved_words(&keywords);
for (const String &E : keywords) {
- if (scr->get_language()->is_control_flow_keyword(E)) {
+ if (scr_lang->is_control_flow_keyword(E)) {
highlighter->add_keyword_color(E, control_flow_keyword_color);
} else {
highlighter->add_keyword_color(E, keyword_color);
@@ -162,7 +172,6 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Member types. */
const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
- StringName instance_base = scr->get_instance_base_type();
if (instance_base != StringName()) {
List<PropertyInfo> plist;
ClassDB::get_property_list(instance_base, &plist);
@@ -187,7 +196,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Comments */
const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
- scr->get_language()->get_comment_delimiters(&comments);
+ scr_lang->get_comment_delimiters(&comments);
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
@@ -197,7 +206,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Doc comments */
const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
List<String> doc_comments;
- scr->get_language()->get_doc_comment_delimiters(&doc_comments);
+ scr_lang->get_doc_comment_delimiters(&doc_comments);
for (const String &doc_comment : doc_comments) {
String beg = doc_comment.get_slice(" ", 0);
String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
@@ -207,7 +216,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Strings */
const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
- scr->get_language()->get_string_delimiters(&strings);
+ scr_lang->get_string_delimiters(&strings);
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 4fff724866..0252e10b43 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -78,6 +78,7 @@ class EditorStandardSyntaxHighlighter : public EditorSyntaxHighlighter {
private:
Ref<CodeHighlighter> highlighter;
+ ScriptLanguage *script_language = nullptr; // See GH-89610.
public:
virtual void _update_cache() override;
@@ -87,6 +88,8 @@ public:
virtual Ref<EditorSyntaxHighlighter> _create() const override;
+ void _set_script_language(ScriptLanguage *p_script_language) { script_language = p_script_language; }
+
EditorStandardSyntaxHighlighter() { highlighter.instantiate(); }
};
diff --git a/main/main.cpp b/main/main.cpp
index cf40f764cf..6a132a37ae 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -347,7 +347,6 @@ void initialize_navigation_server() {
// Fall back to dummy if no default server has been registered.
if (!navigation_server_3d) {
- WARN_PRINT_ONCE("No NavigationServer3D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
navigation_server_3d = memnew(NavigationServer3DDummy);
}
@@ -358,7 +357,6 @@ void initialize_navigation_server() {
// Init 2D Navigation Server
navigation_server_2d = NavigationServer2DManager::new_default_server();
if (!navigation_server_2d) {
- WARN_PRINT_ONCE("No NavigationServer2D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
navigation_server_2d = memnew(NavigationServer2DDummy);
}
diff --git a/methods.py b/methods.py
index 7af621befc..fa7db95e92 100644
--- a/methods.py
+++ b/methods.py
@@ -228,7 +228,32 @@ def get_version_info(module_version_string="", silent=False):
return version_info
+_cleanup_env = None
+_cleanup_bool = False
+
+
def write_file_if_needed(path, string):
+ """Generates a file only if it doesn't already exist or the content has changed.
+
+ Utilizes a dedicated SCons environment to ensure the files are properly removed
+ during cleanup; will not attempt to create files during cleanup.
+
+ - `path` - Path to the file in question; used to create cleanup logic.
+ - `string` - Content to compare against an existing file.
+ """
+ global _cleanup_env
+ global _cleanup_bool
+
+ if _cleanup_env is None:
+ from SCons.Environment import Environment
+
+ _cleanup_env = Environment()
+ _cleanup_bool = _cleanup_env.GetOption("clean")
+
+ _cleanup_env.Clean("#", path)
+ if _cleanup_bool:
+ return
+
try:
with open(path, "r", encoding="utf-8", newline="\n") as f:
if f.read() == string:
@@ -1427,14 +1452,18 @@ def generate_vs_project(env, original_args, project_name="godot"):
props_template = props_template.replace("%%OUTPUT%%", output)
- props_template = props_template.replace(
- "%%DEFINES%%", ";".join([format_key_value(v) for v in list(env["CPPDEFINES"])])
- )
- props_template = props_template.replace("%%INCLUDES%%", ";".join([str(j) for j in env["CPPPATH"]]))
- props_template = props_template.replace(
- "%%OPTIONS%%",
- " ".join(env["CCFLAGS"]) + " " + " ".join([x for x in env["CXXFLAGS"] if not x.startswith("$")]),
- )
+ proplist = [format_key_value(v) for v in list(env["CPPDEFINES"])]
+ proplist += [format_key_value(j) for j in env.get("VSHINT_DEFINES", [])]
+ props_template = props_template.replace("%%DEFINES%%", ";".join(proplist))
+
+ proplist = [str(j) for j in env["CPPPATH"]]
+ proplist += [str(j) for j in env.get("VSHINT_INCLUDES", [])]
+ props_template = props_template.replace("%%INCLUDES%%", ";".join(proplist))
+
+ proplist = env["CCFLAGS"]
+ proplist += [x for x in env["CXXFLAGS"] if not x.startswith("$")]
+ proplist += [str(j) for j in env.get("VSHINT_OPTIONS", [])]
+ props_template = props_template.replace("%%OPTIONS%%", " ".join(proplist))
# Windows allows us to have spaces in paths, so we need
# to double quote off the directory. However, the path ends
diff --git a/misc/msvs/props.template b/misc/msvs/props.template
index 8facaf7f36..f360871b72 100644
--- a/misc/msvs/props.template
+++ b/misc/msvs/props.template
@@ -4,13 +4,13 @@
<NMakeBuildCommandLine>%%BUILD%%</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>%%REBUILD%%</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>%%CLEAN%%</NMakeCleanCommandLine>
- <NMakeOutput>%%OUTPUT%%</NMakeOutput>
- <NMakePreprocessorDefinitions>%%DEFINES%%</NMakePreprocessorDefinitions>
- <NMakeIncludeSearchPath>%%INCLUDES%%</NMakeIncludeSearchPath>
+ <NMakeOutput Condition="'$(NMakeOutput)' == ''">%%OUTPUT%%</NMakeOutput>
+ <NMakePreprocessorDefinitions>%%DEFINES%%;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
+ <NMakeIncludeSearchPath>%%INCLUDES%%;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
<NMakeForcedIncludes>$(NMakeForcedIncludes)</NMakeForcedIncludes>
<NMakeAssemblySearchPath>$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>
<NMakeForcedUsingAssemblies>$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>
- <AdditionalOptions>%%OPTIONS%%</AdditionalOptions>
+ <AdditionalOptions>%%OPTIONS%% $(AdditionalOptions)</AdditionalOptions>
</PropertyGroup>
<PropertyGroup Condition="%%CONDITION%%">
%%PROPERTIES%%
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 4869573972..07d917ea04 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -168,7 +168,7 @@
# Load a scene called "main" located in the root of the project directory and cache it in a variable.
var main = load("res://main.tscn") # main will contain a PackedScene resource.
[/codeblock]
- [b]Important:[/b] The path must be absolute. A relative path will always return [code]null[/code].
+ [b]Important:[/b] Relative paths are [i]not[/i] relative to the script calling this method, instead it is prefixed with [code]"res://"[/code]. Loading from relative paths might not work as expected.
This function is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
[b]Note:[/b] Files have to be imported into the engine first to load them using this function. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
[b]Note:[/b] If [member ProjectSettings.editor/export/convert_text_resources_to_binary] is [code]true[/code], [method @GDScript.load] will not be able to read converted files in an exported project. If you rely on run-time loading of files present within the PCK, set [member ProjectSettings.editor/export/convert_text_resources_to_binary] to [code]false[/code].
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 439555bacb..b4f4e879d0 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -65,8 +65,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
bool in_function_name = false; // Any call.
bool in_function_declaration = false; // Only declaration.
- bool in_var_const_declaration = false;
bool in_signal_declaration = false;
+ bool is_after_func_signal_declaration = false;
+ bool in_var_const_declaration = false;
+ bool is_after_var_const_declaration = false;
bool expect_type = false;
int in_declaration_params = 0; // The number of opened `(` after func/signal name.
@@ -410,6 +412,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
col = class_names[word];
} else if (reserved_keywords.has(word)) {
col = reserved_keywords[word];
+ // Don't highlight `list` as a type in `for elem: Type in list`.
+ expect_type = false;
} else if (member_keywords.has(word)) {
col = member_keywords[word];
}
@@ -480,6 +484,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (is_a_symbol) {
+ if (in_function_declaration || in_signal_declaration) {
+ is_after_func_signal_declaration = true;
+ }
+ if (in_var_const_declaration) {
+ is_after_var_const_declaration = true;
+ }
+
if (in_declaration_params > 0) {
switch (str[j]) {
case '(':
@@ -495,7 +506,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_declaration_param_dicts -= 1;
break;
}
- } else if ((in_function_declaration || in_signal_declaration || prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) && str[j] == '(') {
+ } else if ((is_after_func_signal_declaration || prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) && str[j] == '(') {
in_declaration_params = 1;
in_declaration_param_dicts = 0;
}
@@ -526,19 +537,22 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
expect_type = true;
in_type_params = 0;
}
- if ((in_var_const_declaration || (in_declaration_params == 1 && in_declaration_param_dicts == 0)) && str[j] == ':') {
+ if ((is_after_var_const_declaration || (in_declaration_params == 1 && in_declaration_param_dicts == 0)) && str[j] == ':') {
expect_type = true;
in_type_params = 0;
}
}
+ in_function_name = false;
+ in_function_declaration = false;
+ in_signal_declaration = false;
+ in_var_const_declaration = false;
+ in_lambda = false;
+ in_member_variable = false;
+
if (!is_whitespace(str[j])) {
- in_function_declaration = false;
- in_var_const_declaration = false;
- in_signal_declaration = false;
- in_function_name = false;
- in_lambda = false;
- in_member_variable = false;
+ is_after_func_signal_declaration = false;
+ is_after_var_const_declaration = false;
}
}
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6af6460b31..f67f4913c3 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3293,6 +3293,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
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.
// Virtual check only possible for super() calls because class hierarchy is known. Node/Objects may have scripts attached we don't know of at compile-time.
+ p_call->is_static = method_flags.has_flag(METHOD_FLAG_STATIC);
if (p_call->is_super && method_flags.has_flag(METHOD_FLAG_VIRTUAL)) {
push_error(vformat(R"*(Cannot call the parent class' virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call);
}
@@ -3311,7 +3312,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
base_type.is_meta_type = false;
}
- if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ if (is_self && static_context && !p_call->is_static) {
// Get the parent function above any lambda.
GDScriptParser::FunctionNode *parent_function = parser->current_function;
while (parent_function && parent_function->source_lambda) {
@@ -3323,10 +3324,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
push_error(vformat(R"*(Cannot call non-static function "%s()" from a static variable initializer.)*", p_call->function_name), p_call);
}
- } else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ } else if (!is_self && base_type.is_meta_type && !p_call->is_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 && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ } else if (is_self && !p_call->is_static) {
mark_lambda_use_self();
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 13ed66710c..d706c1b101 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -648,7 +648,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, self, method, arguments);
}
- } else if (codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
+ } else if (call->is_static || codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
if (is_awaited) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index ea67f1eaff..d047fa8e46 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -498,6 +498,7 @@ public:
Vector<ExpressionNode *> arguments;
StringName function_name;
bool is_super = false;
+ bool is_static = false;
CallNode() {
type = CALL;
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
index b0283b0c55..d11300343a 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
@@ -84,6 +84,11 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l
}
}
+void EditorSceneExporterGLTFSettings::_on_extension_property_list_changed() {
+ generate_property_list(_document);
+ emit_signal("property_list_changed");
+}
+
bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) {
PackedStringArray split = String(p_name_str).split("/", true, 1);
if (!_config_name_to_extension_map.has(split[0])) {
@@ -130,6 +135,10 @@ void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p
String image_format_hint_string = "None,PNG,JPEG";
// Add properties from all document extensions.
for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) {
+ const Callable on_prop_changed = callable_mp(this, &EditorSceneExporterGLTFSettings::_on_extension_property_list_changed);
+ if (!extension->is_connected("property_list_changed", on_prop_changed)) {
+ extension->connect("property_list_changed", on_prop_changed);
+ }
const String config_prefix = get_friendly_config_prefix(extension);
_config_name_to_extension_map[config_prefix] = extension;
// If the extension allows saving in different image formats, add to the enum.
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
index 6032932367..e1ce674274 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
@@ -48,6 +48,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _on_extension_property_list_changed();
bool _set_extension_setting(const String &p_name_str, const Variant &p_value);
bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const;
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 4b8f65d8ff..04d26f9942 100644
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -100,9 +100,9 @@ if env["builtin_mbedtls"]:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_mbed_tls.Prepend(CPPPATH=["#thirdparty/mbedtls/include/"])
- env_mbed_tls.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_mbed_tls["ninja"] and env_mbed_tls.msvc else f'\\"{config_path}\\"'
+ env_mbed_tls.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 46020fda89..57611d5f4c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -90,6 +90,13 @@ namespace GodotTools.Export
$"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}",
nameof(path));
+ if (!ProjectContainsDotNet())
+ {
+ _maybeLastExportError = $"This project contains C# files but no solution file was found at the following path: {GodotSharpDirs.ProjectSlnPath}\n" +
+ "A solution file is required for projects with C# files. Please ensure that the solution file exists in the specified location and try again.";
+ throw new InvalidOperationException($"{path} is a C# file but no solution file exists.");
+ }
+
// TODO: What if the source file is not part of the game's C# project?
bool includeScriptsContent = (bool)GetOption("dotnet/include_scripts_content");
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index bf6cab11c7..d3899c809a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -167,8 +167,8 @@ namespace GodotTools
public void ShowConfirmCreateSlnDialog()
{
- _confirmCreateSlnDialog.Title = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR();
- _confirmCreateSlnDialog.DialogText = "Create C# solution".TTR();
+ _confirmCreateSlnDialog.Title = "Create C# solution".TTR();
+ _confirmCreateSlnDialog.DialogText = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR();
EditorInterface.Singleton.PopupDialogCentered(_confirmCreateSlnDialog);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 9b5aec7031..fb1d32c0cb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
+using System.Diagnostics;
#nullable enable
@@ -16,6 +17,8 @@ namespace Godot.Collections
/// interfacing with the engine. Otherwise prefer .NET collections
/// such as <see cref="System.Array"/> or <see cref="List{T}"/>.
/// </summary>
+ [DebuggerTypeProxy(typeof(ArrayDebugView<Variant>))]
+ [DebuggerDisplay("Count = {Count}")]
#pragma warning disable CA1710 // Identifiers should have correct suffix
public sealed class Array :
#pragma warning restore CA1710
@@ -1040,6 +1043,8 @@ namespace Godot.Collections
/// such as arrays or <see cref="List{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
+ [DebuggerTypeProxy(typeof(ArrayDebugView<>))]
+ [DebuggerDisplay("Count = {Count}")]
[SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
[SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")]
public sealed class Array<[MustBeVariant] T> :
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebugView.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebugView.cs
new file mode 100644
index 0000000000..6d6eb61f8f
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebugView.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Godot.Collections
+{
+ internal sealed class ArrayDebugView<T>
+ {
+ private readonly IList<T> _array;
+
+ public ArrayDebugView(IList<T> array)
+ {
+ ArgumentNullException.ThrowIfNull(array);
+
+ _array = array;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public T[] Items
+ {
+ get
+ {
+ var items = new T[_array.Count];
+ _array.CopyTo(items, 0);
+ return items;
+ }
+ }
+ }
+
+ internal sealed class DictionaryDebugView<TKey, TValue>
+ {
+ private readonly IDictionary<TKey, TValue> _dictionary;
+
+ public DictionaryDebugView(IDictionary<TKey, TValue> dictionary)
+ {
+ ArgumentNullException.ThrowIfNull(dictionary);
+
+ _dictionary = dictionary;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public DictionaryKeyItemDebugView<TKey, TValue>[] Items
+ {
+ get
+ {
+ var items = new KeyValuePair<TKey, TValue>[_dictionary.Count];
+ var views = new DictionaryKeyItemDebugView<TKey, TValue>[_dictionary.Count];
+ _dictionary.CopyTo(items, 0);
+ for (int i = 0; i < items.Length; i++)
+ {
+ views[i] = new DictionaryKeyItemDebugView<TKey, TValue>(items[i]);
+ }
+ return views;
+ }
+ }
+ }
+
+ [DebuggerDisplay("{Value}", Name = "[{Key}]")]
+ internal readonly struct DictionaryKeyItemDebugView<TKey, TValue>
+ {
+ public DictionaryKeyItemDebugView(KeyValuePair<TKey, TValue> keyValue)
+ {
+ Key = keyValue.Key;
+ Value = keyValue.Value;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
+ public TKey Key { get; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
+ public TValue Value { get; }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index ef3c9c79d4..7a88fea5f1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -207,7 +207,7 @@ namespace Godot
foreach (FieldInfo field in fields)
{
- Type fieldType = field.GetType();
+ Type fieldType = field.FieldType;
Variant.Type variantType = GD.TypeToVariantType(fieldType);
@@ -216,7 +216,7 @@ namespace Godot
static byte[] VarToBytes(in godot_variant var)
{
- NativeFuncs.godotsharp_var_to_bytes(var, false.ToGodotBool(), out var varBytes);
+ NativeFuncs.godotsharp_var_to_bytes(var, godot_bool.True, out var varBytes);
using (varBytes)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
@@ -483,7 +483,7 @@ namespace Godot
if (fieldInfo != null)
{
- var variantValue = GD.BytesToVar(valueBuffer);
+ var variantValue = GD.BytesToVarWithObjects(valueBuffer);
object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType(
(godot_variant)variantValue.NativeVar, fieldInfo.FieldType);
fieldInfo.SetValue(recreatedTarget, managedValue);
@@ -799,7 +799,7 @@ namespace Godot
return func(variant);
if (typeof(GodotObject).IsAssignableFrom(type))
- return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type, CultureInfo.InvariantCulture);
+ return VariantUtils.ConvertTo<GodotObject>(variant);
if (typeof(GodotObject[]).IsAssignableFrom(type))
{
@@ -818,7 +818,7 @@ namespace Godot
}
using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant);
- return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type, CultureInfo.InvariantCulture);
+ return ConvertToSystemArrayOfGodotObject(godotArray, type);
}
if (type.IsEnum)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index d08fad90db..864815866a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -4,6 +4,7 @@ using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
+using System.Diagnostics;
#nullable enable
@@ -14,6 +15,8 @@ namespace Godot.Collections
/// typed elements allocated in the engine in C++. Useful when
/// interfacing with the engine.
/// </summary>
+ [DebuggerTypeProxy(typeof(DictionaryDebugView<Variant, Variant>))]
+ [DebuggerDisplay("Count = {Count}")]
public sealed class Dictionary :
IDictionary<Variant, Variant>,
IReadOnlyDictionary<Variant, Variant>,
@@ -480,6 +483,8 @@ namespace Godot.Collections
/// </summary>
/// <typeparam name="TKey">The type of the dictionary's keys.</typeparam>
/// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
+ [DebuggerTypeProxy(typeof(DictionaryDebugView<,>))]
+ [DebuggerDisplay("Count = {Count}")]
public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> :
IDictionary<TKey, TValue>,
IReadOnlyDictionary<TKey, TValue>,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index d54942e654..d4c11da963 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -77,6 +77,7 @@
<Compile Include="Core\Color.cs" />
<Compile Include="Core\Colors.cs" />
<Compile Include="Core\DebuggingUtils.cs" />
+ <Compile Include="Core\DebugView.cs" />
<Compile Include="Core\DelegateUtils.cs" />
<Compile Include="Core\Dictionary.cs" />
<Compile Include="Core\Dispatcher.cs" />
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 264a2e9c8e..6c0669b2f3 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -251,6 +251,7 @@ NodePath MultiplayerSpawner::get_spawn_path() const {
void MultiplayerSpawner::set_spawn_path(const NodePath &p_path) {
spawn_path = p_path;
_update_spawn_node();
+ update_configuration_warnings();
}
void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_scene_id) {
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index 02e3a11964..c2ce500af8 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -354,6 +354,7 @@ void MultiplayerSynchronizer::set_root_path(const NodePath &p_path) {
_stop();
root_path = p_path;
_start();
+ update_configuration_warnings();
}
NodePath MultiplayerSynchronizer::get_root_path() const {
diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp
index 069cc0f4a8..0738a102eb 100644
--- a/modules/navigation/2d/nav_mesh_generator_2d.cpp
+++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp
@@ -575,8 +575,6 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
return;
}
- int tilemap_layer = 0; // only main tile map layer is supported
-
Ref<TileSet> tile_set = tilemap->get_tileset();
if (!tile_set.is_valid()) {
return;
@@ -589,77 +587,115 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
return;
}
- const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
- TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
+ HashSet<Vector2i> cells_with_navigation_polygon;
+ HashSet<Vector2i> cells_with_collision_polygon;
- for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
- const Vector2i &cell = used_cells[used_cell_index];
+ const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
- const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
- if (tile_data == nullptr) {
- continue;
- }
+#ifdef DEBUG_ENABLED
+ int error_print_counter = 0;
+ int error_print_max = 10;
+#endif // DEBUG_ENABLED
- // Transform flags.
- const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
- bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
- bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
- bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+ for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) {
+ TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
- Transform2D tile_transform;
- tile_transform.set_origin(tilemap->map_to_local(cell));
+ for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
+ const Vector2i &cell = used_cells[used_cell_index];
- const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+ const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
+ if (tile_data == nullptr) {
+ continue;
+ }
- if (navigation_layers_count > 0) {
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
- if (navigation_polygon.is_valid()) {
- for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
- const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
- if (navigation_polygon_outline.size() == 0) {
- continue;
+ // Transform flags.
+ const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
+ bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
+ bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
+ bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+
+ Transform2D tile_transform;
+ tile_transform.set_origin(tilemap->map_to_local(cell));
+
+ const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+
+ if (navigation_layers_count > 0) {
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
+ if (navigation_polygon.is_valid()) {
+ if (cells_with_navigation_polygon.has(cell)) {
+#ifdef DEBUG_ENABLED
+ error_print_counter++;
+ if (error_print_counter <= error_print_max) {
+ WARN_PRINT(vformat("TileMap navigation mesh baking error. The TileMap cell key Vector2i(%s, %s) has navigation mesh from 2 or more different TileMap layers assigned. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
+ }
+#endif // DEBUG_ENABLED
+ } else {
+ cells_with_navigation_polygon.insert(cell);
+
+ for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
+ const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
+ if (navigation_polygon_outline.size() == 0) {
+ continue;
+ }
+
+ Vector<Vector2> traversable_outline;
+ traversable_outline.resize(navigation_polygon_outline.size());
+
+ const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
+ Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
+
+ for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
+ traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
+ }
+
+ p_source_geometry_data->_add_traversable_outline(traversable_outline);
+ }
}
+ }
+ }
- Vector<Vector2> traversable_outline;
- traversable_outline.resize(navigation_polygon_outline.size());
-
- const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
- Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
-
- for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
- traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
+ if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
+ if (cells_with_collision_polygon.has(cell)) {
+#ifdef DEBUG_ENABLED
+ error_print_counter++;
+ if (error_print_counter <= error_print_max) {
+ WARN_PRINT(vformat("TileMap navigation mesh baking error. The cell key Vector2i(%s, %s) has collision polygons from 2 or more different TileMap layers assigned that all match the parsed collision mask. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
}
+#endif // DEBUG_ENABLED
+ } else {
+ cells_with_collision_polygon.insert(cell);
- p_source_geometry_data->_add_traversable_outline(traversable_outline);
- }
- }
- }
+ for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
+ PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
+ if (collision_polygon_points.size() == 0) {
+ continue;
+ }
- if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
- for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
- PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
- if (collision_polygon_points.size() == 0) {
- continue;
- }
+ if (flip_h || flip_v || transpose) {
+ collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
+ }
- if (flip_h || flip_v || transpose) {
- collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
- }
+ Vector<Vector2> obstruction_outline;
+ obstruction_outline.resize(collision_polygon_points.size());
- Vector<Vector2> obstruction_outline;
- obstruction_outline.resize(collision_polygon_points.size());
+ const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
+ Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
- const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
- Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
+ for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
+ obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
+ }
- for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
- obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
+ p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
+ }
}
-
- p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
}
}
}
+#ifdef DEBUG_ENABLED
+ if (error_print_counter > error_print_max) {
+ ERR_PRINT(vformat("TileMap navigation mesh baking error. A total of %s cells with navigation or collision polygons from 2 or more different TileMap layers overlap. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", error_print_counter));
+ }
+#endif // DEBUG_ENABLED
}
void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
index 7488b5cf8e..4c611d6f4a 100644
--- a/modules/openxr/util.h
+++ b/modules/openxr/util.h
@@ -34,21 +34,23 @@
#define UNPACK(...) __VA_ARGS__
#define INIT_XR_FUNC_V(openxr_api, name) \
- do { \
+ if constexpr (true) { \
XrResult get_instance_proc_addr_result; \
get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(OpenXRAPI::get_singleton(), name)
#define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name)
#define INIT_XR_FUNC(openxr_api, name) \
- do { \
+ if constexpr (true) { \
XrResult get_instance_proc_addr_result; \
get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(OpenXRAPI::get_singleton(), name)
#define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name)
@@ -59,16 +61,18 @@
#define EXT_TRY_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(OpenXRAPI::get_singleton(), name)
#define OPENXR_TRY_API_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(this, name)
#define GDEXTENSION_INIT_XR_FUNC(name) \
- do { \
+ if constexpr (true) { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
ERR_FAIL_NULL(name##_ptr); \
- } while (0)
+ } else \
+ ((void)0)
#define GDEXTENSION_INIT_XR_FUNC_V(name) \
- do { \
+ if constexpr (true) { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
ERR_FAIL_NULL_V(name##_ptr, false); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
PFN_##func_name func_name##_ptr = nullptr; \
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index f5174d7d46..c092fd7511 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -1432,8 +1432,25 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
#endif
if (!p_font_data->face_init) {
- // Get style flags and name.
- if (fd->face->family_name != nullptr) {
+ // When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
+ // FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
+ // To avoid that behavior, use the format-specific name directly if available.
+ hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
+ unsigned int num_entries = 0;
+ const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);
+ const hb_language_t english = hb_language_from_string("en", -1);
+ for (unsigned int i = 0; i < num_entries; i++) {
+ if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {
+ continue;
+ }
+ if (!p_font_data->font_name.is_empty() && names[i].language != english) {
+ continue;
+ }
+ unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;
+ p_font_data->font_name.resize(text_size);
+ hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());
+ }
+ if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {
p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
}
if (fd->face->style_name != nullptr) {
@@ -1452,7 +1469,6 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
}
- hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
// Get supported scripts from OpenType font data.
p_font_data->supported_scripts.clear();
unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);
@@ -6976,6 +6992,34 @@ String TextServerAdvanced::_string_to_lower(const String &p_string, const String
return String::utf16(lower.ptr(), len);
}
+String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {
+#ifndef ICU_STATIC_DATA
+ if (!icu_data_loaded) {
+ return p_string.capitalize();
+ }
+#endif
+
+ if (p_string.is_empty()) {
+ return p_string;
+ }
+ const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ Vector<char16_t> upper;
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
+ upper.resize(len);
+ err = U_ZERO_ERROR;
+ u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
+
+ // Convert back to UTF-32.
+ return String::utf16(upper.ptr(), len);
+}
+
PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 154fe670eb..160eb27528 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -991,6 +991,7 @@ public:
MODBIND2RC(String, string_to_upper, const String &, const String &);
MODBIND2RC(String, string_to_lower, const String &, const String &);
+ MODBIND2RC(String, string_to_title, const String &, const String &);
MODBIND0(cleanup);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 302bd677fe..c3f62d7324 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -71,8 +71,10 @@ using namespace godot;
#endif
#endif
-#ifdef MODULE_SVG_ENABLED
#ifdef MODULE_FREETYPE_ENABLED
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#ifdef MODULE_SVG_ENABLED
#include "thorvg_svg_in_ot.h"
#endif
#endif
@@ -857,8 +859,37 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
if (!p_font_data->face_init) {
- // Get style flags and name.
- if (fd->face->family_name != nullptr) {
+ // When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
+ // FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
+ // To avoid that behavior, use the format-specific name directly if available.
+ if (FT_IS_SFNT(fd->face)) {
+ int name_count = FT_Get_Sfnt_Name_Count(fd->face);
+ for (int i = 0; i < name_count; i++) {
+ FT_SfntName sfnt_name;
+ if (FT_Get_Sfnt_Name(fd->face, i, &sfnt_name) != 0) {
+ continue;
+ }
+ if (sfnt_name.name_id != TT_NAME_ID_FONT_FAMILY && sfnt_name.name_id != TT_NAME_ID_TYPOGRAPHIC_FAMILY) {
+ continue;
+ }
+ if (!p_font_data->font_name.is_empty() && sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES) {
+ continue;
+ }
+
+ switch (sfnt_name.platform_id) {
+ case TT_PLATFORM_APPLE_UNICODE: {
+ p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
+ } break;
+
+ case TT_PLATFORM_MICROSOFT: {
+ if (sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS || sfnt_name.encoding_id == TT_MS_ID_UCS_4) {
+ p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
+ }
+ } break;
+ }
+ }
+ }
+ if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {
p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
}
if (fd->face->style_name != nullptr) {
@@ -4439,6 +4470,10 @@ String TextServerFallback::_string_to_lower(const String &p_string, const String
return p_string.to_lower();
}
+String TextServerFallback::_string_to_title(const String &p_string, const String &p_language) const {
+ return p_string.capitalize();
+}
+
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
PackedInt32Array ret;
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 0db1f7318f..9fd5af8b51 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -848,6 +848,7 @@ public:
MODBIND2RC(String, string_to_upper, const String &, const String &);
MODBIND2RC(String, string_to_lower, const String &, const String &);
+ MODBIND2RC(String, string_to_title, const String &, const String &);
MODBIND0(cleanup);
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index a70ae1b9cc..82ac179611 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -71,7 +71,7 @@
<constant name="IGD_STATUS_HTTP_EMPTY" value="2" enum="IGDStatus">
Empty HTTP response.
</constant>
- <constant name="IGD_STATUS_NO_URLS" value="3" enum="IGDStatus">
+ <constant name="IGD_STATUS_NO_URLS" value="3" enum="IGDStatus" deprecated="This value is no longer used.">
Returned response contained no URLs.
</constant>
<constant name="IGD_STATUS_NO_IGD" value="4" enum="IGDStatus">
@@ -86,7 +86,7 @@
<constant name="IGD_STATUS_INVALID_CONTROL" value="7" enum="IGDStatus">
Invalid control.
</constant>
- <constant name="IGD_STATUS_MALLOC_ERROR" value="8" enum="IGDStatus">
+ <constant name="IGD_STATUS_MALLOC_ERROR" value="8" enum="IGDStatus" deprecated="This value is no longer used.">
Memory allocation error.
</constant>
<constant name="IGD_STATUS_UNKNOWN_ERROR" value="9" enum="IGDStatus">
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 2812f37eb2..95453c1ecd 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -121,33 +121,20 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
return;
}
- struct UPNPUrls *urls = (UPNPUrls *)malloc(sizeof(struct UPNPUrls));
-
- if (!urls) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_MALLOC_ERROR);
- return;
- }
-
+ struct UPNPUrls urls = {};
struct IGDdatas data;
- memset(urls, 0, sizeof(struct UPNPUrls));
-
parserootdesc(xml, size, &data);
free(xml);
xml = nullptr;
- GetUPNPUrls(urls, &data, dev->get_description_url().utf8().get_data(), 0);
-
- if (!urls) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_URLS);
- return;
- }
+ GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0);
char addr[16];
- int i = UPNP_GetValidIGD(devlist, urls, &data, (char *)&addr, 16);
+ int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16);
if (i != 1) {
- FreeUPNPUrls(urls);
+ FreeUPNPUrls(&urls);
switch (i) {
case 0:
@@ -165,18 +152,18 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
}
}
- if (urls->controlURL[0] == '\0') {
- FreeUPNPUrls(urls);
+ if (urls.controlURL[0] == '\0') {
+ FreeUPNPUrls(&urls);
dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL);
return;
}
- dev->set_igd_control_url(urls->controlURL);
+ dev->set_igd_control_url(urls.controlURL);
dev->set_igd_service_type(data.first.servicetype);
dev->set_igd_our_addr(addr);
dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
- FreeUPNPUrls(urls);
+ FreeUPNPUrls(&urls);
}
int UPNP::upnp_result(int in) {
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 7fce5359ae..b49475b0f2 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -595,6 +595,7 @@
Application version visible to the user. Falls back to [member ProjectSettings.application/config/version] if left empty.
</member>
<member name="xr_features/xr_mode" type="int" setter="" getter="">
+ The extended reality (XR) mode for this application.
</member>
</members>
</class>
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 64ef1397ba..19e215bfaf 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1920,7 +1920,15 @@ bool EditorExportPlatformAndroid::get_export_option_visibility(const EditorExpor
bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
if (p_option == "graphics/opengl_debug" ||
p_option == "command_line/extra_args" ||
- p_option == "permissions/custom_permissions") {
+ p_option == "permissions/custom_permissions" ||
+ p_option == "gradle_build/compress_native_libraries" ||
+ p_option == "package/retain_data_on_uninstall" ||
+ p_option == "package/exclude_from_recents" ||
+ p_option == "package/show_in_app_library" ||
+ p_option == "package/show_as_launcher_app" ||
+ p_option == "apk_expansion/enable" ||
+ p_option == "apk_expansion/SALT" ||
+ p_option == "apk_expansion/public_key") {
return advanced_options_enabled;
}
if (p_option == "gradle_build/gradle_build_directory" || p_option == "gradle_build/android_source_template") {
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index e540b7617f..2d98feb81b 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1895,7 +1895,7 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window)
return Size2();
}
-void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
// Windows docs for window styles:
// https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
// https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
@@ -1909,7 +1909,17 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
- if ((p_fullscreen && p_multiwindow_fs) || p_maximized) {
+ if (p_maximized) {
+ r_style |= WS_MAXIMIZE;
+ }
+ if (!p_fullscreen) {
+ r_style |= WS_SYSMENU | WS_MINIMIZEBOX;
+
+ if (p_resizable) {
+ r_style |= WS_MAXIMIZEBOX;
+ }
+ }
+ if ((p_fullscreen && p_multiwindow_fs) || p_maximized_fs) {
r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen.
}
} else {
@@ -1945,7 +1955,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
DWORD style = 0;
DWORD style_ex = 0;
- _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus || wd.is_popup, style, style_ex);
+ _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex);
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
@@ -1988,6 +1998,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
wd.pre_fs_valid = true;
}
+ ShowWindow(wd.hWnd, SW_RESTORE);
MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
if (restore_mouse_trails > 1) {
@@ -2023,7 +2034,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
}
if ((p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) && !wd.fullscreen) {
- if (wd.minimized) {
+ if (wd.minimized || wd.maximized) {
ShowWindow(wd.hWnd, SW_RESTORE);
}
wd.was_maximized = wd.maximized;
@@ -3709,63 +3720,18 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return MA_NOACTIVATE; // Do not activate, but process mouse messages.
}
} break;
- case WM_SETFOCUS: {
- windows[window_id].window_has_focus = true;
- last_focused_window = window_id;
-
- // Restore mouse mode.
- _set_mouse_mode_impl(mouse_mode);
-
- if (!app_focused) {
- if (OS::get_singleton()->get_main_loop()) {
- OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
- }
- app_focused = true;
- }
- } break;
- case WM_KILLFOCUS: {
- windows[window_id].window_has_focus = false;
- last_focused_window = window_id;
-
- // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
- ReleaseCapture();
-
- // Release every touch to avoid sticky points.
- for (const KeyValue<int, Vector2> &E : touch_state) {
- _touch_event(window_id, false, E.value.x, E.value.y, E.key);
- }
- touch_state.clear();
-
- bool self_steal = false;
- HWND new_hwnd = (HWND)wParam;
- if (IsWindow(new_hwnd)) {
- self_steal = true;
+ case WM_ACTIVATEAPP: {
+ bool new_app_focused = (bool)wParam;
+ if (new_app_focused == app_focused) {
+ break;
}
-
- if (!self_steal) {
- if (OS::get_singleton()->get_main_loop()) {
- OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
- }
- app_focused = false;
+ app_focused = new_app_focused;
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(app_focused ? MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN : MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
} break;
- case WM_ACTIVATE: { // Watch for window activate message.
- if (!windows[window_id].window_focused) {
- _process_activate_event(window_id, wParam, lParam);
- } else {
- windows[window_id].saved_wparam = wParam;
- windows[window_id].saved_lparam = lParam;
-
- // Run a timer to prevent event catching warning if the focused window is closing.
- windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
- }
- if (wParam != WA_INACTIVE) {
- track_mouse_leave_event(hWnd);
-
- if (!IsIconic(hWnd)) {
- SetFocus(hWnd);
- }
- }
+ case WM_ACTIVATE: {
+ _process_activate_event(window_id, wParam, lParam);
return 0; // Return to the message loop.
} break;
case WM_GETMINMAXINFO: {
@@ -3782,6 +3748,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
min_max_info->ptMaxTrackSize.x = windows[window_id].max_size.x + decor.x;
min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
}
+ if (windows[window_id].borderless) {
+ Rect2i screen_rect = screen_get_usable_rect(window_get_current_screen(window_id));
+
+ // Set the size of (borderless) maximized mode to exclude taskbar (or any other panel) if present.
+ min_max_info->ptMaxPosition.x = screen_rect.position.x;
+ min_max_info->ptMaxPosition.y = screen_rect.position.y;
+ min_max_info->ptMaxSize.x = screen_rect.size.x;
+ min_max_info->ptMaxSize.y = screen_rect.size.y;
+ }
return 0;
}
} break;
@@ -3833,9 +3808,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case SC_MONITORPOWER: // Monitor trying to enter powersave?
return 0; // Prevent from happening.
case SC_KEYMENU:
- if ((lParam >> 16) <= 0) {
+ Engine *engine = Engine::get_singleton();
+ if (((lParam >> 16) <= 0) && !engine->is_project_manager_hint() && !engine->is_editor_hint() && !GLOBAL_GET("application/run/enable_alt_space_menu")) {
+ return 0;
+ }
+ if (!alt_mem || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) {
return 0;
}
+ SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_SPACE, 0);
+ SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_MENU, 0);
}
} break;
case WM_INDICATOR_CALLBACK_MESSAGE: {
@@ -3864,9 +3845,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_CLOSE: // Did we receive a close message?
{
- if (windows[window_id].focus_timer_id != 0U) {
- KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id);
- }
_send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
return 0; // Jump back.
@@ -4569,10 +4547,23 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
window.minimized = true;
} else if (IsZoomed(hWnd)) {
window.maximized = true;
+
+ // If maximized_window_size == screen_size add 1px border to prevent switching to exclusive_fs.
+ if (!window.maximized_fs && window.borderless && window_rect.position == screen_position && window_rect.size == screen_size) {
+ // Window (borderless) was just maximized and the covers the entire screen.
+ window.maximized_fs = true;
+ _update_window_style(window_id, false);
+ }
} else if (window_rect.position == screen_position && window_rect.size == screen_size) {
window.fullscreen = true;
}
+ if (window.maximized_fs && !window.maximized) {
+ // Window (maximized and covering fullscreen) was just non-maximized.
+ window.maximized_fs = false;
+ _update_window_style(window_id, false);
+ }
+
if (!window.minimized) {
window.width = window_client_rect.size.width;
window.height = window_client_rect.size.height;
@@ -4625,10 +4616,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if (!Main::is_iterating()) {
Main::iteration();
}
- } else if (wParam == windows[window_id].focus_timer_id) {
- _process_activate_event(window_id, windows[window_id].saved_wparam, windows[window_id].saved_lparam);
- KillTimer(windows[window_id].hWnd, wParam);
- windows[window_id].focus_timer_id = 0U;
}
} break;
case WM_SYSKEYUP:
@@ -4834,20 +4821,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) {
if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
- _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN);
- windows[p_window_id].window_focused = true;
+ last_focused_window = p_window_id;
alt_mem = false;
control_mem = false;
shift_mem = false;
gr_mem = false;
-
- // Restore mouse mode.
_set_mouse_mode_impl(mouse_mode);
+ if (!IsIconic(windows[p_window_id].hWnd)) {
+ SetFocus(windows[p_window_id].hWnd);
+ }
+ windows[p_window_id].window_focused = true;
+ _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN);
} else { // WM_INACTIVE.
Input::get_singleton()->release_pressed_events();
- _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
- windows[p_window_id].window_focused = false;
+ track_mouse_leave_event(windows[p_window_id].hWnd);
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
+ ReleaseCapture();
alt_mem = false;
+ windows[p_window_id].window_focused = false;
+ _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
}
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) {
@@ -5051,7 +5043,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle;
DWORD dwStyle;
- _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
RECT WindowRect;
@@ -5284,6 +5276,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.height = p_rect.size.height;
}
+ // Set size of maximized borderless window (by default it covers the entire screen).
+ if (p_mode == WINDOW_MODE_MAXIMIZED && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
+ Rect2i srect = screen_get_usable_rect(rq_screen);
+ SetWindowPos(wd.hWnd, HWND_TOP, srect.position.x, srect.position.y, srect.size.width, srect.size.height, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
window_id_counter++;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 1191f22968..2f1309176d 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -382,6 +382,7 @@ class DisplayServerWindows : public DisplayServer {
bool pre_fs_valid = false;
RECT pre_fs_rect;
bool maximized = false;
+ bool maximized_fs = false;
bool minimized = false;
bool fullscreen = false;
bool multiwindow_fs = false;
@@ -402,7 +403,6 @@ class DisplayServerWindows : public DisplayServer {
// Timers.
uint32_t move_timer_id = 0U;
- uint32_t focus_timer_id = 0U;
HANDLE wtctx;
LOGCONTEXTW wtlc;
@@ -472,7 +472,7 @@ class DisplayServerWindows : public DisplayServer {
HashMap<IndicatorID, IndicatorData> indicators;
void _send_window_event(const WindowData &wd, WindowEvent p_event);
- void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
+ void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
MouseMode mouse_mode;
int restore_mouse_trails = 0;
diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
index 1239a2b32f..06b272c10e 100644
--- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml
+++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
@@ -4,6 +4,7 @@
Exporter for Windows.
</brief_description>
<description>
+ The Windows exporter customizes how a Windows build is handled. In the editor's "Export" window, it is created when adding a new "Windows" preset.
</description>
<tutorials>
<link title="Exporting for Windows">$DOCS_URL/tutorials/export/exporting_for_windows.html</link>
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index e9bab274c6..4b866fc6de 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -627,7 +627,7 @@ void Camera2D::align() {
}
void Camera2D::set_position_smoothing_speed(real_t p_speed) {
- position_smoothing_speed = p_speed;
+ position_smoothing_speed = MAX(0, p_speed);
_update_process_internal_for_smoothing();
}
@@ -636,7 +636,7 @@ real_t Camera2D::get_position_smoothing_speed() const {
}
void Camera2D::set_rotation_smoothing_speed(real_t p_speed) {
- rotation_smoothing_speed = p_speed;
+ rotation_smoothing_speed = MAX(0, p_speed);
_update_process_internal_for_smoothing();
}
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index caabb4225f..8415fb38cb 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -231,7 +231,7 @@ void Decal::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_emission", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION);
ADD_GROUP("Parameters", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix");
// A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface.
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 17dfbb4516..566801c9f7 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -1055,7 +1055,6 @@ void Skeleton3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
ADD_GROUP("Modifier", "modifier_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "modifier_reset_on_save", PROPERTY_HINT_NONE, ""), "set_modifier_reset_on_save_enabled", "is_modifier_reset_on_save_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "modifier_callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_modifier_callback_mode_process", "get_modifier_callback_mode_process");
ADD_SIGNAL(MethodInfo("pose_updated"));
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 757ac68e46..01e1de8f23 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -689,14 +689,19 @@ bool AnimationMixer::_update_caches() {
track_value->init_value = anim->track_get_key_value(i, 0);
track_value->init_value.zero();
+ track_value->init_use_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
+
// Can't interpolate them, need to convert.
track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);
// If there is a Reset Animation, it takes precedence by overwriting.
if (has_reset_anim) {
int rt = reset_anim->find_track(path, track_src_type);
- if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
+ if (rt >= 0) {
+ track_value->init_use_continuous = track_value->init_use_continuous || (reset_anim->value_track_get_update_mode(rt) != Animation::UPDATE_DISCRETE); // Take precedence Force Continuous.
+ if (reset_anim->track_get_key_count(rt) > 0) {
+ track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
+ }
}
}
@@ -996,6 +1001,7 @@ void AnimationMixer::_blend_init() {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
t->value = Animation::cast_to_blendwise(t->init_value);
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
+ t->use_continuous = t->init_use_continuous;
t->use_discrete = false;
} break;
case Animation::TYPE_AUDIO: {
@@ -1415,6 +1421,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE;
bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
if (t->is_variant_interpolatable && (!is_discrete || force_continuous)) {
+ t->use_continuous = true;
Variant value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time));
value = post_process_key_value(a, i, value, t->object_id);
if (value == Variant()) {
@@ -1727,7 +1734,7 @@ void AnimationMixer::_blend_apply() {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- if (!t->is_variant_interpolatable || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) {
+ if (!t->is_variant_interpolatable || !t->use_continuous || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) {
break; // Don't overwrite the value set by UPDATE_DISCRETE.
}
@@ -1969,6 +1976,7 @@ void AnimationMixer::_build_backup_track_cache() {
if (t_obj) {
t->value = Animation::cast_to_blendwise(t_obj->get_indexed(t->subpath));
}
+ t->use_continuous = true;
t->use_discrete = false;
if (t->init_value.is_array()) {
t->element_size = MAX(t->element_size.operator int(), (t->value.operator Array()).size());
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index ed291bfe63..b7898cffc9 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -222,9 +222,14 @@ protected:
Variant init_value;
Variant value;
Vector<StringName> subpath;
+
+ // TODO: There are many boolean, can be packed into one integer.
+ bool init_use_continuous = false;
+ bool use_continuous = false;
bool use_discrete = false;
bool is_using_angle = false;
bool is_variant_interpolatable = true;
+
Variant element_size;
TrackCacheValue(const TrackCacheValue &p_other) :
@@ -232,6 +237,8 @@ protected:
init_value(p_other.init_value),
value(p_other.value),
subpath(p_other.subpath),
+ init_use_continuous(p_other.init_use_continuous),
+ use_continuous(p_other.use_continuous),
use_discrete(p_other.use_discrete),
is_using_angle(p_other.is_using_angle),
is_variant_interpolatable(p_other.is_variant_interpolatable),
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 62bb14459d..f1a8c2f6ae 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -241,10 +241,6 @@ PackedStringArray Control::get_configuration_warnings() const {
warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
}
- if (get_z_index() != 0) {
- warnings.push_back(RTR("Changing the Z index of a control only affects the drawing order, not the input event handling order."));
- }
-
return warnings;
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 11c200064e..beb2583b61 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -3780,7 +3780,7 @@ void Node::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages");
ADD_GROUP("Physics Interpolation", "physics_interpolation_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_physics_interpolation_mode", "get_physics_interpolation_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,On,Off"), "set_physics_interpolation_mode", "get_physics_interpolation_mode");
ADD_GROUP("Auto Translate", "auto_translate_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "auto_translate_mode", PROPERTY_HINT_ENUM, "Inherit,Always,Disabled"), "set_auto_translate_mode", "get_auto_translate_mode");
@@ -3833,7 +3833,7 @@ Node::Node() {
data.unhandled_input = false;
data.unhandled_key_input = false;
- data.physics_interpolated = false;
+ data.physics_interpolated = true;
data.parent_owned = false;
data.in_constructor = true;
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index 24ed480289..2c1d3d4a4c 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -68,7 +68,7 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
} else if (what == "group") {
set_group(which, p_value);
} else if (what == "require") {
- set_require(which, p_value);
+ set_required(which, p_value);
} else {
return false;
}
@@ -113,7 +113,7 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
} else if (what == "group") {
r_ret = get_group(which);
} else if (what == "require") {
- r_ret = is_require(which);
+ r_ret = is_required(which);
} else {
return false;
}
@@ -299,7 +299,7 @@ SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_id
return bones[p_bone_idx].tail_direction;
}
-void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) {
+void SkeletonProfile::set_tail_direction(int p_bone_idx, TailDirection p_tail_direction) {
if (is_read_only) {
return;
}
@@ -328,7 +328,7 @@ Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const {
return bones[p_bone_idx].reference_pose;
}
-void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) {
+void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose) {
if (is_read_only) {
return;
}
@@ -342,7 +342,7 @@ Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const {
return bones[p_bone_idx].handle_offset;
}
-void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) {
+void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset) {
if (is_read_only) {
return;
}
@@ -365,17 +365,17 @@ void SkeletonProfile::set_group(int p_bone_idx, const StringName &p_group) {
emit_signal("profile_updated");
}
-bool SkeletonProfile::is_require(int p_bone_idx) const {
+bool SkeletonProfile::is_required(int p_bone_idx) const {
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false);
- return bones[p_bone_idx].require;
+ return bones[p_bone_idx].required;
}
-void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) {
+void SkeletonProfile::set_required(int p_bone_idx, bool p_required) {
if (is_read_only) {
return;
}
ERR_FAIL_INDEX(p_bone_idx, bones.size());
- bones.write[p_bone_idx].require = p_require;
+ bones.write[p_bone_idx].required = p_required;
emit_signal("profile_updated");
}
@@ -432,6 +432,9 @@ void SkeletonProfile::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group);
ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group);
+ ClassDB::bind_method(D_METHOD("is_required", "bone_idx"), &SkeletonProfile::is_required);
+ ClassDB::bind_method(D_METHOD("set_required", "bone_idx", "required"), &SkeletonProfile::set_required);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_root_bone", "get_root_bone");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "scale_base_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_scale_base_bone", "get_scale_base_bone");
@@ -478,14 +481,14 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0);
bones.write[1].handle_offset = Vector2(0.5, 0.5);
bones.write[1].group = "Body";
- bones.write[1].require = true;
+ bones.write[1].required = true;
bones.write[2].bone_name = "Spine";
bones.write[2].bone_parent = "Hips";
bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[2].handle_offset = Vector2(0.5, 0.43);
bones.write[2].group = "Body";
- bones.write[2].require = true;
+ bones.write[2].required = true;
bones.write[3].bone_name = "Chest";
bones.write[3].bone_parent = "Spine";
@@ -506,7 +509,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[5].handle_offset = Vector2(0.5, 0.23);
bones.write[5].group = "Body";
- bones.write[5].require = false;
+ bones.write[5].required = false;
bones.write[6].bone_name = "Head";
bones.write[6].bone_parent = "Neck";
@@ -514,7 +517,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[6].handle_offset = Vector2(0.5, 0.18);
bones.write[6].group = "Body";
- bones.write[6].require = true;
+ bones.write[6].required = true;
bones.write[7].bone_name = "LeftEye";
bones.write[7].bone_parent = "Head";
@@ -539,21 +542,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0);
bones.write[10].handle_offset = Vector2(0.55, 0.235);
bones.write[10].group = "Body";
- bones.write[10].require = true;
+ bones.write[10].required = true;
bones.write[11].bone_name = "LeftUpperArm";
bones.write[11].bone_parent = "LeftShoulder";
bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
bones.write[11].handle_offset = Vector2(0.6, 0.24);
bones.write[11].group = "Body";
- bones.write[11].require = true;
+ bones.write[11].required = true;
bones.write[12].bone_name = "LeftLowerArm";
bones.write[12].bone_parent = "LeftUpperArm";
bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
bones.write[12].handle_offset = Vector2(0.7, 0.24);
bones.write[12].group = "Body";
- bones.write[12].require = true;
+ bones.write[12].required = true;
bones.write[13].bone_name = "LeftHand";
bones.write[13].bone_parent = "LeftLowerArm";
@@ -562,7 +565,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
bones.write[13].handle_offset = Vector2(0.82, 0.235);
bones.write[13].group = "Body";
- bones.write[13].require = true;
+ bones.write[13].required = true;
bones.write[14].bone_name = "LeftThumbMetacarpal";
bones.write[14].bone_parent = "LeftHand";
@@ -659,21 +662,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0);
bones.write[29].handle_offset = Vector2(0.45, 0.235);
bones.write[29].group = "Body";
- bones.write[29].require = true;
+ bones.write[29].required = true;
bones.write[30].bone_name = "RightUpperArm";
bones.write[30].bone_parent = "RightShoulder";
bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
bones.write[30].handle_offset = Vector2(0.4, 0.24);
bones.write[30].group = "Body";
- bones.write[30].require = true;
+ bones.write[30].required = true;
bones.write[31].bone_name = "RightLowerArm";
bones.write[31].bone_parent = "RightUpperArm";
bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
bones.write[31].handle_offset = Vector2(0.3, 0.24);
bones.write[31].group = "Body";
- bones.write[31].require = true;
+ bones.write[31].required = true;
bones.write[32].bone_name = "RightHand";
bones.write[32].bone_parent = "RightLowerArm";
@@ -682,7 +685,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
bones.write[32].handle_offset = Vector2(0.18, 0.235);
bones.write[32].group = "Body";
- bones.write[32].require = true;
+ bones.write[32].required = true;
bones.write[33].bone_name = "RightThumbMetacarpal";
bones.write[33].bone_parent = "RightHand";
@@ -779,21 +782,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0);
bones.write[48].handle_offset = Vector2(0.549, 0.49);
bones.write[48].group = "Body";
- bones.write[48].require = true;
+ bones.write[48].required = true;
bones.write[49].bone_name = "LeftLowerLeg";
bones.write[49].bone_parent = "LeftUpperLeg";
bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
bones.write[49].handle_offset = Vector2(0.548, 0.683);
bones.write[49].group = "Body";
- bones.write[49].require = true;
+ bones.write[49].required = true;
bones.write[50].bone_name = "LeftFoot";
bones.write[50].bone_parent = "LeftLowerLeg";
bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
bones.write[50].handle_offset = Vector2(0.545, 0.9);
bones.write[50].group = "Body";
- bones.write[50].require = true;
+ bones.write[50].required = true;
bones.write[51].bone_name = "LeftToes";
bones.write[51].bone_parent = "LeftFoot";
@@ -806,21 +809,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0);
bones.write[52].handle_offset = Vector2(0.451, 0.49);
bones.write[52].group = "Body";
- bones.write[52].require = true;
+ bones.write[52].required = true;
bones.write[53].bone_name = "RightLowerLeg";
bones.write[53].bone_parent = "RightUpperLeg";
bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
bones.write[53].handle_offset = Vector2(0.452, 0.683);
bones.write[53].group = "Body";
- bones.write[53].require = true;
+ bones.write[53].required = true;
bones.write[54].bone_name = "RightFoot";
bones.write[54].bone_parent = "RightLowerLeg";
bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
bones.write[54].handle_offset = Vector2(0.455, 0.9);
bones.write[54].group = "Body";
- bones.write[54].require = true;
+ bones.write[54].required = true;
bones.write[55].bone_name = "RightToes";
bones.write[55].bone_parent = "RightFoot";
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index 143f495c61..b5a3bce940 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -61,7 +61,7 @@ protected:
Transform3D reference_pose;
Vector2 handle_offset;
StringName group;
- bool require = false;
+ bool required = false;
};
StringName root_bone;
@@ -104,22 +104,22 @@ public:
void set_bone_parent(int p_bone_idx, const StringName &p_bone_parent);
TailDirection get_tail_direction(int p_bone_idx) const;
- void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction);
+ void set_tail_direction(int p_bone_idx, TailDirection p_tail_direction);
StringName get_bone_tail(int p_bone_idx) const;
void set_bone_tail(int p_bone_idx, const StringName &p_bone_tail);
Transform3D get_reference_pose(int p_bone_idx) const;
- void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose);
+ void set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose);
Vector2 get_handle_offset(int p_bone_idx) const;
- void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
+ void set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset);
StringName get_group(int p_bone_idx) const;
void set_group(int p_bone_idx, const StringName &p_group);
- bool is_require(int p_bone_idx) const;
- void set_require(int p_bone_idx, const bool p_require);
+ bool is_required(int p_bone_idx) const;
+ void set_required(int p_bone_idx, bool p_required);
bool has_bone(const StringName &p_bone_name);
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index 7ab1d399fb..d1d8854b18 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -639,7 +639,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
// AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
- theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale)));
+ theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), 0));
theme->set_constant("buttons_separation", "AcceptDialog", Math::round(10 * scale));
// File Dialog
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 b54f511d05..48c9cda253 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -777,7 +777,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
// can't do blit subpass because we're scaling
using_subpass_post_process = false;
- } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
+ } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes) || environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) {
// can't do blit subpass because we're using post processes
using_subpass_post_process = false;
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 7dfff0b76f..00291d2ac4 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -5089,7 +5089,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
draw_list = nullptr;
compute_list = nullptr;
- if (main_instance) {
+ bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");
+ if (main_instance && project_pipeline_cache_enable) {
// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.
pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",
OS::get_singleton()->get_current_rendering_method(),
@@ -5223,8 +5224,12 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
case DRIVER_RESOURCE_LOGICAL_DEVICE:
case DRIVER_RESOURCE_PHYSICAL_DEVICE:
case DRIVER_RESOURCE_TOPMOST_OBJECT:
+ break;
case DRIVER_RESOURCE_COMMAND_QUEUE:
+ driver_id = main_queue.id;
+ break;
case DRIVER_RESOURCE_QUEUE_FAMILY:
+ driver_id = main_queue_family.id;
break;
case DRIVER_RESOURCE_TEXTURE:
case DRIVER_RESOURCE_TEXTURE_VIEW:
@@ -5232,19 +5237,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
Texture *tex = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(tex, 0);
- driver_id = tex->driver_id;
+ driver_id = tex->driver_id.id;
} break;
case DRIVER_RESOURCE_SAMPLER: {
RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(sampler_driver_id, 0);
- driver_id = *sampler_driver_id;
+ driver_id = (*sampler_driver_id).id;
} break;
case DRIVER_RESOURCE_UNIFORM_SET: {
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(uniform_set, 0);
- driver_id = uniform_set->driver_id;
+ driver_id = uniform_set->driver_id.id;
} break;
case DRIVER_RESOURCE_BUFFER: {
Buffer *buffer = nullptr;
@@ -5261,19 +5266,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
}
ERR_FAIL_NULL_V(buffer, 0);
- driver_id = buffer->driver_id;
+ driver_id = buffer->driver_id.id;
} break;
case DRIVER_RESOURCE_COMPUTE_PIPELINE: {
ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(compute_pipeline, 0);
- driver_id = compute_pipeline->driver_id;
+ driver_id = compute_pipeline->driver_id.id;
} break;
case DRIVER_RESOURCE_RENDER_PIPELINE: {
RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(render_pipeline, 0);
- driver_id = render_pipeline->driver_id;
+ driver_id = render_pipeline->driver_id.id;
} break;
default: {
ERR_FAIL_V(0);
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index 09a0412941..e9464ba321 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -128,7 +128,7 @@ public:
#define DEFINE_ID(m_name) \
struct m_name##ID : public ID { \
- _ALWAYS_INLINE_ operator bool() const { return id != 0; } \
+ _ALWAYS_INLINE_ explicit operator bool() const { return id != 0; } \
_ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) { \
id = p_other.id; \
return *this; \
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index 4b85d1c2bf..adac7ee3eb 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -261,7 +261,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
}
if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) {
- if (resource_tracker->parent->texture_driver_id != 0) {
+ if (resource_tracker->parent->texture_driver_id.id != 0) {
// If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it.
_add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
}
@@ -324,7 +324,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command.");
} else {
// Delete the slice from the dirty list and revert it to the usage of the parent.
- if (current_tracker->texture_driver_id != 0) {
+ if (current_tracker->texture_driver_id.id != 0) {
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
// Merge the area of the slice with the current tracking area of the command and indicate it's a write usage as well.
@@ -383,7 +383,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
while (current_tracker != nullptr) {
current_tracker->reset_if_outdated(tracking_frame);
- if (current_tracker->texture_driver_id != 0) {
+ if (current_tracker->texture_driver_id.id != 0) {
// Transition all slices to the layout of the parent resource.
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
}
diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp
index fdf0d73654..0889898f0b 100644
--- a/servers/rendering/rendering_light_culler.cpp
+++ b/servers/rendering/rendering_light_culler.cpp
@@ -427,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
uint8_t *entry = &data.LUT_entries[lookup][0];
int n_edges = data.LUT_entry_sizes[lookup] - 1;
+ const Vector3 &pt2 = p_light_source.pos;
+
for (int e = 0; e < n_edges; e++) {
int i0 = entry[e];
int i1 = entry[e + 1];
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
// Last to 0 edge.
@@ -446,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
#ifdef LIGHT_CULLER_DEBUG_LOGGING
diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h
index 602543850a..0bf975430b 100644
--- a/servers/rendering/rendering_light_culler.h
+++ b/servers/rendering/rendering_light_culler.h
@@ -163,6 +163,39 @@ private:
bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1);
+ // Avoid adding extra culling planes derived from near colinear triangles.
+ // The normals derived from these will be inaccurate, and can lead to false
+ // culling of objects that should be within the light volume.
+ bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const {
+ // Lengths of sides a, b and c.
+ float la = (p_b - p_a).length();
+ float lb = (p_c - p_b).length();
+ float lc = (p_c - p_a).length();
+
+ // Get longest side into lc.
+ if (lb < la) {
+ SWAP(la, lb);
+ }
+ if (lc < lb) {
+ SWAP(lb, lc);
+ }
+
+ // Prevent divide by zero.
+ if (lc > 0.00001f) {
+ // If the summed length of the smaller two
+ // sides is close to the length of the longest side,
+ // the points are colinear, and the triangle is near degenerate.
+ float ld = ((la + lb) - lc) / lc;
+
+ // ld will be close to zero for colinear tris.
+ return ld < 0.00001f;
+ }
+
+ // Don't create planes from tiny triangles,
+ // they won't be accurate.
+ return true;
+ }
+
// Internal version uses LightSource.
bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index eb9f1c1484..53e1d119fd 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -341,6 +341,7 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_string_to_upper, "string", "language");
GDVIRTUAL_BIND(_string_to_lower, "string", "language");
+ GDVIRTUAL_BIND(_string_to_title, "string", "language");
GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text");
@@ -1507,6 +1508,14 @@ String TextServerExtension::string_to_upper(const String &p_string, const String
return p_string;
}
+String TextServerExtension::string_to_title(const String &p_string, const String &p_language) const {
+ String ret;
+ if (GDVIRTUAL_CALL(_string_to_title, p_string, p_language, ret)) {
+ return ret;
+ }
+ return p_string;
+}
+
String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const {
String ret;
if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) {
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 84d68de4fa..53d30abee4 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -566,8 +566,10 @@ public:
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+ virtual String string_to_title(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
+ GDVIRTUAL2RC(String, _string_to_title, const String &, const String &);
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 078ee27753..fac9e32d01 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -491,6 +491,7 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL(""));
ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("string_to_title", "string", "language"), &TextServer::string_to_title, DEFVAL(""));
ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text);
diff --git a/servers/text_server.h b/servers/text_server.h
index 4a16ae64e8..396d7ca8e5 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -546,6 +546,7 @@ public:
// Other string operations.
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
+ virtual String string_to_title(const String &p_string, const String &p_language = "") const = 0;
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index f23fffe5eb..fc3fd6a87d 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -354,6 +354,7 @@ TEST_CASE("[Vector2] Plane methods") {
const Vector2 vector_y = Vector2(0, 1);
const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919);
const Vector2 vector_non_normal = Vector2(5.4, 1.6);
+ const real_t p_d = 99.1;
CHECK_MESSAGE(
vector.bounce(vector_y) == Vector2(1.2, -3.4),
"Vector2 bounce on a plane with normal of the Y axis should.");
@@ -373,6 +374,9 @@ TEST_CASE("[Vector2] Plane methods") {
vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)),
"Vector2 projected on a normal should return expected value.");
CHECK_MESSAGE(
+ vector_normal.plane_project(p_d, vector).is_equal_approx(Vector2(94.187635516479631, 30.951892004882851)),
+ "Vector2 plane_project should return expected value.");
+ CHECK_MESSAGE(
vector.slide(vector_y) == Vector2(1.2, 0),
"Vector2 slide on a plane with normal of the Y axis should set the Y to zero.");
CHECK_MESSAGE(
diff --git a/thirdparty/README.md b/thirdparty/README.md
index be386a3920..8fabe8a893 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -87,7 +87,7 @@ Files extracted from upstream source:
## certs
- Upstream: Mozilla, via https://github.com/bagder/ca-bundle
-- Version: git (bef37a977ccb45fb4c1b213b79dd6ba438077561, 2023)
+- Version: git (c5a419971b1bec220368c619aaafd0b818aa119f, 2024)
- License: MPL 2.0
@@ -194,7 +194,7 @@ commits.
## enet
- Upstream: https://github.com/lsalzman/enet
-- Version: git (ea4607a90dbfbcf4da2669ea998585253d8e70b1, 2023)
+- Version: git (c44b7d0f7ff21edb702745e4c019d0537928c373, 2024)
- License: MIT
Files extracted from upstream source:
@@ -838,11 +838,13 @@ folder.
Files extracted from upstream source:
+- `LICENSE.txt`
- All `.cpp`, `.h` and `.inl` files
-Important: Some files have Godot-made changes.
-They are marked with `// -- GODOT start --` and `// -- GODOT end --`
-comments and a patch is provided in the squish/ folder.
+Some downstream changes have been made and are identified by
+`// -- GODOT begin --` and `// -- GODOT end --` comments.
+They can be reapplied using the patches included in the `patches`
+folder.
## tinyexr
diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt
index df7a026bed..f437587091 100644
--- a/thirdparty/certs/ca-certificates.crt
+++ b/thirdparty/certs/ca-certificates.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Dec 13 07:16:08 2023 GMT
+## Certificate data from Mozilla as of: Mon Mar 11 15:15:21 2024 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
-## SHA256: 1970dd65858925d68498d2356aea6d03f764422523c5887deca8ce3ba9e1f845
+## SHA256: 4d96bd539f4719e9ace493757afbe4a23ee8579de1c97fbebc50bba3c12e8c1e
##
@@ -3532,3 +3532,50 @@ dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ
iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN
lM47ni3niAIi9G7oyOzWPPO5std3eqx7
-----END CERTIFICATE-----
+
+Telekom Security TLS ECC Root 2020
+==================================
+-----BEGIN CERTIFICATE-----
+MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE
+RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl
+a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz
+NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg
+R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG
+SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1
+2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC
+MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ
+Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU
+ga/sf+Rn27iQ7t0l
+-----END CERTIFICATE-----
+
+Telekom Security TLS RSA Root 2023
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG
+EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU
+ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy
+NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp
+dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC
+KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP
+GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx
+UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo
+l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9
+FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v
+zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg
+rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML
+KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S
+WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
+p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+
+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp
+kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy
+/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4
+mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz
+aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa
+oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8
+wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE
+HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0
+o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
+-----END CERTIFICATE-----
diff --git a/thirdparty/enet/patches/godot_socket.patch b/thirdparty/enet/patches/godot_socket.patch
index 364b3536be..d0fb97fb92 100644
--- a/thirdparty/enet/patches/godot_socket.patch
+++ b/thirdparty/enet/patches/godot_socket.patch
@@ -1,5 +1,5 @@
diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
-index fc45cbd0c9..77f8004b80 100644
+index 4a207041b3..5232f8a869 100644
--- a/thirdparty/enet/enet/enet.h
+++ b/thirdparty/enet/enet/enet.h
@@ -10,13 +10,19 @@ extern "C"
@@ -22,7 +22,7 @@ index fc45cbd0c9..77f8004b80 100644
#include "enet/types.h"
#include "enet/protocol.h"
-@@ -86,11 +92,15 @@ typedef enum _ENetSocketShutdown
+@@ -87,11 +93,15 @@ typedef enum _ENetSocketShutdown
* but not for enet_host_create. Once a server responds to a broadcast, the
* address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
*/
@@ -38,7 +38,7 @@ index fc45cbd0c9..77f8004b80 100644
/**
* Packet flag bit constants.
-@@ -604,6 +614,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t,
+@@ -608,6 +618,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t,
extern size_t enet_protocol_command_size (enet_uint8);
@@ -50,7 +50,7 @@ index fc45cbd0c9..77f8004b80 100644
}
#endif
diff --git a/thirdparty/enet/host.c b/thirdparty/enet/host.c
-index 3b2180f7fd..21ab27e247 100644
+index fff946a392..adb3533cf1 100644
--- a/thirdparty/enet/host.c
+++ b/thirdparty/enet/host.c
@@ -87,7 +87,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
@@ -63,10 +63,10 @@ index 3b2180f7fd..21ab27e247 100644
host -> receivedData = NULL;
host -> receivedDataLength = 0;
diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c
-index 9d654f1d96..d7fe80f117 100644
+index 843a719af3..5f18700599 100644
--- a/thirdparty/enet/protocol.c
+++ b/thirdparty/enet/protocol.c
-@@ -309,7 +309,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
+@@ -318,7 +318,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
}
else
if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
@@ -75,7 +75,7 @@ index 9d654f1d96..d7fe80f117 100644
{
if (currentPeer -> address.port == host -> receivedAddress.port &&
currentPeer -> connectID == command -> connect.connectID)
-@@ -1031,9 +1031,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+@@ -1043,9 +1043,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
peer -> state == ENET_PEER_STATE_ZOMBIE ||
@@ -87,7 +87,7 @@ index 9d654f1d96..d7fe80f117 100644
(peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
sessionID != peer -> incomingSessionID))
return 0;
-@@ -1075,7 +1074,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+@@ -1090,7 +1089,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer != NULL)
{
diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c
index af307af7e5..5f18700599 100644
--- a/thirdparty/enet/protocol.c
+++ b/thirdparty/enet/protocol.c
@@ -1071,11 +1071,14 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (host -> checksum != NULL)
{
- enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)],
- desiredChecksum = * checksum;
+ enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)];
+ enet_uint32 desiredChecksum, newChecksum;
ENetBuffer buffer;
+ /* Checksum may be an unaligned pointer, use memcpy to avoid undefined behaviour. */
+ memcpy (& desiredChecksum, checksum, sizeof (enet_uint32));
- * checksum = peer != NULL ? peer -> connectID : 0;
+ newChecksum = peer != NULL ? peer -> connectID : 0;
+ memcpy (checksum, & newChecksum, sizeof (enet_uint32));
buffer.data = host -> receivedData;
buffer.dataLength = host -> receivedDataLength;
@@ -1703,9 +1706,12 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
if (host -> checksum != NULL)
{
enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength];
- * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0;
+ enet_uint32 newChecksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0;
+ /* Checksum may be unaligned, use memcpy to avoid undefined behaviour. */
+ memcpy(checksum, & newChecksum, sizeof (enet_uint32));
host -> buffers -> dataLength += sizeof (enet_uint32);
- * checksum = host -> checksum (host -> buffers, host -> bufferCount);
+ newChecksum = host -> checksum (host -> buffers, host -> bufferCount);
+ memcpy(checksum, & newChecksum, sizeof (enet_uint32));
}
if (shouldCompress > 0)
diff --git a/thirdparty/squish/LICENSE.txt b/thirdparty/squish/LICENSE.txt
new file mode 100644
index 0000000000..e491e36226
--- /dev/null
+++ b/thirdparty/squish/LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2006 Simon Brown si@sjbrown.co.uk
+
+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.
diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch
deleted file mode 100644
index 555fbc51d0..0000000000
--- a/thirdparty/squish/godot-changes.patch
+++ /dev/null
@@ -1,211 +0,0 @@
-diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
-index af8b98036..3d87adaa7 100644
---- a/thirdparty/squish/colourblock.cpp
-+++ b/thirdparty/squish/colourblock.cpp
-@@ -24,6 +24,9 @@
- -------------------------------------------------------------------------- */
-
- #include "colourblock.h"
-+// -- Godot start --
-+#include "alpha.h"
-+// -- Godot end --
-
- namespace squish {
-
-@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
- }
- }
-
-+// -- Godot start --
-+void DecompressColourBc5( u8* rgba, void const* block)
-+{
-+ void const* rblock = block;
-+ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
-+ DecompressAlphaDxt5(rgba,rblock);
-+ for ( int i = 0; i < 16; ++i ) {
-+ rgba[i*4] = rgba[i*4 + 3];
-+ }
-+ DecompressAlphaDxt5(rgba,gblock);
-+ for ( int i = 0; i < 16; ++i ) {
-+ rgba[i*4+1] = rgba[i*4 + 3];
-+ rgba[i*4 + 2] = 0;
-+ rgba[i*4 + 3] = 255;
-+ }
-+}
-+// -- GODOT end --
-+
-+
- } // namespace squish
-diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
-index fee2cd7c5..3cb9b7e3b 100644
---- a/thirdparty/squish/colourblock.h
-+++ b/thirdparty/squish/colourblock.h
-@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
- void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
-
- void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
-+// -- GODOT start --
-+void DecompressColourBc5( u8* rgba, void const* block );
-+// -- GODOT end --
-
- } // namespace squish
-
-diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
-index 92edefe96..05f8d7259 100644
---- a/thirdparty/squish/config.h
-+++ b/thirdparty/squish/config.h
-@@ -32,6 +32,26 @@
- #endif
-
- // Set to 1 or 2 when building squish to use SSE or SSE2 instructions.
-+// -- GODOT start --
-+#ifdef _MSC_VER
-+ #if defined(_M_IX86_FP)
-+ #if _M_IX86_FP >= 2
-+ #define SQUISH_USE_SSE 2
-+ #elif _M_IX86_FP >= 1
-+ #define SQUISH_USE_SSE 1
-+ #endif
-+ #elif defined(_M_X64)
-+ #define SQUISH_USE_SSE 2
-+ #endif
-+#else
-+ #if defined(__SSE2__)
-+ #define SQUISH_USE_SSE 2
-+ #elif defined(__SSE__)
-+ #define SQUISH_USE_SSE 1
-+ #endif
-+#endif
-+// -- GODOT end --
-+
- #ifndef SQUISH_USE_SSE
- #define SQUISH_USE_SSE 0
- #endif
-diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
-index 1d22a64ad..fd11a147d 100644
---- a/thirdparty/squish/squish.cpp
-+++ b/thirdparty/squish/squish.cpp
-@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
- colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
-
- // decompress colour
-- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT start --
-+ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ if(( flags & ( kBc5 ) ) != 0)
-+ DecompressColourBc5( rgba, colourBlock);
-+ else
-+ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT end --
-
- // decompress alpha separately if necessary
- if( ( flags & kDxt3 ) != 0 )
-
-diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
-index 49401358bc..f14c9362bd 100644
---- a/thirdparty/squish/colourblock.cpp
-+++ b/thirdparty/squish/colourblock.cpp
-@@ -24,9 +24,9 @@
- -------------------------------------------------------------------------- */
-
- #include "colourblock.h"
--// -- Godot start --
-+// -- GODOT start --
- #include "alpha.h"
--// -- Godot end --
-+// -- GODOT end --
-
- namespace squish {
-
-diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch
-index ef7bafb4b4..655a8cffc2 100644
---- a/thirdparty/squish/godot-changes.patch
-+++ b/thirdparty/squish/godot-changes.patch
-@@ -1,22 +1,33 @@
- diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
--index af8b98036..3d87adaa7 100644
-+index af8b980365..f14c9362bd 100644
- --- a/thirdparty/squish/colourblock.cpp
- +++ b/thirdparty/squish/colourblock.cpp
- @@ -24,6 +24,9 @@
- -------------------------------------------------------------------------- */
-
- #include "colourblock.h"
--+// -- Godot start --
-++// -- GODOT start --
- +#include "alpha.h"
--+// -- Godot end --
-++// -- GODOT end --
-
- namespace squish {
-
--@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
-+@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
- }
- }
-
--+// -- Godot start --
-++// -- GODOT start --
-++void DecompressColourBc4( u8* rgba, void const* block)
-++{
-++ DecompressAlphaDxt5(rgba,block);
-++ for ( int i = 0; i < 16; ++i ) {
-++ rgba[i*4] = rgba[i*4 + 3];
-++ rgba[i*4 + 1] = 0;
-++ rgba[i*4 + 2] = 0;
-++ rgba[i*4 + 3] = 255;
-++ }
-++}
-++
- +void DecompressColourBc5( u8* rgba, void const* block)
- +{
- + void const* rblock = block;
-@@ -37,21 +48,22 @@ index af8b98036..3d87adaa7 100644
- +
- } // namespace squish
- diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
--index fee2cd7c5..3cb9b7e3b 100644
-+index fee2cd7c5d..e1eb9e4917 100644
- --- a/thirdparty/squish/colourblock.h
- +++ b/thirdparty/squish/colourblock.h
--@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
-+@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
- void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
-
- void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
- +// -- GODOT start --
-++void DecompressColourBc4( u8* rgba, void const* block );
- +void DecompressColourBc5( u8* rgba, void const* block );
- +// -- GODOT end --
-
- } // namespace squish
-
- diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
--index 92edefe96..05f8d7259 100644
-+index 92edefe966..05f8d72598 100644
- --- a/thirdparty/squish/config.h
- +++ b/thirdparty/squish/config.h
- @@ -32,6 +32,26 @@
-@@ -82,17 +94,19 @@ index 92edefe96..05f8d7259 100644
- #define SQUISH_USE_SSE 0
- #endif
- diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
--index 1d22a64ad..fd11a147d 100644
-+index 1d22a64ad6..086ba11cd0 100644
- --- a/thirdparty/squish/squish.cpp
- +++ b/thirdparty/squish/squish.cpp
--@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
-+@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags )
- colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
-
- // decompress colour
- - DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
- + // -- GODOT start --
- + //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
--+ if(( flags & ( kBc5 ) ) != 0)
-++ if(( flags & ( kBc4 ) ) != 0)
-++ DecompressColourBc4( rgba, colourBlock);
-++ else if(( flags & ( kBc5 ) ) != 0)
- + DecompressColourBc5( rgba, colourBlock);
- + else
- + DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); \ No newline at end of file
diff --git a/thirdparty/squish/patches/config_sse.patch b/thirdparty/squish/patches/config_sse.patch
new file mode 100644
index 0000000000..047701ee32
--- /dev/null
+++ b/thirdparty/squish/patches/config_sse.patch
@@ -0,0 +1,31 @@
+diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
+index 92edefe966..05f8d72598 100644
+--- a/thirdparty/squish/config.h
++++ b/thirdparty/squish/config.h
+@@ -32,6 +32,26 @@
+ #endif
+
+ // Set to 1 or 2 when building squish to use SSE or SSE2 instructions.
++// -- GODOT start --
++#ifdef _MSC_VER
++ #if defined(_M_IX86_FP)
++ #if _M_IX86_FP >= 2
++ #define SQUISH_USE_SSE 2
++ #elif _M_IX86_FP >= 1
++ #define SQUISH_USE_SSE 1
++ #endif
++ #elif defined(_M_X64)
++ #define SQUISH_USE_SSE 2
++ #endif
++#else
++ #if defined(__SSE2__)
++ #define SQUISH_USE_SSE 2
++ #elif defined(__SSE__)
++ #define SQUISH_USE_SSE 1
++ #endif
++#endif
++// -- GODOT end --
++
+ #ifndef SQUISH_USE_SSE
+ #define SQUISH_USE_SSE 0
+ #endif
diff --git a/thirdparty/squish/patches/decompress_bc4_bc5.patch b/thirdparty/squish/patches/decompress_bc4_bc5.patch
new file mode 100644
index 0000000000..949375560c
--- /dev/null
+++ b/thirdparty/squish/patches/decompress_bc4_bc5.patch
@@ -0,0 +1,85 @@
+diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
+index af8b980365..f14c9362bd 100644
+--- a/thirdparty/squish/colourblock.cpp
++++ b/thirdparty/squish/colourblock.cpp
+@@ -24,6 +24,9 @@
+ -------------------------------------------------------------------------- */
+
+ #include "colourblock.h"
++// -- GODOT start --
++#include "alpha.h"
++// -- GODOT end --
+
+ namespace squish {
+
+@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
+ }
+ }
+
++// -- GODOT start --
++void DecompressColourBc4( u8* rgba, void const* block)
++{
++ DecompressAlphaDxt5(rgba,block);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4] = rgba[i*4 + 3];
++ rgba[i*4 + 1] = 0;
++ rgba[i*4 + 2] = 0;
++ rgba[i*4 + 3] = 255;
++ }
++}
++
++void DecompressColourBc5( u8* rgba, void const* block)
++{
++ void const* rblock = block;
++ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
++ DecompressAlphaDxt5(rgba,rblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4] = rgba[i*4 + 3];
++ }
++ DecompressAlphaDxt5(rgba,gblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4+1] = rgba[i*4 + 3];
++ rgba[i*4 + 2] = 0;
++ rgba[i*4 + 3] = 255;
++ }
++}
++// -- GODOT end --
++
++
+ } // namespace squish
+diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
+index fee2cd7c5d..e1eb9e4917 100644
+--- a/thirdparty/squish/colourblock.h
++++ b/thirdparty/squish/colourblock.h
+@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
+ void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
+
+ void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
++// -- GODOT start --
++void DecompressColourBc4( u8* rgba, void const* block );
++void DecompressColourBc5( u8* rgba, void const* block );
++// -- GODOT end --
+
+ } // namespace squish
+
+diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
+index 1d22a64ad6..086ba11cd0 100644
+--- a/thirdparty/squish/squish.cpp
++++ b/thirdparty/squish/squish.cpp
+@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags )
+ colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
+
+ // decompress colour
+- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT start --
++ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ if(( flags & ( kBc4 ) ) != 0)
++ DecompressColourBc4( rgba, colourBlock);
++ else if(( flags & ( kBc5 ) ) != 0)
++ DecompressColourBc5( rgba, colourBlock);
++ else
++ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT end --
+
+ // decompress alpha separately if necessary
+ if( ( flags & kDxt3 ) != 0 )