Compare commits

...

No commits in common. "development" and "archive/old-template" have entirely different histories.

3091 changed files with 345826 additions and 212101 deletions

15
.gitattributes vendored
View file

@ -1,15 +0,0 @@
*.blend filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.scn filter=lfs diff=lfs merge=lfs -text
*.res filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.x86_64 filter=lfs diff=lfs merge=lfs -text

0
.gitmodules vendored Normal file
View file

View file

@ -1,3 +1,6 @@
# If you change this file, please format all files of the codebase as part of your PR:
# pre-commit run clang-format --all
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 18.1.8).
@ -38,7 +41,7 @@ AlignAfterOpenBracket: DontAlign
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCaseColons: false
# AlignEscapedNewlines: Right
AlignEscapedNewlines: DontAlign # Aligning leads to long diffs
AlignOperands: DontAlign
AlignTrailingComments:
Kind: Never

View file

@ -1,21 +1,25 @@
# If you change this file, please format all files of the codebase as part of your PR:
# pre-commit run --hook-stage manual clang-tidy --all
Checks:
- -*
- cppcoreguidelines-pro-type-member-init
- bugprone-use-after-move
- modernize-deprecated-headers
- modernize-redundant-void-arg
- modernize-use-bool-literals
- modernize-use-default-member-init
# - modernize-use-default-member-init # TODO Re-activate
- modernize-use-nullptr
- readability-braces-around-statements
- readability-redundant-member-init
- readability-operators-representation
HeaderFileExtensions: ["", h, hh, hpp, hxx, inc, glsl]
ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
FormatStyle: file
CheckOptions:
cppcoreguidelines-pro-type-member-init.IgnoreArrays: true
cppcoreguidelines-pro-type-member-init.UseAssignment: true
modernize-deprecated-headers.CheckHeaderFile: true
modernize-use-bool-literals.IgnoreMacros: false
modernize-use-default-member-init.IgnoreMacros: false
modernize-use-default-member-init.UseAssignment: true
readability-operators-representation.BinaryOperators: "&&;&=;&;|;~;!;!=;||;|=;^;^="
readability-operators-representation.OverloadedOperators: "&&;&=;&;|;~;!;!=;||;|=;^;^="

View file

@ -72,3 +72,18 @@ e06d83860d798b6766b23d6eae48557387a7db85
# Style: Replace header guards with `#pragma once`
324512e11c1b7663c3cf47bec6ddbe65c6b8db2b
# Style: Don't right-align escaped newlines
c5df0cb82bc539eff7dcfb2add99d60771fc50c5
# Style: Convert `*.gen.inc` to `*.gen.h`
7dae5da1982f4a55ba91557814905faef9ce461b
# Move RenderingServer enums to a dedicated RenderingServerEnums (`RSE`) namespace
f5a290ac462765afca34e64dd39f883511510147
# Style: Add `class_db.h` includes explicitly
e380a417526c11f15a9ddb3997292409b10da2af
# Move DisplayServer enums and typedefs to DisplayServerEnums
a447ac95ec170ee117c2eae55f1bfff0d0cf0dce

View file

@ -1,8 +1,6 @@
<!--
Please target the `master` branch in priority.
Please target the `master` branch. We will take care of backporting relevant fixes to older versions.
Relevant fixes are cherry-picked for stable branches as needed by maintainers.
To speed up the contribution process and avoid CI errors, please set up pre-commit hooks locally:
https://contributing.godotengine.org/en/latest/engine/guidelines/code_style.html
Before submitting, please read our checklist for new contributors:
https://contributing.godotengine.org/en/latest/engine/introduction.html#checklist-for-new-contributors
-->

View file

@ -12,7 +12,7 @@ runs:
using: composite
steps:
- name: Restore default cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-ping
with:
path: ${{ inputs.scons-cache }}
@ -27,7 +27,7 @@ runs:
# This is done after pulling the default cache so that PRs can integrate any potential changes
# from the default branch without conflicting with whatever local changes were already made.
- name: Restore local cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
if: github.ref_name != github.event.repository.default_branch
with:
path: ${{ inputs.scons-cache }}

View file

@ -16,7 +16,7 @@ runs:
run: misc/scripts/purge_cache.py ${{ env.CACHE_TIMESTAMP }} "${{ inputs.scons-cache }}"
- name: Save SCons cache directory
uses: actions/cache/save@v5
uses: actions/cache/save@v4
with:
path: ${{ inputs.scons-cache }}
key: ${{ inputs.cache-name }}|${{ github.ref_name }}|${{ github.sha }}

View file

@ -0,0 +1,33 @@
name: Godot hash compatibility test
description: Check if methods with given hashes used by the older GDExtensions still can be loaded with given Godot version.
inputs:
bin:
description: Path to the Godot binary.
required: true
type: string
reftags:
description: Reference tags of Godot versions to check (comma separated).
required: true
type: string
runs:
using: composite
steps:
- name: Extract GDExtension interface
shell: sh
run: |
${{ inputs.bin }} --headless --dump-gdextension-interface
mkdir tests/compatibility_test/src/deps/
mv gdextension_interface.h tests/compatibility_test/src/deps/
- name: Build minimal GDExtension
shell: sh
run: scons --directory=./tests/compatibility_test
- name: Download reference GDExtension API JSON and try to load it
shell: sh
env:
GODOT4_BIN: ${{ inputs.bin }}
REFTAGS: ${{ inputs.reftags }}
run: ./tests/compatibility_test/run_compatibility_test.py

View file

@ -16,7 +16,7 @@ runs:
using: composite
steps:
- name: Set up Python 3.x
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
# Semantic version range syntax or exact version of a Python version.
python-version: ${{ inputs.python-version }}

View file

@ -0,0 +1,55 @@
name: Export Godot project
description: Export a test Godot project.
inputs:
bin:
description: The path to the Godot executable
required: true
runs:
using: composite
steps:
- name: Import resources and export project
shell: sh
run: |
git clone --depth=1 https://github.com/godotengine/godot-tests.git /tmp/godot-tests
echo "Exporting project for Linux (PCK)"
${{ inputs.bin }} --headless --path /tmp/godot-tests/tests/test_project/ --export-pack "Linux" /tmp/test_project.pck 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
echo "Exporting project for Linux (ZIP)"
${{ inputs.bin }} --headless --path /tmp/godot-tests/tests/test_project/ --export-pack "Linux" /tmp/test_project.zip 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
echo "Exporting project for Linux as dedicated server (PCK)"
${{ inputs.bin }} --headless --path /tmp/godot-tests/tests/test_project/ --export-pack "Linux Server" /tmp/test_project_server.pck 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
- name: Run project files from folder
shell: sh
run: |
xvfb-run ${{ inputs.bin }} --path /tmp/godot-tests/tests/test_project/ --language fr --resolution 64x64 --write-movie /tmp/test_project_folder.png --quit 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
${{ inputs.bin }} --headless --path /tmp/godot-tests/tests/test_project/ --quit 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
- name: Run exported project PCK/ZIP
shell: sh
run: |
xvfb-run ${{ inputs.bin }} --main-pack /tmp/test_project.pck --language fr --resolution 64x64 --write-movie /tmp/test_project_pck.png --quit 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
xvfb-run ${{ inputs.bin }} --main-pack /tmp/test_project.zip --language fr --resolution 64x64 --write-movie /tmp/test_project_zip.png --quit 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
# Headless mode is implied for dedicated server PCKs.
${{ inputs.bin }} --main-pack /tmp/test_project_server.pck --quit 2>&1 | tee log.txt || true
GODOT_CHECK_CI_LOG_ALL_ERRORS=1 misc/scripts/check_ci_log.py log.txt
echo "Checking whether video output from project folder and exported project match..."
md5sum /tmp/test_project*.png | md5sum --check
echo "Checking whether audio output from project folder and exported project match..."
md5sum /tmp/test_project*.wav | md5sum --check

View file

@ -14,7 +14,7 @@ runs:
using: composite
steps:
- name: Upload Godot Artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}

16
engine/.github/changed_files.yml vendored Normal file
View file

@ -0,0 +1,16 @@
# We lack a convenient means of gathering *all* the changes when specializations are passed, so
# a catch-all variable is the easiest workaround.
everything:
- "**"
# Determines if build actions should occur after static checks are ran. Broadly speaking, these
# files changing would result in SCons rebuilding the engine, or are otherwise pertinent to the
# buildsystem itself.
sources:
- .github/{actions,workflows}/*.yml
- "**/{SConstruct,SCsub,*.py}"
- "**/*.{h,hpp,hh,hxx,c,cpp,cc,cxx,m,mm,inc,glsl}"
- modules/mono/**/*.{cs,csproj,sln,props,targets}
- platform/android/java/{gradle*,**/*.{jar,java,kt,gradle}}
- platform/web/{package{,-lock}.json,js/**/*.js}
- tests/**

View file

@ -8,7 +8,6 @@ env:
SCONS_FLAGS: >-
dev_mode=yes
module_text_server_fb_enabled=yes
tests=no
swappy=yes
jobs:
@ -39,12 +38,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive
- name: Set up Java 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 17

View file

@ -8,7 +8,6 @@ env:
SCONS_FLAGS: >-
dev_mode=yes
module_text_server_fb_enabled=yes
tests=no
debug_symbols=no
jobs:
@ -20,7 +19,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive

View file

@ -1,6 +1,11 @@
name: 🐧 Linux Builds
on:
workflow_call:
inputs:
changed-files:
description: A list of changed files.
required: true
type: string
workflow_dispatch:
# Global Settings
@ -8,7 +13,6 @@ env:
SCONS_FLAGS: >-
dev_mode=yes
module_text_server_fb_enabled=yes
"accesskit_sdk_path=${{ github.workspace }}/accesskit-c-0.21.2/"
GODOT_CPP_BRANCH: 4.5
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
@ -30,15 +34,17 @@ jobs:
- name: Editor w/ Mono (target=editor)
cache-name: linux-editor-mono
target: editor
scons-flags: module_mono_enabled=yes
scons-flags: module_mono_enabled=yes compiledb=yes
bin: ./bin/godot.linuxbsd.editor.x86_64.mono
build-mono: true
doc-test: true
proj-conv: true
proj-export: true
api-compat: true
artifact: true
# Validate godot-cpp compatibility on one arbitrary editor build.
godot-cpp: true
clang-tidy: true
- name: Editor with doubles and GCC sanitizers (target=editor, dev_build=yes, scu_build=yes, precision=double, use_asan=yes, use_ubsan=yes, linker=mold)
cache-name: linux-editor-double-sanitizers
@ -110,7 +116,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive
@ -118,7 +124,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install libwayland-bin # TODO: Figure out somehow how to embed this one.
if [ "${{ matrix.proj-test }}" == "true" ]; then
if [ "${{ matrix.proj-test }}" == "true" -o "${{ matrix.proj-export }}" == "true" ]; then
sudo apt-get install mesa-vulkan-drivers
fi
@ -143,7 +149,7 @@ jobs:
uses: ./.github/actions/godot-deps
with:
# Sync with Ensure*Version in SConstruct.
python-version: 3.8
python-version: 3.9
scons-version: 4.0
- name: Force remove preinstalled .NET SDKs
@ -159,15 +165,15 @@ jobs:
dotnet-version: 8.0.100
- name: Download pre-built AccessKit
uses: dsaltares/fetch-gh-release-asset@1.1.2
with:
repo: godotengine/godot-accesskit-c-static
version: tags/0.21.2
file: accesskit-c-0.21.2.zip
target: accesskit-c-0.21.2/accesskit_c.zip
- name: Extract pre-built AccessKit
run: unzip -o accesskit-c-0.21.2/accesskit_c.zip
shell: sh
id: accesskit-sdk
run: |
if python ./misc/scripts/install_accesskit.py; then
echo "ACCESSKIT_ENABLED=yes" >> "$GITHUB_OUTPUT"
else
echo "::warning::AccessKit SDK installation failed, building without AccessKit support."
echo "ACCESSKIT_ENABLED=no" >> "$GITHUB_OUTPUT"
fi
- name: Install mold linker
if: matrix.proj-test
@ -176,10 +182,16 @@ jobs:
- name: Compilation
uses: ./.github/actions/godot-build
with:
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }}
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }}
platform: linuxbsd
target: ${{ matrix.target }}
- name: Style checks via pre-commit
if: matrix.clang-tidy
uses: pre-commit/action@v3.0.1
with:
extra_args: --files ${{ inputs.changed-files }} --hook-stage manual clang-tidy
- name: Compilation (godot-cpp)
uses: ./.github/actions/godot-cpp-build
if: matrix.godot-cpp
@ -238,11 +250,18 @@ jobs:
git diff --color --exit-code && ! git ls-files --others --exclude-standard | sed -e 's/^/New doc file missing in PR: /' | grep 'xml$'
# Check API backwards compatibility
- name: Check for GDExtension compatibility
- name: Check for GDExtension compatibility JSON check
if: matrix.api-compat
run: |
./misc/scripts/validate_extension_api.sh "${{ matrix.bin }}"
- name: Test GDExtension compatibility load methods
uses: ./.github/actions/godot-compat-test
if: matrix.api-compat
with:
bin: ${{ matrix.bin }}
reftags: "4.5-stable,4.4-stable"
# Download and run the test project
- name: Test Godot project
uses: ./.github/actions/godot-project-test
@ -250,6 +269,13 @@ jobs:
with:
bin: ${{ matrix.bin }}
# Test project export
- name: Test project export
uses: ./.github/actions/godot-project-export
if: matrix.proj-export
with:
bin: ${{ matrix.bin }}
# Test the project converter
- name: Test project converter
uses: ./.github/actions/godot-converter-test

View file

@ -8,7 +8,6 @@ env:
SCONS_FLAGS: >-
dev_mode=yes
module_text_server_fb_enabled=yes
"accesskit_sdk_path=${{ github.workspace }}/accesskit-c-0.21.2/"
jobs:
build-macos:
@ -33,7 +32,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive
@ -51,15 +50,15 @@ jobs:
uses: ./.github/actions/godot-deps
- name: Download pre-built AccessKit
uses: dsaltares/fetch-gh-release-asset@1.1.2
with:
repo: godotengine/godot-accesskit-c-static
version: tags/0.21.2
file: accesskit-c-0.21.2.zip
target: accesskit-c-0.21.2/accesskit_c.zip
- name: Extract pre-built AccessKit
run: unzip -o accesskit-c-0.21.2/accesskit_c.zip
shell: sh
id: accesskit-sdk
run: |
if python3 ./misc/scripts/install_accesskit.py; then
echo "ACCESSKIT_ENABLED=yes" >> "$GITHUB_OUTPUT"
else
echo "::warning::AccessKit SDK installation failed, building without AccessKit support."
echo "ACCESSKIT_ENABLED=no" >> "$GITHUB_OUTPUT"
fi
- name: Setup Vulkan SDK
id: vulkan-sdk
@ -75,14 +74,14 @@ jobs:
- name: Compilation (x86_64)
uses: ./.github/actions/godot-build
with:
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=x86_64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }}
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=x86_64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }}
platform: macos
target: ${{ matrix.target }}
- name: Compilation (arm64)
uses: ./.github/actions/godot-build
with:
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=arm64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }}
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=arm64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }}
platform: macos
target: ${{ matrix.target }}

View file

@ -18,29 +18,37 @@ jobs:
android-build:
name: 🤖 Android
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/android_builds.yml
ios-build:
name: 🍏 iOS
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/ios_builds.yml
linux-build:
name: 🐧 Linux
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/linux_builds.yml
with:
changed-files: ${{ needs.static-checks.outputs.changed-files }}
macos-build:
name: 🍎 macOS
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/macos_builds.yml
windows-build:
name: 🏁 Windows
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/windows_builds.yml
web-build:
name: 🌐 Web
needs: static-checks
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
uses: ./.github/workflows/web_builds.yml

View file

@ -1,6 +1,13 @@
name: 📊 Static Checks
on:
workflow_call:
outputs:
changed-files:
description: A list of changed files.
value: ${{ jobs.static-checks.outputs.changed-files }}
sources-changed:
description: Determines if any source files were changed.
value: ${{ jobs.static-checks.outputs.sources-changed }}
workflow_dispatch:
jobs:
@ -8,11 +15,15 @@ jobs:
name: Code style, file formatting, and docs
runs-on: ubuntu-24.04
timeout-minutes: 30
outputs:
changed-files: '"${{ steps.changed-files.outputs.everything_all_changed_files }}"' # Wrap with quotes to bookend internal quote separators.
sources-changed: ${{ steps.changed-files.outputs.sources_any_changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 2
fetch-depth: 0 # Treeless clone. Slightly less performant than a shallow clone, but makes finding diffs instantaneous.
filter: tree:0 # See: https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/
# This needs to happen before Python and npm execution; it must happen before any extra files are written.
- name: .gitignore checks (gitignore_check.sh)
@ -20,18 +31,17 @@ jobs:
bash ./misc/scripts/gitignore_check.sh
- name: Get changed files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "${{ github.event_name }}" == "pull_request" ]; then
files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true)
elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then
files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true)
fi
files=$(echo "$files" | xargs -I {} sh -c 'echo "\"./{}\""' | tr '\n' ' ')
echo "CHANGED_FILES=$files" >> $GITHUB_ENV
id: changed-files
uses: tj-actions/changed-files@v47
with:
safe_output: false # Output passed to environment variable to avoid command injection.
separator: '" "' # To account for paths with spaces, ensure our items are split by quotes internally.
skip_initial_fetch: true
files_yaml_from_source_file: .github/changed_files.yml
- name: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
env:
CHANGED_FILES: '"${{ steps.changed-files.outputs.everything_all_changed_files }}"' # Wrap with quotes to bookend internal quote separators.
with:
extra_args: --files ${{ env.CHANGED_FILES }}

View file

@ -7,7 +7,6 @@ on:
env:
SCONS_FLAGS: >-
dev_mode=yes
tests=no
debug_symbols=no
use_closure_compiler=yes
EM_VERSION: 4.0.11
@ -21,21 +20,21 @@ jobs:
fail-fast: false
matrix:
include:
- name: Template w/ threads (target=template_release, threads=yes)
- name: Template w/ threads, 64-bit (target=template_release, threads=yes, arch=wasm64)
cache-name: web-template
target: template_release
scons-flags: threads=yes
scons-flags: threads=yes arch=wasm64
artifact: true
- name: Template w/o threads (target=template_release, threads=no)
- name: Template w/o threads, 32-bit (target=template_release, threads=no, arch=wasm32)
cache-name: web-nothreads-template
target: template_release
scons-flags: threads=no
scons-flags: threads=no arch=wasm32
artifact: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive

View file

@ -10,7 +10,6 @@ env:
module_text_server_fb_enabled=yes
debug_symbols=no
"angle_libs=${{ github.workspace }}/"
"accesskit_sdk_path=${{ github.workspace }}/accesskit-c-0.21.2/"
SCONS_CACHE_MSVC_CONFIG: true
PYTHONIOENCODING: utf8
@ -59,7 +58,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive
@ -96,20 +95,20 @@ jobs:
run: Expand-Archive -Force angle/angle.zip ${{ github.workspace }}/
- name: Download pre-built AccessKit
uses: dsaltares/fetch-gh-release-asset@1.1.2
with:
repo: godotengine/godot-accesskit-c-static
version: tags/0.21.2
file: accesskit-c-0.21.2.zip
target: accesskit-c-0.21.2/accesskit_c.zip
- name: Extract pre-built AccessKit
run: unzip -o accesskit-c-0.21.2/accesskit_c.zip
shell: sh
id: accesskit-sdk
run: |
if python ./misc/scripts/install_accesskit.py; then
echo "ACCESSKIT_ENABLED=yes" >> "$GITHUB_OUTPUT"
else
echo "::warning::AccessKit SDK installation failed, building without AccessKit support."
echo "ACCESSKIT_ENABLED=no" >> "$GITHUB_OUTPUT"
fi
- name: Compilation
uses: ./.github/actions/godot-build
with:
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} d3d12=${{ steps.d3d12-sdk.outputs.D3D12_ENABLED }}
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} d3d12=${{ steps.d3d12-sdk.outputs.D3D12_ENABLED }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }}
platform: windows
target: ${{ matrix.target }}

View file

@ -29,30 +29,36 @@ repos:
types_or: [text]
args: [-style=file:misc/utility/clang_format_glsl.yml]
# Not automatically triggered (because it requires compile_commands.json to be up-to-date).
# Invoke it manually via `pre-commit run --hook-stage manual clang-tidy`
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: clang-tidy
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
args: [--fix, --quiet, --use-color]
# TODO .inc ignored for now because they don't include their parent header.
# TODO Platform-specific subfolders currently fail, we should try to include them
files: ^(core|main|scene)/.*\.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|java)$
# No unknown warning suppression used for easier compatibility with gcc
args: [--fix, --quiet, --use-color, -p=compile_commands.json, -extra-arg=-Wno-unknown-warning-option]
types_or: [text]
additional_dependencies: [clang-tidy==21.1.6]
require_serial: true
stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
require_serial: false
stages: [manual]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.7
rev: v0.15.0
hooks:
- id: ruff-check
args: [--fix]
args: [--color=always]
files: (\.py|SConstruct|SCsub)$
types_or: [text]
- id: ruff-format
args: [--color=always]
files: (\.py|SConstruct|SCsub)$
types_or: [text]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1 # Latest version that supports Python 3.8
rev: v1.19.1
hooks:
- id: mypy
files: \.py$
@ -103,6 +109,12 @@ repos:
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
additional_dependencies: [xmlschema]
- id: validate-codeowners
name: validate codeowners
language: python
entry: python misc/scripts/validate_codeowners.py
args: [--unowned]
- id: eslint
name: eslint
language: node

View file

@ -7,289 +7,6 @@ previous feature release. It is equivalent to the listings on our
Changelogs for earlier feature releases are available in their respective Git
branches, and linked at the [end of this file](#Past-releases).
## 4.6.2 - 2026-04-01
- [Release announcement](https://godotengine.org/article/maintenance-release-godot-4-6-2)
- [Interactive changelog](https://godotengine.github.io/godot-interactive-changelog/#4.6.2)
#### 3D
- Fix `GridMap` editor pasting when orbiting using the "Alt" key ([GH-116778](https://github.com/godotengine/godot/pull/116778)).
- Fix 3D editor camera not updating correctly ([GH-106219](https://github.com/godotengine/godot/pull/106219)).
- Fix 3D focus selection for subgizmos ([GH-116972](https://github.com/godotengine/godot/pull/116972)).
- Fix collision repositioning for child nodes ([GH-115353](https://github.com/godotengine/godot/pull/115353)).
- Fix DirectionalLight3D property list ([GH-117189](https://github.com/godotengine/godot/pull/117189)).
- Fix some UI issues with the `GridMap` editor ([GH-116555](https://github.com/godotengine/godot/pull/116555)).
- Remove unneeded checks for undo-redo history from Skeleton3DEditor ([GH-115784](https://github.com/godotengine/godot/pull/115784)).
#### Animation
- Account for the current section when processing AnimationTracks ([GH-116046](https://github.com/godotengine/godot/pull/116046)).
- Check `playback_queue` existence after emit `animation_finished` signal ([GH-116676](https://github.com/godotengine/godot/pull/116676)).
- Clear fade-out on request firing in AnimationNodeOneShot ([GH-115125](https://github.com/godotengine/godot/pull/115125)).
- Deselect bezier keyframes when switching animations ([GH-116953](https://github.com/godotengine/godot/pull/116953)).
- Fix animation player crash when setting current animation to stop ([GH-116264](https://github.com/godotengine/godot/pull/116264)).
- Fix icon size in AnimationPlayer tracks ([GH-115576](https://github.com/godotengine/godot/pull/115576)).
- Fix visual shift of animation editor keys during selection ([GH-117290](https://github.com/godotengine/godot/pull/117290)).
- Fix timeline cursor following mouse during marker selection ([GH-117634](https://github.com/godotengine/godot/pull/117634)).
#### Assetlib
- Fix TLS handshake fail preventing AssetLib use with `builtin_certs=no` ([GH-115450](https://github.com/godotengine/godot/pull/115450)).
#### Audio
- AudioStreamWAV: Check for `eof_reached` when reading LIST INFO tags ([GH-116719](https://github.com/godotengine/godot/pull/116719)).
- Fix `AudioStreamPlaybackMicrophone` shutdown crash ([GH-116299](https://github.com/godotengine/godot/pull/116299)).
#### Buildsystem
- Add UTF-8 encoding to svg file open in `platform_builders.py` ([GH-117454](https://github.com/godotengine/godot/pull/117454)).
- CI: Bump JavaScript actions to Node 24 ([GH-117428](https://github.com/godotengine/godot/pull/117428)).
- CI: Restore godot-cpp caching ([GH-116586](https://github.com/godotengine/godot/pull/116586)).
- Fix Metal driver build with Xcode 26.4 ([GH-117989](https://github.com/godotengine/godot/pull/117989)).
- ScrollBar: Fix compilation with `precision=double` ([GH-117224](https://github.com/godotengine/godot/pull/117224)).
- Update CODEOWNERS ([GH-117674](https://github.com/godotengine/godot/pull/117674)).
#### C#
- Revert "[.NET] Remove EFS update on reloading assemblies" but with deferred call ([GH-117617](https://github.com/godotengine/godot/pull/117617)).
#### Core
- Fix `String::split_` crash on empty string ([GH-117353](https://github.com/godotengine/godot/pull/117353)).
- Fix editable children state when duplicating instantiated nodes ([GH-117041](https://github.com/godotengine/godot/pull/117041)).
- Make sure `ScriptLanguage` is initialized even after `init_languages` call ([GH-114131](https://github.com/godotengine/godot/pull/114131)).
- RingBuffer: Fix `T read()` method reading empty buffer ([GH-117388](https://github.com/godotengine/godot/pull/117388)).
- RingBuffer: Fix overreading on methods that take an offset as an argument ([GH-117151](https://github.com/godotengine/godot/pull/117151)).
#### Documentation
- Editor Settings: Prevent crash when viewing `filesystem/import/blender/blender_path` ([GH-115895](https://github.com/godotengine/godot/pull/115895)).
- Fix UPNP code sample using `OK` constant incorrectly ([GH-115549](https://github.com/godotengine/godot/pull/115549)).
#### Editor
- Add support for `--ignore-error-breaks` to `LocalDebugger` ([GH-116823](https://github.com/godotengine/godot/pull/116823)).
- Check if a resource from a snapshot exists before loading it ([GH-115194](https://github.com/godotengine/godot/pull/115194)).
- Create EditorHelpHighlighter in Project Manager ([GH-116014](https://github.com/godotengine/godot/pull/116014)).
- Don't tint the preview camera icon ([GH-116525](https://github.com/godotengine/godot/pull/116525)).
- Ensure debug features get cleared after use ([GH-115116](https://github.com/godotengine/godot/pull/115116)).
- Fix build profile generator always enabling 2D navigation ([GH-115412](https://github.com/godotengine/godot/pull/115412)).
- Fix build profile generator creating bogus profiles ([GH-115410](https://github.com/godotengine/godot/pull/115410)).
- Fix Change version link in web editor shell ([GH-117763](https://github.com/godotengine/godot/pull/117763)).
- Fix code completion popup colors not being updated properly ([GH-115315](https://github.com/godotengine/godot/pull/115315)).
- Fix detection of some features in Engine Compilation Configuration Editor ([GH-115230](https://github.com/godotengine/godot/pull/115230)).
- Fix editor not handling unsaved changes on restart from settings ([GH-116218](https://github.com/godotengine/godot/pull/116218)).
- Fix EditorSettings error due to `android_sdk_path` when exporting a project ([GH-116515](https://github.com/godotengine/godot/pull/116515)).
- Fix extend script button styling in scene tree dock ([GH-115045](https://github.com/godotengine/godot/pull/115045)).
- Fix hidden `Import` tab height ([GH-115172](https://github.com/godotengine/godot/pull/115172)).
- Fix mute button after pausing and stopping ([GH-116537](https://github.com/godotengine/godot/pull/116537)).
- Fix theme item inspector tooltips for Window subclasses ([GH-115245](https://github.com/godotengine/godot/pull/115245)).
- Hide property groups from the "Members" section in Debugger ([GH-116790](https://github.com/godotengine/godot/pull/116790)).
- macOS: Set apple menu node name to non empty value ([GH-115726](https://github.com/godotengine/godot/pull/115726)).
- Properly update region editor window when undoing changes to `region_rect` ([GH-108875](https://github.com/godotengine/godot/pull/108875)).
- Scene tree dock: Don't log error if there is no selection upon handling `item_icon_double_clicked` signal ([GH-115347](https://github.com/godotengine/godot/pull/115347)).
- Set accessibility name on Tree inline cell editor when editing ([GH-117135](https://github.com/godotengine/godot/pull/117135)).
- Stop autocomplete from eating words by default ([GH-117464](https://github.com/godotengine/godot/pull/117464)).
#### Export
- Android Editor: Copy keystore to temp file during export ([GH-116161](https://github.com/godotengine/godot/pull/116161)).
- Linux: Handle debug symbols with renamed executable ([GH-114947](https://github.com/godotengine/godot/pull/114947)).
#### GDExtension
- Add missing `GDVIRTUAL_BIND(_get_supported_extensions)` on `MovieWriter` ([GH-117479](https://github.com/godotengine/godot/pull/117479)).
#### GDScript
- Stop `RemoteDebugger` from improperly flushing messages during break ([GH-115532](https://github.com/godotengine/godot/pull/115532)).
#### GUI
- Fix "Custom" anchor preset being ignored if the parent isn't a `Control` ([GH-117488](https://github.com/godotengine/godot/pull/117488)).
- Fix `SplitContainerDragger` dragging with enabled screen reader, allow resizing with keyboard shortcuts ([GH-116628](https://github.com/godotengine/godot/pull/116628)).
- Fix `TabContainer` accessibility sub-element cleanup ([GH-116617](https://github.com/godotengine/godot/pull/116617)).
- Fix camera focus triggered by double-clicking Tree buttons ([GH-114519](https://github.com/godotengine/godot/pull/114519)).
- Fix crash on removing Windows PopupMenu submenu ([GH-115373](https://github.com/godotengine/godot/pull/115373)).
- Fix drag-resizing `Control` with non-zero `pivot_offset_ratio` ([GH-116057](https://github.com/godotengine/godot/pull/116057)).
- Fix error after setting native PopupMenu item ID ([GH-115378](https://github.com/godotengine/godot/pull/115378)).
- Fix LCD batching flag for StyleBoxTexture ([GH-116647](https://github.com/godotengine/godot/pull/116647)).
- Fix RichTextLabel drag selection not working after double-click ([GH-117201](https://github.com/godotengine/godot/pull/117201)).
- Fix soft hyphen not working with small (or zero) line breaking width ([GH-116196](https://github.com/godotengine/godot/pull/116196)).
- Fix SplitContainer accessibility errors ([GH-116601](https://github.com/godotengine/godot/pull/116601)).
- Fix wrong normal icon color in FileDialog ([GH-115917](https://github.com/godotengine/godot/pull/115917)).
- PopupMenu: Use parent `GraphEdit` scale for popups inside `GraphElement` instead of completely disabling it ([GH-115620](https://github.com/godotengine/godot/pull/115620)).
- RTL: Fix `%` handling in `[img=WxH]` tags ([GH-116928](https://github.com/godotengine/godot/pull/116928)).
- Stop exposing external theme item properties ([GH-115392](https://github.com/godotengine/godot/pull/115392)).
- TextEdit: Fix clipping of last character due to right margin rounding ([GH-116850](https://github.com/godotengine/godot/pull/116850)).
- TextServer: Fix numeric keycap emoji sequence rendering ([GH-115687](https://github.com/godotengine/godot/pull/115687)).
- TextServer: Ignore language of embedded object replacement spans when updating line breaks ([GH-116197](https://github.com/godotengine/godot/pull/116197)).
#### Import
- Blender attempts should be incremented to avoid endless loop ([GH-116589](https://github.com/godotengine/godot/pull/116589)).
#### Input
- Fix issues with `InputMap::load_from_project_settings()` when called in tool script ([GH-105045](https://github.com/godotengine/godot/pull/105045)).
- macOS: Hide input accessory popups when no text control selected ([GH-115619](https://github.com/godotengine/godot/pull/115619)).
- Sync controller mappings DB with SDL community repo ([GH-115752](https://github.com/godotengine/godot/pull/115752)).
#### Physics
- Jolt Physics: Make MoveKinematic more accurate when rotating a body by a very small angle ([GH-115327](https://github.com/godotengine/godot/pull/115327)).
- Jolt Physics: Rework how gravity is applied to dynamic bodies to prevent energy increase on elastic collisions ([GH-115305](https://github.com/godotengine/godot/pull/115305)).
- Jolt Physics: Swapping vertices of triangle if it is scaled inside out ([GH-115089](https://github.com/godotengine/godot/pull/115089)).
#### Platforms
- Android: Enable native file picker support on all devices ([GH-115257](https://github.com/godotengine/godot/pull/115257)).
- Android: Fix FileAccess crash when using treeUri in Gradle-built apps ([GH-117131](https://github.com/godotengine/godot/pull/117131)).
- Android: Fix JavaClassWrapper test crashes on API 26 and lower ([GH-115800](https://github.com/godotengine/godot/pull/115800)).
- Android: Remove version check for `FEATURE_NATIVE_DIALOG_FILE` support ([GH-116584](https://github.com/godotengine/godot/pull/116584)).
- Apple Embedded: Fix static .a/.xcframework library loading in `open_dynamic_library` ([GH-117469](https://github.com/godotengine/godot/pull/117469)).
- Fix macOS Steam time tracking lost when opening a project ([GH-117335](https://github.com/godotengine/godot/pull/117335)).
- Fix startup errors/warnings on X11 when the Prefer Wayland editor setting is enabled ([GH-116366](https://github.com/godotengine/godot/pull/116366)).
- iOS: Add UIScene lifecycle events ([GH-116395](https://github.com/godotengine/godot/pull/116395)).
- iOS: Propagate VC UI preferences to SwiftUI hosting controller ([GH-116633](https://github.com/godotengine/godot/pull/116633)).
- LinuxBSD: Fix UI freeze when opening file manager ([GH-114521](https://github.com/godotengine/godot/pull/114521)).
- macOS: Add `nullptr` checks of `script_debugger` in `LayerHost::gui_input` ([GH-116724](https://github.com/godotengine/godot/pull/116724)).
- macOS: Add null check to `get_framework_executable` ([GH-116354](https://github.com/godotengine/godot/pull/116354)).
- macOS: Enable wake for events if `Magnet` is running ([GH-116524](https://github.com/godotengine/godot/pull/116524)).
- macOS: Fix confined mouse movement getting out of sync ([GH-116242](https://github.com/godotengine/godot/pull/116242)).
- Wayland: Improve mapping robustness and synchronization ([GH-117385](https://github.com/godotengine/godot/pull/117385)).
- Wayland: Only handle the current output mode ([GH-116236](https://github.com/godotengine/godot/pull/116236)).
- Wayland: Skip resize request when the size is the same ([GH-116376](https://github.com/godotengine/godot/pull/116376)).
- Windows: Set current driver when ANGLE init fails ([GH-117253](https://github.com/godotengine/godot/pull/117253)).
- Windows: Use executable icon as default for the window ([GH-115294](https://github.com/godotengine/godot/pull/115294)).
#### Plugin
- Android: Fix java.util.HashMap handling ([GH-114941](https://github.com/godotengine/godot/pull/114941)).
- Fix EditorDock not reopening ([GH-117340](https://github.com/godotengine/godot/pull/117340)).
#### Rendering
- Add compatibility fallback to `textureLod` when reading from `RADIANCE` ([GH-116155](https://github.com/godotengine/godot/pull/116155)).
- Apply fixed size properly for mono/stereo rendering ([GH-115147](https://github.com/godotengine/godot/pull/115147)).
- Fix accidental write-combined memory reads in canvas renderer ([GH-115757](https://github.com/godotengine/godot/pull/115757)).
- Fix shader compilation error when writing to `FOG` when `render_mode fog_disabled` ([GH-115026](https://github.com/godotengine/godot/pull/115026)).
- Fix Tangent decoding detection when computing vertex skinning ([GH-117401](https://github.com/godotengine/godot/pull/117401)).
- Fix viewport debanding not working with spatial scalers ([GH-114890](https://github.com/godotengine/godot/pull/114890)).
- Handle nearest filtering modes in D3D12 driver when anisotropy is enabled ([GH-115504](https://github.com/godotengine/godot/pull/115504)).
- macOS: Force ANGLE (GL over Metal) when running in VM ([GH-117371](https://github.com/godotengine/godot/pull/117371)).
- Restore default sky roughness levels to 8 ([GH-116154](https://github.com/godotengine/godot/pull/116154)).
#### Shaders
- Fix UTF-8 handling in GLES3 shaders ([GH-116756](https://github.com/godotengine/godot/pull/116756)).
- Fixes for completion of shader preprocessor defines ([GH-116413](https://github.com/godotengine/godot/pull/116413)).
- VisualShader: Fix nodes not attaching to new Frame on duplication ([GH-115193](https://github.com/godotengine/godot/pull/115193)).
#### Tests
- Android: Fail instrumented tests when test function doesn't complete ([GH-115713](https://github.com/godotengine/godot/pull/115713)).
- Fix file access tests failing on older Android devices ([GH-115718](https://github.com/godotengine/godot/pull/115718)).
#### Thirdparty
- Accessibility: Handle adapter activation/deactivation ([GH-115565](https://github.com/godotengine/godot/pull/115565)).
- Add missing patch files to `thirdparty/jolt_physics` ([GH-115884](https://github.com/godotengine/godot/pull/115884)).
- libpng: Update to 1.6.55 ([GH-117564](https://github.com/godotengine/godot/pull/117564)).
- Update access-kit to 0.21.2 ([GH-117433](https://github.com/godotengine/godot/pull/117433)).
## 4.6.1 - 2026-02-16
- [Release announcement](https://godotengine.org/article/maintenance-release-godot-4-6-1)
- [Interactive changelog](https://godotengine.github.io/godot-interactive-changelog/#4.6.1)
#### 3D
- Change orbit snap shortcut with navigation scheme ([GH-115298](https://github.com/godotengine/godot/pull/115298)).
- Fix `Skeleton3D` Edit Mode bone buttons have priority over transform gizmo ([GH-115608](https://github.com/godotengine/godot/pull/115608)).
- Fix viewport orbit snap defaulting to always snapping when shortcut(s) are set to none ([GH-115002](https://github.com/godotengine/godot/pull/115002)).
- Increase float precision in the editor inspector for Quaternions ([GH-106352](https://github.com/godotengine/godot/pull/106352)).
- Register zoom shortcuts to match preset `Godot` navigation scheme ([GH-115290](https://github.com/godotengine/godot/pull/115290)).
#### Animation
- Fix double memdelete of `dummy_player` ([GH-115968](https://github.com/godotengine/godot/pull/115968)).
- Fix LookAtModifier3D / AimModifier3D forward vector ([GH-115689](https://github.com/godotengine/godot/pull/115689)).
- Fix use-after-free in Animation Blend Tree ([GH-115919](https://github.com/godotengine/godot/pull/115919)).
- Fix use-after-free in AnimationTree (AHashMap realloc) ([GH-115931](https://github.com/godotengine/godot/pull/115931)).
#### Buildsystem
- Fix missing lib with `builtin_glslang=false` ([GH-93478](https://github.com/godotengine/godot/pull/93478)).
#### C#
- Revert "Improve performance of `CSharpLanguage::reload_assemblies`" ([GH-115759](https://github.com/godotengine/godot/pull/115759)).
#### Core
- Fix ClassDB class list sorting regression ([GH-115923](https://github.com/godotengine/godot/pull/115923)).
- Fix the `NodePath` hash function to not yield the same value for similar paths ([GH-115473](https://github.com/godotengine/godot/pull/115473)).
#### Editor
- Fix `NodePath` `EditorProperty` using the wrong scene root ([GH-115422](https://github.com/godotengine/godot/pull/115422)).
- Fix create dialog recents ([GH-115314](https://github.com/godotengine/godot/pull/115314)).
- Fix Rename option for instance roots ([GH-115575](https://github.com/godotengine/godot/pull/115575)).
- Fix Unique Resources from Inherited Scenes ([GH-115862](https://github.com/godotengine/godot/pull/115862)).
- Fix wrong base type when creating script ([GH-115778](https://github.com/godotengine/godot/pull/115778)).
#### Export
- Load translation files to check locale for ICU data export ([GH-115827](https://github.com/godotengine/godot/pull/115827)).
#### GDScript
- LSP: Add `godot` to known language ids ([GH-115671](https://github.com/godotengine/godot/pull/115671)).
- LSP: Handle clients that do not support `CompletionContext` ([GH-115672](https://github.com/godotengine/godot/pull/115672)).
#### GUI
- Fix current line highlight not extending into gutter ([GH-115729](https://github.com/godotengine/godot/pull/115729)).
#### Input
- Update editor shortcuts when changing 3D navigation scheme ([GH-115289](https://github.com/godotengine/godot/pull/115289)).
#### Particles
- Revert "Change curve range for particle multipliers" ([GH-116140](https://github.com/godotengine/godot/pull/116140)).
#### Physics
- Fix transform updates sometimes being discarded when using Jolt ([GH-115364](https://github.com/godotengine/godot/pull/115364)).
#### Platforms
- Android: Fix `Bad file descriptor` in SAF/MediaStore in long term access ([GH-115751](https://github.com/godotengine/godot/pull/115751)).
- Fix crash in `StorageScope.kt` on Android ([GH-115515](https://github.com/godotengine/godot/pull/115515)).
- Wayland Embedder: Fix FD leak with inert objects ([GH-115823](https://github.com/godotengine/godot/pull/115823)).
- Windows: Disable MSVC control flow check on IAT hooks ([GH-115430](https://github.com/godotengine/godot/pull/115430)).
#### Plugin
- Android: Fix plugin type mismatch regression ([GH-115685](https://github.com/godotengine/godot/pull/115685)).
#### Rendering
- Avoid reading from sky pointer when rendering background without sky ([GH-115874](https://github.com/godotengine/godot/pull/115874)).
- Ensure that uv border size is passed in to sky rendering functions ([GH-115606](https://github.com/godotengine/godot/pull/115606)).
- Pick the sample closer to the camera when resolving 2x MSAA ([GH-115124](https://github.com/godotengine/godot/pull/115124)).
- Update re-spirv with more derivative operations ([GH-115921](https://github.com/godotengine/godot/pull/115921)).
- Use sky's corrected camera projection for `combined_reprojection` ([GH-115292](https://github.com/godotengine/godot/pull/115292)).
- Use transmittance instead of opacity in the early-out branch when calculating volumetric fog ([GH-116107](https://github.com/godotengine/godot/pull/116107)).
#### Thirdparty
- libpng: Update to 1.6.54 ([GH-115714](https://github.com/godotengine/godot/pull/115714)).
## 4.6 - 2026-01-26
- [Release announcement](https://godotengine.org/releases/4.6/)

View file

@ -65,7 +65,7 @@ for an introduction to developing on Godot.
The [Contributing docs](https://contributing.godotengine.org/en/latest/organization/how_to_contribute.html)
also have important information on the [PR workflow](https://contributing.godotengine.org/en/latest/organization/pull_requests/creating_pull_requests.html)
(with a helpful guide for Git usage), and our [Code style guidelines](https://contributing.godotengine.org/en/latest/engine/guidelines/code_style.html)
(with a helpful guide for Git usage), and our [Code style guidelines](https://contributing.godotengine.org/en/latest/engine/guidelines/cpp_usage_guidelines.html)
which all contributions need to follow.
### Be mindful of your commits

View file

@ -310,6 +310,11 @@ Comment: The FreeType Project
Copyright: 1996-2025, David Turner, Robert Wilhelm, and Werner Lemberg.
License: FTL
Files: thirdparty/gamepadmotionhelpers/*
Comment: GamepadMotionHelpers
Copyright: 2020-2023, Julian "Jibb" Smart
License: Expat
Files: thirdparty/glad/*
Comment: glad
Copyright: 2013-2022, David Herberth
@ -427,6 +432,11 @@ Comment: meshoptimizer
Copyright: 2016-2024, Arseny Kapoulkine
License: Expat
Files: thirdparty/metal-cpp/*
Comment: metal-cpp
Copyright: 2024, Apple Inc.
License: Apache-2.0
Files: thirdparty/mingw-std-threads/*
Comment: mingw-std-threads
Copyright: 2016, Mega Limited
@ -574,6 +584,11 @@ Comment: SPIRV-Cross
Copyright: 2015-2021, Arm Limited
License: Apache-2.0 or Expat
Files: thirdparty/spirv-headers/*
Comment: SPIRV-Headers
Copyright: 2015-2024, The Khronos Group Inc.
License: Expat
Files: thirdparty/spirv-reflect/*
Comment: SPIRV-Reflect
Copyright: 2017-2022, Google Inc.
@ -608,19 +623,19 @@ License: BSD-3-clause
Files: thirdparty/volk/*
Comment: volk
Copyright: 2018-2024, Arseny Kapoulkine
Copyright: 2018-2025, Arseny Kapoulkine
License: Expat
Files: thirdparty/vulkan/*
Comment: Vulkan Headers
Copyright: 2014-2024, The Khronos Group Inc.
2014-2024, Valve Corporation
2014-2024, LunarG, Inc.
Copyright: 2015-2025, The Khronos Group Inc.
2015-2025, Valve Corporation
2015-2025, LunarG, Inc.
License: Apache-2.0
Files: thirdparty/vulkan/vk_mem_alloc.h
Comment: Vulkan Memory Allocator
Copyright: 2017-2024, Advanced Micro Devices, Inc.
Copyright: 2017-2025, Advanced Micro Devices, Inc.
License: Expat
Files: thirdparty/wayland/*

View file

@ -2,7 +2,7 @@
from misc.utility.scons_hints import *
EnsureSConsVersion(4, 0)
EnsurePythonVersion(3, 8)
EnsurePythonVersion(3, 9)
# System
import glob
@ -199,8 +199,7 @@ opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", Tru
opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False))
opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False))
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
opts.Add(BoolVariable("accesskit", "Use AccessKit C SDK", True))
opts.Add(("accesskit_sdk_path", "Path to the AccessKit C SDK", ""))
opts.Add(BoolVariable("accesskit", "Enable the AccessKit driver for screen reader support", True))
opts.Add(BoolVariable("sdl", "Enable the SDL3 input driver", True))
opts.Add(
EnumVariable(
@ -236,6 +235,7 @@ opts.Add(BoolVariable("ninja", "Use the ninja backend for faster rebuilds", Fals
opts.Add(BoolVariable("ninja_auto_run", "Run ninja automatically after generating the ninja file", True))
opts.Add("ninja_file", "Path to the generated ninja file", "build.ninja")
opts.Add(BoolVariable("compiledb", "Generate compilation DB (`compile_commands.json`) for external tools", False))
opts.Add(BoolVariable("compiledb_gen_only", "Exit after building the compilation database", False))
opts.Add(
"num_jobs",
"Use up to N jobs when compiling (equivalent to `-j N`). Defaults to max jobs - 1. Ignored if -j is used.",
@ -648,8 +648,11 @@ if env["build_profile"] != "":
dbo = ft["disabled_build_options"]
for c in dbo:
env[c] = dbo[c]
except json.JSONDecodeError:
print_error(f'Failed to open feature build profile: "{env["build_profile"]}"')
except json.JSONDecodeError as err:
print_error(f'Failed to open feature build profile due to JSON decoding error: "{env["build_profile"]}"\n{err}')
Exit(255)
except FileNotFoundError:
print_error(f'Feature build profile not found at: "{env["build_profile"]}"')
Exit(255)
# 'dev_mode' and 'production' are aliases to set default options if they haven't been
@ -1169,7 +1172,6 @@ env.Append(BUILDERS=GLSL_BUILDERS)
if env["compiledb"]:
env.Tool("compilation_db")
env.Alias("compiledb", env.CompilationDatabase())
env.NoCache(env.CompilationDatabase())
if not env["verbose"]:
env["COMPILATIONDB_COMSTR"] = "$GENCOMSTR"
@ -1229,6 +1231,12 @@ if env["vsproj"]:
# Miscellaneous & post-build methods.
if not env.GetOption("clean") and not env.GetOption("help"):
if env["compiledb"] and env["compiledb_gen_only"]:
from SCons.Tool.compilation_db import write_compilation_db
write_compilation_db([env.File("compile_commands.json")], [], env)
env.Exit()
methods.dump(env)
methods.show_progress(env)
methods.prepare_purge(env)

View file

@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/donors.gen.h"
#include "core/license.gen.h"
#include "core/object/ref_counted.h"
#include "core/variant/typed_array.h"
#include "core/version.h"
#include "servers/rendering/rendering_device.h"

View file

@ -30,23 +30,27 @@
#include "project_settings.h"
#include "core/core_bind.h" // For Compression enum.
#include "core/input/input_map.h"
#include "core/io/compression.h"
#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/io/resource_uid.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/object/message_queue.h"
#include "core/object/script_language.h"
#include "core/os/os.h"
#include "core/templates/rb_set.h"
#include "core/variant/typed_array.h"
#include "core/variant/variant_parser.h"
#include "core/version.h"
#include "servers/rendering/rendering_server.h"
#ifdef TOOLS_ENABLED
#include "modules/modules_enabled.gen.h" // For mono.
#include "core/config/engine.h"
#include "modules/modules_enabled.gen.h" // IWYU pragma: keep. For mono.
#endif // TOOLS_ENABLED
ProjectSettings *ProjectSettings::get_singleton() {
@ -635,7 +639,8 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
} else if (p_from_version <= 6) {
// Check if we still have legacy boot splash (removed in 4.6), map it to new project setting, then remove legacy setting.
if (has_setting("application/boot_splash/fullsize")) {
set_setting("application/boot_splash/stretch_mode", RenderingServer::map_scaling_option_to_stretch_mode(get_setting("application/boot_splash/fullsize")));
// See RenderingServerEnums::SplashStretchMode.
set_setting("application/boot_splash/stretch_mode", get_setting("application/boot_splash/fullsize") ? 1 : 0);
set_setting("application/boot_splash/fullsize", Variant());
}
}
@ -1057,6 +1062,7 @@ bool ProjectSettings::is_builtin_setting(const String &p_name) const {
void ProjectSettings::clear(const String &p_name) {
ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
props.erase(p_name);
_queue_changed(p_name);
}
Error ProjectSettings::save() {
@ -1640,7 +1646,7 @@ void ProjectSettings::_bind_methods() {
void ProjectSettings::_add_builtin_input_map() {
if (InputMap::get_singleton()) {
HashMap<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
HashMap<String, List<Ref<InputEvent>>> builtins(InputMap::get_singleton()->get_builtins());
for (KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
Array events;
@ -1703,6 +1709,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/accessibility_support", PROPERTY_HINT_ENUM, "Auto (When Screen Reader is Running),Always Active,Disabled"), 0);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/updates_per_second", PROPERTY_HINT_RANGE, "1,100,1"), 60);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "accessibility/general/accessibility_driver", PROPERTY_HINT_ENUM, "accesskit,dummy"), "accesskit");
// The default window size is tuned to:
// - Have a 16:9 aspect ratio,
@ -1732,6 +1739,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution
GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
GLOBAL_DEF("display/window/hdr/request_hdr_output", false);
GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
@ -1751,10 +1760,10 @@ ProjectSettings::ProjectSettings() {
_add_builtin_input_map();
// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
// Keep the enum values in sync with the `DisplayServerEnums::ScreenOrientation` enum.
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor");
GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
// Keep the enum values in sync with the `DisplayServer::VSyncMode` enum.
// Keep the enum values in sync with the `DisplayServerEnums::VSyncMode` enum.
custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox");
GLOBAL_DEF("display/window/frame_pacing/android/enable_frame_pacing", true);

View file

@ -31,6 +31,7 @@
#pragma once
#include "core/object/object.h"
#include "core/os/thread_safe.h"
#include "core/templates/rb_map.h"
template <typename T>
@ -204,7 +205,7 @@ public:
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
uint64_t get_last_saved_time() { return last_save_time; }
List<String> get_input_presets() const { return input_presets; }
List<String> get_input_presets() const { return List<String>(input_presets); }
Variant get_setting_with_override(const StringName &p_name) const;
Variant get_setting_with_override_and_custom_features(const StringName &p_name, const Vector<String> &p_features) const;

View file

@ -30,6 +30,10 @@
#ifndef DISABLE_DEPRECATED
#include "core_bind.h"
#include "core/object/class_db.h"
namespace CoreBind {
// Semaphore

View file

@ -31,6 +31,7 @@
#include "core_bind.h"
#include "core_bind.compat.inc"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
@ -39,8 +40,11 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
#include "core/os/process_id.h"
#include "core/os/thread_safe.h"
#include "core/variant/typed_array.h"
@ -425,7 +429,7 @@ int OS::create_instance(const Vector<String> &p_arguments) {
for (const String &arg : p_arguments) {
args.push_back(arg);
}
::OS::ProcessID pid = 0;
ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_instance(args, &pid);
if (err != OK) {
return -1;
@ -446,7 +450,7 @@ int OS::create_process(const String &p_path, const Vector<String> &p_arguments,
for (const String &arg : p_arguments) {
args.push_back(arg);
}
::OS::ProcessID pid = 0;
ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console);
if (err != OK) {
return -1;

View file

@ -31,8 +31,10 @@
#pragma once
#include "core/debugger/engine_profiler.h"
#include "core/io/logger.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/class_db.h"
#include "core/object/script_backtrace.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"

View file

@ -41,7 +41,7 @@ def version_hash_builder(target, source, env):
#include "core/version.h"
const char *const GODOT_VERSION_HASH = "{git_hash}";
const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
const unsigned long long GODOT_VERSION_TIMESTAMP = {git_timestamp};
""".format(**source[0].read())
)
@ -63,7 +63,7 @@ def encryption_key_builder(target, source, env):
with methods.generated_wrapper(str(target[0])) as file:
file.write(
f"""\
#include "core/config/project_settings.h"
#include <cstdint>
uint8_t script_encryption_key[32] = {{
{methods.format_buffer(buffer, 1)}

View file

@ -30,10 +30,13 @@
#include "core_constants.h"
#include "core/input/input_event.h"
#include "core/object/class_db.h"
#include "core/input/input_enums.h"
#include "core/object/method_bind.h" // IWYU pragma: keep. To bind `MethodFlags`.
#include "core/object/object.h"
#include "core/os/keyboard.h"
#include "core/variant/type_info.h"
#include "core/variant/variant.h"
#include "core/variant/variant_caster.h"
struct _CoreConstant {
#ifdef DEBUG_ENABLED
@ -69,183 +72,183 @@ static HashMap<StringName, Vector<_CoreConstant>> _global_enums;
#ifdef DEBUG_ENABLED
#define BIND_CORE_CONSTANT(m_constant) \
#define BIND_CORE_CONSTANT(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant); \
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, false, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
// This just binds enum classes as if they were regular enum constants.
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, false, true)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member, false, true)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant, true)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant, true)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#else
#define BIND_CORE_CONSTANT(m_constant) \
#define BIND_CORE_CONSTANT(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
// This just binds enum classes as if they were regular enum constants.
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
@ -549,6 +552,11 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE3);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE4);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, TOUCHPAD);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC2);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC3);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC4);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC5);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC6);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, SDL_MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MAX);
@ -729,6 +737,18 @@ void register_global_constants() {
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL_REQUIRED);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAGS_DEFAULT);
BIND_CORE_CONSTANT(UINT8_MAX);
BIND_CORE_CONSTANT(UINT16_MAX);
BIND_CORE_CONSTANT(UINT32_MAX);
BIND_CORE_CONSTANT(INT8_MIN);
BIND_CORE_CONSTANT(INT8_MAX);
BIND_CORE_CONSTANT(INT16_MIN);
BIND_CORE_CONSTANT(INT16_MAX);
BIND_CORE_CONSTANT(INT32_MIN);
BIND_CORE_CONSTANT(INT32_MAX);
BIND_CORE_CONSTANT(INT64_MIN);
BIND_CORE_CONSTANT(INT64_MAX);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);

View file

@ -28,7 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "core/crypto/aes_context.h"
#include "aes_context.h"
#include "core/object/class_db.h"
Error AESContext::start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv) {
ERR_FAIL_COND_V_MSG(mode != MODE_MAX, ERR_ALREADY_IN_USE, "AESContext already started. Call 'finish' before starting a new one.");

View file

@ -32,6 +32,7 @@
#include "core/crypto/crypto_core.h"
#include "core/object/ref_counted.h"
#include "core/variant/type_info.h"
class AESContext : public RefCounted {
GDCLASS(AESContext, RefCounted);

View file

@ -30,6 +30,8 @@
#include "crypto.h"
#include "core/object/class_db.h"
/// Resources
CryptoKey *(*CryptoKey::_create)(bool p_notify_postinitialize) = nullptr;

View file

@ -31,6 +31,7 @@
#include "crypto_core.h"
#include "core/os/os.h"
#include "core/string/ustring.h"
#include <mbedtls/aes.h>
#include <mbedtls/base64.h>

View file

@ -30,7 +30,12 @@
#pragma once
#include "core/object/ref_counted.h"
#include "core/error/error_list.h"
#include <cstddef>
#include <cstdint>
class String;
class CryptoCore {
public:

View file

@ -31,6 +31,7 @@
#include "hashing_context.h"
#include "core/crypto/crypto_core.h"
#include "core/object/class_db.h"
Error HashingContext::start(HashType p_type) {
ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);

View file

@ -31,6 +31,7 @@
#pragma once
#include "core/object/ref_counted.h"
#include "core/variant/type_info.h"
class HashingContext : public RefCounted {
GDCLASS(HashingContext, RefCounted);

View file

@ -31,6 +31,7 @@
#include "engine_profiler.h"
#include "core/debugger/engine_debugger.h"
#include "core/object/class_db.h" // IWYU pragma: keep. `GDVIRTUAL_BIND` macro.
void EngineProfiler::_bind_methods() {
GDVIRTUAL_BIND(_toggle, "enable", "options");

View file

@ -30,7 +30,7 @@
#pragma once
#include "core/object/gdvirtual.gen.inc"
#include "core/object/gdvirtual.gen.h"
#include "core/object/ref_counted.h"
class EngineProfiler : public RefCounted {

View file

@ -34,6 +34,8 @@
#include "core/os/main_loop.h"
#include "core/os/os.h"
#include <cstdio>
struct LocalDebugger::ScriptsProfiler {
struct ProfileInfoSort {
bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const {

View file

@ -31,7 +31,6 @@
#pragma once
#include "core/debugger/engine_debugger.h"
#include "core/object/script_language.h"
#include "core/templates/list.h"
class LocalDebugger : public EngineDebugger {

View file

@ -30,6 +30,7 @@
#include "remote_debugger.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
@ -38,6 +39,7 @@
#include "core/input/input.h"
#include "core/io/resource_loader.h"
#include "core/math/expression.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/os/os.h"
#include "servers/display/display_server.h"
@ -426,12 +428,12 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
}
send_message("debug_enter", msg);
Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
Input::MouseMode mouse_mode = Input::MouseMode::MOUSE_MODE_VISIBLE;
if (Thread::is_main_thread()) {
mouse_mode = Input::get_singleton()->get_mouse_mode();
if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
if (mouse_mode != Input::MouseMode::MOUSE_MODE_VISIBLE) {
Input::get_singleton()->set_mouse_mode(Input::MouseMode::MOUSE_MODE_VISIBLE);
}
} else {
MutexLock mutex_lock(mutex);

View file

@ -33,8 +33,6 @@
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/remote_debugger_peer.h"
#include "core/object/class_db.h"
#include "core/string/string_name.h"
#include "core/string/ustring.h"
#include "core/variant/array.h"

View file

@ -32,6 +32,9 @@
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/io/stream_peer_socket.h"
#include "core/io/stream_peer_tcp.h"
#include "core/io/stream_peer_uds.h"
#include "core/os/os.h"
bool RemoteDebuggerPeerTCP::is_peer_connected() {

View file

@ -30,13 +30,13 @@
#pragma once
#include "core/io/stream_peer_tcp.h"
#include "core/io/stream_peer_uds.h"
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
#include "core/string/ustring.h"
class StreamPeerSocket;
class RemoteDebuggerPeer : public RefCounted {
GDSOFTCLASS(RemoteDebuggerPeer, RefCounted);

View file

@ -30,6 +30,8 @@
#include "doc_data.h"
#include "core/object/object.h"
String DocData::get_default_value_string(const Variant &p_value) {
const Variant::Type type = p_value.get_type();
if (type == Variant::ARRAY) {

View file

@ -30,7 +30,6 @@
#pragma once
#include "core/io/xml_parser.h"
#include "core/variant/variant.h"
class DocData {

View file

@ -36,6 +36,8 @@
#include "core/os/os.h"
#include "core/string/ustring.h"
#include <cstdio>
// Optional physics interpolation warnings try to include the path to the relevant node.
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
#include "core/config/project_settings.h"

View file

@ -32,10 +32,6 @@
#include "core/typedefs.h"
#ifdef _MSC_VER
#include <intrin.h> // `__fastfail()`.
#endif
class String;
class ObjectID;
@ -95,11 +91,11 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
#define FUNCTION_STR __FUNCTION__
#endif
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(__clang__)
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
*/
#define GENERATE_TRAP() __fastfail(7 /* FAST_FAIL_FATAL_APP_EXIT */)
#define GENERATE_TRAP() __debugbreak()
#else
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
@ -135,32 +131,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns.
*/
#define ERR_FAIL_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -170,32 +166,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -206,12 +202,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the application crashes.
*/
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
@ -221,12 +217,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Unsigned integer index out of bounds error macros.
@ -238,32 +234,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -273,32 +269,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -309,12 +305,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
@ -324,12 +320,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Null reference error macros.
@ -341,32 +337,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns.
*/
#define ERR_FAIL_NULL(m_param) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL(m_param) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -376,32 +372,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V(m_param, m_retval) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL_V(m_param, m_retval) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -413,11 +409,11 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns.
*/
#define ERR_FAIL_COND(m_cond) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -427,21 +423,21 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*/
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -453,11 +449,11 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns `m_retval`.
*/
#define ERR_FAIL_COND_V(m_cond, m_retval) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND_V(m_cond, m_retval) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -467,21 +463,21 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*/
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -491,32 +487,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop continues.
*/
#define ERR_CONTINUE(m_cond) \
if (unlikely(m_cond)) { \
#define ERR_CONTINUE(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
continue; \
} else \
continue; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop continues.
*/
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
continue; \
} else \
continue; \
} else \
((void)0)
/**
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
continue; \
} else \
continue; \
} else \
((void)0)
/**
@ -526,32 +522,32 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop breaks.
*/
#define ERR_BREAK(m_cond) \
if (unlikely(m_cond)) { \
#define ERR_BREAK(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
break; \
} else \
break; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
*/
#define ERR_BREAK_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_BREAK_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
break; \
} else \
break; \
} else \
((void)0)
/**
* Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
break; \
} else \
break; \
} else \
((void)0)
/**
@ -562,12 +558,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, the application crashes.
*/
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
@ -577,12 +573,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the application crashes.
*/
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Generic error macros.
@ -594,11 +590,11 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* The current function returns.
*/
#define ERR_FAIL() \
if (true) { \
#define ERR_FAIL() \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -607,21 +603,21 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* Prints `m_msg`, and the current function returns.
*/
#define ERR_FAIL_MSG(m_msg) \
if (true) { \
#define ERR_FAIL_MSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
return; \
} else \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
return; \
} else \
return; \
} else \
((void)0)
/**
@ -631,11 +627,11 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* The current function returns `m_retval`.
*/
#define ERR_FAIL_V(m_retval) \
if (true) { \
#define ERR_FAIL_V(m_retval) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -644,21 +640,21 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* Prints `m_msg`, and the current function returns `m_retval`.
*/
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
if (true) { \
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
return m_retval; \
} else \
((void)0)
/**
@ -680,27 +676,27 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
/**
* Prints `m_msg` once during the application lifetime.
*/
#define ERR_PRINT_ONCE(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define ERR_PRINT_ONCE(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
} \
} else \
} \
} else \
((void)0)
/**
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
*/
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
} \
} else \
} \
} else \
((void)0)
// Print warning message macros.
@ -724,37 +720,37 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \
} \
} else \
} \
} else \
((void)0)
/**
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \
} \
} else \
} \
} else \
((void)0)
/**
* Warns about `m_msg` only when verbose mode is enabled.
*/
#define WARN_VERBOSE(m_msg) \
{ \
#define WARN_VERBOSE(m_msg) \
{ \
if (is_print_verbose_enabled()) { \
WARN_PRINT(m_msg); \
} \
WARN_PRINT(m_msg); \
} \
}
// Print deprecated warning message macros.
@ -762,27 +758,27 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
/**
* Warns that the current function is deprecated.
*/
#define WARN_DEPRECATED \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define WARN_DEPRECATED \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \
} \
} else \
} \
} else \
((void)0)
/**
* Warns that the current function is deprecated and prints `m_msg`.
*/
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
static bool warning_shown = false; \
if (unlikely(!warning_shown)) { \
warning_shown = true; \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \
} \
} else \
} \
} else \
((void)0)
/**
@ -791,12 +787,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* The application crashes.
*/
#define CRASH_NOW() \
if (true) { \
#define CRASH_NOW() \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
@ -804,12 +800,12 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
*
* Prints `m_msg`, and then the application crashes.
*/
#define CRASH_NOW_MSG(m_msg) \
if (true) { \
#define CRASH_NOW_MSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
@ -828,26 +824,26 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
* and that can't fail for other contributors once the code is finished and merged.
*/
#ifdef DEV_ENABLED
#define DEV_ASSERT(m_cond) \
if (unlikely(!(m_cond))) { \
#define DEV_ASSERT(m_cond) \
if (unlikely(!(m_cond))) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
#else
#define DEV_ASSERT(m_cond)
#endif
#ifdef DEV_ENABLED
#define DEV_CHECK_ONCE(m_cond) \
if (true) { \
static bool first_print = true; \
if (first_print && unlikely(!(m_cond))) { \
#define DEV_CHECK_ONCE(m_cond) \
if (true) { \
static bool first_print = true; \
if (first_print && unlikely(!(m_cond))) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "DEV_CHECK_ONCE failed \"" _STR(m_cond) "\" is false."); \
first_print = false; \
} \
} else \
first_print = false; \
} \
} else \
((void)0)
#else
#define DEV_CHECK_ONCE(m_cond)

View file

@ -7,7 +7,7 @@ import make_interface_dumper
import make_interface_header
import make_wrappers
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
env.CommandNoCache("ext_wrappers.gen.h", "make_wrappers.py", env.Run(make_wrappers.run))
env.CommandNoCache(
"gdextension_interface_dump.gen.h",
["gdextension_interface.json", "make_interface_dumper.py"],

View file

@ -35,6 +35,7 @@
#include "core/extension/gdextension_special_compat_hashes.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/object/class_db.h"
#include "core/templates/pair.h"
#include "core/version.h"
@ -281,59 +282,59 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
// Member offsets, meta types and sizes.
#define REAL_MEMBER_OFFSET(type, member) \
{ \
type, \
member, \
"float", \
sizeof(float), \
"float", \
sizeof(float), \
"double", \
sizeof(double), \
"double", \
sizeof(double), \
{ \
type, \
member, \
"float", \
sizeof(float), \
"float", \
sizeof(float), \
"double", \
sizeof(double), \
"double", \
sizeof(double), \
}
#define INT32_MEMBER_OFFSET(type, member) \
{ \
type, \
member, \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
{ \
type, \
member, \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
}
#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
{ \
type, \
member, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
{ \
type, \
member, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
}
#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
{ \
type, \
member, \
member_type, \
sizeof(float) * member_elems, \
member_type, \
sizeof(float) * member_elems, \
member_type, \
sizeof(double) * member_elems, \
member_type, \
sizeof(double) * member_elems, \
{ \
type, \
member, \
member_type, \
sizeof(float) * member_elems, \
member_type, \
sizeof(float) * member_elems, \
member_type, \
sizeof(double) * member_elems, \
member_type, \
sizeof(double) * member_elems, \
}
struct {

View file

@ -30,14 +30,17 @@
#pragma once
#include "core/extension/gdextension.h"
#ifdef TOOLS_ENABLED
#include "core/error/error_list.h"
#include "core/string/ustring.h"
#include "core/variant/dictionary.h"
class GDExtensionAPIDump {
public:
static Dictionary generate_extension_api(bool p_include_docs = false);
static void generate_extension_json_file(const String &p_path, bool p_include_docs = false);
static Error validate_extension_json_file(const String &p_path);
};
#endif

View file

@ -30,6 +30,10 @@
#ifndef DISABLE_DEPRECATED
#include "gdextension.h"
#include "core/object/class_db.h"
Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) {
return ERR_UNAVAILABLE;
}
@ -46,4 +50,4 @@ void GDExtension::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418);
}
#endif
#endif // DISABLE_DEPRECATED

View file

@ -32,6 +32,7 @@
#include "gdextension.compat.inc"
#include "core/config/project_settings.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
#include "gdextension_library_loader.h"
@ -950,7 +951,7 @@ void GDExtension::prepare_reload() {
state.push_back(Pair<String, Variant>(P.name, value));
}
E.value.instance_state[obj_id] = {
state, // List<Pair<String, Variant>> properties;
std::move(state), // List<Pair<String, Variant>> properties;
obj->is_extension_placeholder(), // bool is_placeholder;
};
}

View file

@ -32,7 +32,6 @@
#include "core/extension/gdextension_interface.gen.h"
#include "core/extension/gdextension_loader.h"
#include "core/io/config_file.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"

View file

@ -31,7 +31,6 @@
#pragma once
#include "core/extension/gdextension_loader.h"
#include "core/os/shared_object.h"
class GDExtension;

View file

@ -5859,7 +5859,7 @@
"return_value": {
"type": "GDExtensionInt",
"description": [
"The resulting encoded string length in characters (not bytes), not including a null terminator."
"The resulting encoded string length in characters, not including a null terminator. Characters that cannot be converted to Latin-1 are replaced with a space."
]
},
"arguments": [
@ -5896,7 +5896,7 @@
"return_value": {
"type": "GDExtensionInt",
"description": [
"The resulting encoded string length in characters (not bytes), not including a null terminator."
"The resulting encoded string length in bytes (not characters), not including a null terminator."
]
},
"arguments": [
@ -5933,7 +5933,7 @@
"return_value": {
"type": "GDExtensionInt",
"description": [
"The resulting encoded string length in characters (not bytes), not including a null terminator."
"The resulting encoded string length in 16-bit code units (not bytes or characters), not including a null terminator."
]
},
"arguments": [
@ -6007,7 +6007,7 @@
"return_value": {
"type": "GDExtensionInt",
"description": [
"The resulting encoded string length in characters (not bytes), not including a null terminator."
"The resulting encoded string length in characters (for UTF-32) or 16-bit code units (for UTF-16), depending on the wchar_t representation. Does not include a null terminator."
]
},
"arguments": [

View file

@ -30,8 +30,10 @@
#include "gdextension_library_loader.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "core/version.h"
#include "gdextension.h"

View file

@ -30,12 +30,16 @@
#include "gdextension_manager.h"
#include "core/config/engine.h"
#include "core/extension/gdextension_function_loader.h"
#include "core/extension/gdextension_library_loader.h"
#include "core/extension/gdextension_special_compat_hashes.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/os/os.h"
GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load) {
if (level >= 0) { // Already initialized up to some level.
@ -477,8 +481,8 @@ void GDExtensionManager::_bind_methods() {
BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
ADD_SIGNAL(MethodInfo("extensions_reloaded"));
ADD_SIGNAL(MethodInfo("extension_loaded", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
ADD_SIGNAL(MethodInfo("extension_unloading", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
ADD_SIGNAL(MethodInfo("extension_loaded", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, GDExtension::get_class_static())));
ADD_SIGNAL(MethodInfo("extension_unloading", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, GDExtension::get_class_static())));
}
GDExtensionManager::GDExtensionManager() {

View file

@ -31,7 +31,9 @@
#include "godot_instance.h"
#include "core/extension/gdextension_manager.h"
#include "core/object/class_db.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
#include "main/main.h"
#include "servers/display/display_server.h"

View file

@ -31,7 +31,7 @@
#pragma once
#include "core/extension/gdextension_interface.gen.h"
#include "core/object/class_db.h"
#include "core/object/object.h"
class GodotInstance : public Object {
GDCLASS(GodotInstance, Object);

View file

@ -30,6 +30,10 @@
#ifndef DISABLE_DEPRECATED
#include "input.h"
#include "core/object/class_db.h"
void Input::_vibrate_handheld_bind_compat_91143(int p_duration_ms) {
vibrate_handheld(p_duration_ms, -1.0);
}

View file

@ -31,15 +31,21 @@
#include "input.h"
#include "input.compat.inc"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/input/default_controller_mappings.h"
#include "core/input/input_map.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#ifdef DEV_ENABLED
#include "core/os/thread.h"
#endif
#include "thirdparty/gamepadmotionhelpers/GamepadMotion.hpp"
#define STANDARD_GRAVITY 9.80665f
static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = {
"a",
"b",
@ -62,6 +68,11 @@ static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = {
"paddle3",
"paddle4",
"touchpad",
"misc2",
"misc3",
"misc4",
"misc5",
"misc6",
};
static const char *_joy_axes[(size_t)JoyAxis::SDL_MAX] = {
@ -114,6 +125,8 @@ bool Input::is_mouse_mode_override_enabled() {
}
void Input::_bind_methods() {
using namespace InputClassEnums;
ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
ClassDB::bind_method(D_METHOD("is_physical_key_pressed", "keycode"), &Input::is_physical_key_pressed);
@ -140,13 +153,32 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
ClassDB::bind_method(D_METHOD("get_joy_vibration_remaining_duration", "device"), &Input::get_joy_vibration_remaining_duration);
ClassDB::bind_method(D_METHOD("is_joy_vibrating", "device"), &Input::is_joy_vibrating);
ClassDB::bind_method(D_METHOD("has_joy_vibration", "device"), &Input::has_joy_vibration);
ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms", "amplitude"), &Input::vibrate_handheld, DEFVAL(500), DEFVAL(-1.0));
ClassDB::bind_method(D_METHOD("set_ignore_joypad_on_unfocused_application", "enable"), &Input::set_ignore_joypad_on_unfocused_application);
ClassDB::bind_method(D_METHOD("is_ignoring_joypad_on_unfocused_application"), &Input::is_ignoring_joypad_on_unfocused_application);
ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
ClassDB::bind_method(D_METHOD("get_joy_accelerometer", "device"), &Input::get_joy_accelerometer);
ClassDB::bind_method(D_METHOD("get_joy_gravity", "device"), &Input::get_joy_gravity);
ClassDB::bind_method(D_METHOD("get_joy_gyroscope", "device"), &Input::get_joy_gyroscope);
ClassDB::bind_method(D_METHOD("get_joy_motion_sensors_rate", "device"), &Input::get_joy_motion_sensors_rate);
ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_enabled", "device"), &Input::is_joy_motion_sensors_enabled);
ClassDB::bind_method(D_METHOD("set_joy_motion_sensors_enabled", "device", "enable"), &Input::set_joy_motion_sensors_enabled);
ClassDB::bind_method(D_METHOD("has_joy_motion_sensors", "device"), &Input::has_joy_motion_sensors);
ClassDB::bind_method(D_METHOD("start_joy_motion_sensors_calibration", "device"), &Input::start_joy_motion_sensors_calibration);
ClassDB::bind_method(D_METHOD("stop_joy_motion_sensors_calibration", "device"), &Input::stop_joy_motion_sensors_calibration);
ClassDB::bind_method(D_METHOD("clear_joy_motion_sensors_calibration", "device"), &Input::clear_joy_motion_sensors_calibration);
ClassDB::bind_method(D_METHOD("get_joy_motion_sensors_calibration", "device"), &Input::get_joy_motion_sensors_calibration);
ClassDB::bind_method(D_METHOD("set_joy_motion_sensors_calibration", "device", "calibration_info"), &Input::set_joy_motion_sensors_calibration);
ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrated", "device"), &Input::is_joy_motion_sensors_calibrated);
ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrating", "device"), &Input::is_joy_motion_sensors_calibrating);
ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity);
ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer);
ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer);
@ -177,6 +209,7 @@ void Input::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_mouse_from_touch"), "set_emulate_mouse_from_touch", "is_emulating_mouse_from_touch");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_touch_from_mouse"), "set_emulate_touch_from_mouse", "is_emulating_touch_from_mouse");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_joypad_on_unfocused_application"), "set_ignore_joypad_on_unfocused_application", "is_ignoring_joypad_on_unfocused_application");
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
@ -296,24 +329,14 @@ bool Input::is_anything_pressed() const {
return false;
}
bool Input::is_anything_pressed_except_mouse() const {
bool Input::is_any_key_pressed() const {
_THREAD_SAFE_METHOD_
if (disable_input) {
return false;
}
if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty()) {
return true;
}
for (const KeyValue<StringName, Input::ActionState> &E : action_states) {
if (E.value.cache.pressed) {
return true;
}
}
return false;
return !keys_pressed.is_empty();
}
bool Input::is_key_pressed(Key p_keycode) const {
@ -356,6 +379,10 @@ bool Input::is_mouse_button_pressed(MouseButton p_button) const {
return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
}
bool Input::_should_ignore_joypad_events() const {
return ignore_joypad_on_unfocused_application && !application_focused && !embedder_focused;
}
static JoyAxis _combine_device(JoyAxis p_value, int p_device) {
return JoyAxis((int)p_value | (p_device << 20));
}
@ -615,6 +642,33 @@ float Input::get_joy_vibration_duration(int p_device) {
}
}
float Input::get_joy_vibration_remaining_duration(int p_device) {
_THREAD_SAFE_METHOD_
const Joypad *joypad = joy_names.getptr(p_device);
if (joypad == nullptr || !joypad->has_vibration) {
return 0.f;
}
const VibrationInfo *vibration = joy_vibration.getptr(p_device);
if (vibration == nullptr || (vibration->weak_magnitude == 0.f && vibration->strong_magnitude == 0.f) || vibration->duration < 0.f) {
return 0.f;
}
float vibration_duration = vibration->duration;
if (vibration_duration > 0xFFFF / 1000.f || vibration_duration == 0.f) {
vibration_duration = 0xFFFF / 1000.f; // SDL_MAX_RUMBLE_DURATION_MS / 1000.f
}
return MAX(vibration_duration - (OS::get_singleton()->get_ticks_usec() - vibration->timestamp) / 1e6, 0.f);
}
bool Input::is_joy_vibrating(int p_device) {
return get_joy_vibration_remaining_duration(p_device) > 0.0f;
}
bool Input::has_joy_vibration(int p_device) const {
_THREAD_SAFE_METHOD_
const Joypad *joypad = joy_names.getptr(p_device);
return joypad != nullptr && joypad->has_vibration;
}
static String _hex_str(uint8_t p_byte) {
static const char *dict = "0123456789abcdef";
char ret[3];
@ -684,6 +738,11 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_
for (int i = 0; i < (int)JoyAxis::MAX; i++) {
set_joy_axis(p_idx, (JoyAxis)i, 0.0f);
}
MotionInfo *motion = joy_motion.getptr(p_idx);
if (motion != nullptr && motion->gamepad_motion != nullptr) {
delete motion->gamepad_motion;
}
joy_motion.erase(p_idx);
}
joy_names[p_idx] = js;
@ -959,6 +1018,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
device_state.pressed[event_index] = is_pressed;
device_state.strength[event_index] = p_event->get_action_strength(E.key);
device_state.raw_strength[event_index] = p_event->get_action_raw_strength(E.key);
device_state.event_type[event_index] = p_event->get_type();
// Update the action's global state and cache.
if (!is_pressed) {
@ -1005,6 +1065,12 @@ void Input::set_joy_features(int p_device, JoypadFeatures *p_features) {
}
void Input::set_joy_light(int p_device, const Color &p_color) {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return;
}
Joypad *joypad = joy_names.getptr(p_device);
if (!joypad || !joypad->has_light || joypad->features == nullptr) {
return;
@ -1018,8 +1084,218 @@ bool Input::has_joy_light(int p_device) const {
return joypad && joypad->has_light;
}
Vector3 Input::get_joy_accelerometer(int p_device) const {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return Vector3();
}
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return Vector3();
}
float joy_acceleration_data[3];
motion->gamepad_motion->GetProcessedAcceleration(joy_acceleration_data[0], joy_acceleration_data[1], joy_acceleration_data[2]);
Vector3 joy_acceleration(joy_acceleration_data[0], joy_acceleration_data[1], joy_acceleration_data[2]);
float joy_gravity_data[3];
motion->gamepad_motion->GetGravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]);
Vector3 joy_gravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]);
return (-joy_acceleration + joy_gravity) * STANDARD_GRAVITY;
}
Vector3 Input::get_joy_gravity(int p_device) const {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return Vector3();
}
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return Vector3();
}
float joy_gravity_data[3];
motion->gamepad_motion->GetGravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]);
Vector3 joy_gravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]);
return joy_gravity.normalized() * STANDARD_GRAVITY;
}
Vector3 Input::get_joy_gyroscope(int p_device) const {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return Vector3();
}
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return Vector3();
}
float joy_gyro_data[3];
motion->gamepad_motion->GetCalibratedGyro(joy_gyro_data[0], joy_gyro_data[1], joy_gyro_data[2]);
Vector3 joy_gyro(joy_gyro_data[0], joy_gyro_data[1], joy_gyro_data[2]);
return joy_gyro * M_PI / 180.0;
}
void Input::set_joy_motion_sensors_enabled(int p_device, bool p_enable) {
_THREAD_SAFE_METHOD_
Joypad *joypad = joy_names.getptr(p_device);
if (joypad == nullptr || joypad->features == nullptr) {
return;
}
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
joypad->features->set_joy_motion_sensors_enabled(p_enable);
motion->sensors_enabled = p_enable;
}
bool Input::is_joy_motion_sensors_enabled(int p_device) const {
_THREAD_SAFE_METHOD_
const MotionInfo *motion = joy_motion.getptr(p_device);
return motion != nullptr && motion->sensors_enabled;
}
bool Input::has_joy_motion_sensors(int p_device) const {
_THREAD_SAFE_METHOD_
return joy_motion.has(p_device);
}
float Input::get_joy_motion_sensors_rate(int p_device) const {
_THREAD_SAFE_METHOD_
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return 0.0f;
}
return motion->sensor_data_rate;
}
void Input::start_joy_motion_sensors_calibration(int p_device) {
_THREAD_SAFE_METHOD_
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
ERR_FAIL_COND_MSG(!motion->sensors_enabled, "Motion sensors are not enabled on the joypad.");
ERR_FAIL_COND_MSG(motion->calibrating, "Calibration already in progress.");
motion->gamepad_motion->ResetContinuousCalibration();
motion->gamepad_motion->StartContinuousCalibration();
motion->calibrating = true;
motion->calibrated = false;
}
void Input::stop_joy_motion_sensors_calibration(int p_device) {
_THREAD_SAFE_METHOD_
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
ERR_FAIL_COND_MSG(!motion->sensors_enabled, "Motion sensors are not enabled on the joypad.");
ERR_FAIL_COND_MSG(!motion->calibrating, "Calibration hasn't been started.");
motion->gamepad_motion->PauseContinuousCalibration();
motion->calibrating = false;
motion->calibrated = true;
}
void Input::clear_joy_motion_sensors_calibration(int p_device) {
_THREAD_SAFE_METHOD_
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
// Calibration might be in progress and the developer or the user might want to reset it,
// so no need to stop the calibration.
motion->gamepad_motion->ResetContinuousCalibration();
}
Dictionary Input::get_joy_motion_sensors_calibration(int p_device) const {
_THREAD_SAFE_METHOD_
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return Dictionary();
}
if (!motion->calibrated) {
return Dictionary();
}
float joy_gyro_offset_data[3];
motion->gamepad_motion->GetCalibrationOffset(joy_gyro_offset_data[0], joy_gyro_offset_data[1], joy_gyro_offset_data[2]);
Vector3 joy_gyro_offset(joy_gyro_offset_data[0], joy_gyro_offset_data[1], joy_gyro_offset_data[2]);
Dictionary result;
result["gyroscope_offset"] = joy_gyro_offset * M_PI / 180.0;
return result;
}
void Input::set_joy_motion_sensors_calibration(int p_device, const Dictionary &p_calibration_info) {
_THREAD_SAFE_METHOD_
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
ERR_FAIL_COND_MSG(motion->calibrating, "Calibration is currently in progress.");
Vector3 gyro_offset = p_calibration_info.get("gyroscope_offset", Vector3()).operator Vector3() * 180.0 / M_PI;
motion->gamepad_motion->SetCalibrationOffset(gyro_offset.x, gyro_offset.y, gyro_offset.z, 1);
motion->calibrating = false;
motion->calibrated = true;
}
bool Input::is_joy_motion_sensors_calibrating(int p_device) const {
_THREAD_SAFE_METHOD_
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return false;
}
return motion->calibrating;
}
bool Input::is_joy_motion_sensors_calibrated(int p_device) const {
_THREAD_SAFE_METHOD_
const MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return false;
}
return motion->calibrated;
}
void Input::set_joy_motion_sensors_rate(int p_device, float p_rate) {
_THREAD_SAFE_METHOD_
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
motion->sensor_data_rate = p_rate;
}
void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return;
}
if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
return;
}
@ -1045,6 +1321,17 @@ void Input::vibrate_handheld(int p_duration_ms, float p_amplitude) {
OS::get_singleton()->vibrate_handheld(p_duration_ms, p_amplitude);
}
void Input::set_ignore_joypad_on_unfocused_application(bool p_ignore) {
ignore_joypad_on_unfocused_application = p_ignore;
if (_should_ignore_joypad_events()) {
release_pressed_events();
}
}
bool Input::is_ignoring_joypad_on_unfocused_application() const {
return ignore_joypad_on_unfocused_application;
}
void Input::set_gravity(const Vector3 &p_gravity) {
_THREAD_SAFE_METHOD_
@ -1311,17 +1598,49 @@ bool Input::is_using_accumulated_input() {
}
void Input::release_pressed_events() {
// Don't release the events if the application (or the window it's embedded in) is still focused.
if (application_focused || embedder_focused) {
return;
}
flush_buffered_events(); // this is needed to release actions strengths
keys_pressed.clear();
physical_keys_pressed.clear();
key_label_pressed.clear();
joy_buttons_pressed.clear();
_joy_axis.clear();
if (ignore_joypad_on_unfocused_application) {
joy_buttons_pressed.clear();
_joy_axis.clear();
for (KeyValue<StringName, Input::ActionState> &E : action_states) {
if (E.value.cache.pressed) {
action_release(E.key);
for (KeyValue<StringName, Input::ActionState> &E : action_states) {
if (E.value.cache.pressed) {
action_release(E.key);
}
}
for (int device : get_connected_joypads()) {
stop_joy_vibration(device);
}
} else {
for (KeyValue<StringName, Input::ActionState> &E : action_states) {
if (E.value.cache.pressed) {
bool is_only_joypad_pressed = true;
int max_event = InputMap::get_singleton()->action_get_events(E.key)->size() + 1; // +1 comes from InputEventAction.
for (const KeyValue<int, ActionState::DeviceState> &kv : E.value.device_states) {
const ActionState::DeviceState &device_state = kv.value;
for (int i = 0; i < max_event; i++) {
if (device_state.event_type[i] != InputEventType::JOY_MOTION && device_state.event_type[i] != InputEventType::JOY_BUTTON && device_state.strength[i] > 0.0f) {
is_only_joypad_pressed = false;
action_release(E.key);
break;
}
}
if (!is_only_joypad_pressed) {
break;
}
}
}
}
}
}
@ -1332,6 +1651,11 @@ void Input::set_event_dispatch_function(EventDispatchFunc p_function) {
void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) {
_THREAD_SAFE_METHOD_;
if (_should_ignore_joypad_events()) {
return;
}
Joypad &joy = joy_names[p_device];
ERR_FAIL_INDEX((int)p_button, (int)JoyButton::MAX);
@ -1360,6 +1684,10 @@ void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) {
void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
_THREAD_SAFE_METHOD_;
if (_should_ignore_joypad_events()) {
return;
}
ERR_FAIL_INDEX((int)p_axis, (int)JoyAxis::MAX);
Joypad &joy = joy_names[p_device];
@ -1429,6 +1757,11 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
void Input::joy_hat(int p_device, BitField<HatMask> p_val) {
_THREAD_SAFE_METHOD_;
if (_should_ignore_joypad_events()) {
return;
}
const Joypad &joy = joy_names[p_device];
JoyEvent map[(size_t)HatDir::MAX];
@ -1469,6 +1802,27 @@ void Input::joy_hat(int p_device, BitField<HatMask> p_val) {
joy_names[p_device].hat_current = (int)p_val;
}
void Input::joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, const Vector3 &p_gyroscope) {
_THREAD_SAFE_METHOD_
if (_should_ignore_joypad_events()) {
return;
}
// TODO: events
MotionInfo *motion = joy_motion.getptr(p_device);
if (motion == nullptr) {
return;
}
Vector3 gyro_degrees = p_gyroscope * 180.0 / M_PI;
Vector3 accel_g = -p_accelerometer / STANDARD_GRAVITY;
uint64_t new_timestamp = OS::get_singleton()->get_ticks_msec();
float delta_time = (new_timestamp - motion->last_timestamp) / 1000.0f;
motion->last_timestamp = new_timestamp;
motion->gamepad_motion->ProcessMotion(gyro_degrees.x, gyro_degrees.y, gyro_degrees.z, accel_g.x, accel_g.y, accel_g.z, delta_time);
}
void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) {
Ref<InputEventJoypadButton> ievent;
ievent.instantiate();
@ -1517,9 +1871,22 @@ void Input::_update_joypad_features(int p_device) {
if (!joypad || joypad->features == nullptr) {
return;
}
if (joypad->features->has_joy_vibration()) {
joypad->has_vibration = true;
}
if (joypad->features->has_joy_light()) {
joypad->has_light = true;
}
if (joypad->features->has_joy_motion_sensors()) {
MotionInfo &motion = joy_motion[p_device];
if (!motion.gamepad_motion) {
motion.gamepad_motion = new GamepadMotion();
} else {
motion.gamepad_motion->Reset();
}
motion.last_timestamp = OS::get_singleton()->get_ticks_msec();
}
}
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
@ -2004,6 +2371,7 @@ Input::Input() {
gravity_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gravity", false);
gyroscope_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gyroscope", false);
magnetometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_magnetometer", false);
ignore_joypad_on_unfocused_application = GLOBAL_DEF_RST_BASIC("input_devices/joypads/ignore_joypad_on_unfocused_application", false);
}
Input::~Input() {

View file

@ -38,6 +38,43 @@
#include "core/templates/rb_set.h"
#include "core/variant/typed_array.h"
class GamepadMotion;
namespace InputClassEnums {
// Keep synced with DisplayServerEnums::MouseMode enum.
enum MouseMode : int {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED,
MOUSE_MODE_CONFINED,
MOUSE_MODE_CONFINED_HIDDEN,
MOUSE_MODE_MAX,
};
// Keep synced with DisplayServerEnums and Control enums.
#undef CursorShape
enum CursorShape : int {
CURSOR_ARROW,
CURSOR_IBEAM,
CURSOR_POINTING_HAND,
CURSOR_CROSS,
CURSOR_WAIT,
CURSOR_BUSY,
CURSOR_DRAG,
CURSOR_CAN_DROP,
CURSOR_FORBIDDEN,
CURSOR_VSIZE,
CURSOR_HSIZE,
CURSOR_BDIAGSIZE,
CURSOR_FDIAGSIZE,
CURSOR_MOVE,
CURSOR_VSPLIT,
CURSOR_HSPLIT,
CURSOR_HELP,
CURSOR_MAX
};
} //namespace InputClassEnums
class Input : public Object {
GDCLASS(Input, Object);
_THREAD_SAFE_CLASS_
@ -47,44 +84,21 @@ class Input : public Object {
static constexpr uint64_t MAX_EVENT = 32;
public:
// Keep synced with "DisplayServer::MouseMode" enum.
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED,
MOUSE_MODE_CONFINED,
MOUSE_MODE_CONFINED_HIDDEN,
MOUSE_MODE_MAX,
};
#undef CursorShape
enum CursorShape {
CURSOR_ARROW,
CURSOR_IBEAM,
CURSOR_POINTING_HAND,
CURSOR_CROSS,
CURSOR_WAIT,
CURSOR_BUSY,
CURSOR_DRAG,
CURSOR_CAN_DROP,
CURSOR_FORBIDDEN,
CURSOR_VSIZE,
CURSOR_HSIZE,
CURSOR_BDIAGSIZE,
CURSOR_FDIAGSIZE,
CURSOR_MOVE,
CURSOR_VSPLIT,
CURSOR_HSPLIT,
CURSOR_HELP,
CURSOR_MAX
};
// TODO: When we migrate to C++20, replace these with "using enum" and skip prefixing MouseMode and CursorShape in other files.
using MouseMode = InputClassEnums::MouseMode;
using CursorShape = InputClassEnums::CursorShape;
class JoypadFeatures {
public:
virtual ~JoypadFeatures() {}
virtual bool has_joy_vibration() const { return false; }
virtual bool has_joy_light() const { return false; }
virtual void set_joy_light(const Color &p_color) {}
virtual bool has_joy_motion_sensors() const { return false; }
virtual void set_joy_motion_sensors_enabled(bool p_enable) {}
};
static constexpr int32_t JOYPADS_MAX = 16;
@ -112,6 +126,9 @@ private:
int64_t mouse_window = 0;
bool legacy_just_pressed_behavior = false;
bool disable_input = false;
bool ignore_joypad_on_unfocused_application = false;
bool application_focused = true;
bool embedder_focused = false;
struct ActionState {
uint64_t pressed_physics_frame = UINT64_MAX;
@ -126,6 +143,7 @@ private:
bool pressed[MAX_EVENT] = { false };
float strength[MAX_EVENT] = { 0.0 };
float raw_strength[MAX_EVENT] = { 0.0 };
InputEventType event_type[MAX_EVENT] = { InputEventType::INVALID };
};
bool api_pressed = false;
float api_strength = 0.0;
@ -157,6 +175,23 @@ private:
HashMap<int, VibrationInfo> joy_vibration;
struct MotionInfo {
bool sensors_enabled : 1;
bool calibrating : 1;
bool calibrated : 1;
float sensor_data_rate = 0.0f;
uint64_t last_timestamp = 0;
GamepadMotion *gamepad_motion = nullptr;
MotionInfo() {
sensors_enabled = false;
calibrating = false;
calibrated = false;
}
};
HashMap<int, MotionInfo> joy_motion;
struct VelocityTrack {
uint64_t last_tick = 0;
Vector2 velocity;
@ -184,6 +219,7 @@ private:
int hat_current = 0;
Dictionary info;
bool has_light = false;
bool has_vibration = false;
Input::JoypadFeatures *features = nullptr;
};
@ -195,7 +231,7 @@ private:
int fallback_mapping = -1; // Index of the guid in map_db.
CursorShape default_shape = CURSOR_ARROW;
CursorShape default_shape = CursorShape::CURSOR_ARROW;
enum JoyType {
TYPE_BUTTON,
@ -275,6 +311,8 @@ private:
#endif
friend class DisplayServer;
friend class SceneTree;
friend class SceneDebugger;
static void (*set_mouse_mode_func)(MouseMode);
static MouseMode (*get_mouse_mode_func)();
@ -289,6 +327,8 @@ private:
EventDispatchFunc event_dispatch_function = nullptr;
bool _should_ignore_joypad_events() const;
#ifndef DISABLE_DEPRECATED
void _vibrate_handheld_bind_compat_91143(int p_duration_ms = 500);
static void _bind_compatibility_methods();
@ -312,7 +352,7 @@ public:
static Input *get_singleton();
bool is_anything_pressed() const;
bool is_anything_pressed_except_mouse() const;
bool is_any_key_pressed() const;
bool is_key_pressed(Key p_keycode) const;
bool is_physical_key_pressed(Key p_keycode) const;
bool is_key_label_pressed(Key p_keycode) const;
@ -334,7 +374,10 @@ public:
TypedArray<int> get_connected_joypads();
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
float get_joy_vibration_remaining_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
bool is_joy_vibrating(int p_device);
bool has_joy_vibration(int p_device) const;
void joy_connection_changed(int p_idx, bool p_connected, const String &p_name, const String &p_guid = "", const Dictionary &p_joypad_info = Dictionary());
Vector3 get_gravity() const;
@ -363,10 +406,35 @@ public:
void set_joy_light(int p_device, const Color &p_color);
bool has_joy_light(int p_device) const;
Vector3 get_joy_accelerometer(int p_device) const;
Vector3 get_joy_gravity(int p_device) const;
Vector3 get_joy_gyroscope(int p_device) const;
void set_joy_motion_sensors_enabled(int p_device, bool p_enable);
bool is_joy_motion_sensors_enabled(int p_device) const;
bool has_joy_motion_sensors(int p_device) const;
float get_joy_motion_sensors_rate(int p_device) const;
void start_joy_motion_sensors_calibration(int p_device);
void stop_joy_motion_sensors_calibration(int p_device);
void clear_joy_motion_sensors_calibration(int p_device);
Dictionary get_joy_motion_sensors_calibration(int p_device) const;
void set_joy_motion_sensors_calibration(int p_device, const Dictionary &p_calibration_info);
bool is_joy_motion_sensors_calibrating(int p_device) const;
bool is_joy_motion_sensors_calibrated(int p_device) const;
void set_joy_motion_sensors_rate(int p_device, float p_rate);
void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
void stop_joy_vibration(int p_device);
void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);
void set_ignore_joypad_on_unfocused_application(bool p_ignore);
bool is_ignoring_joypad_on_unfocused_application() const;
void set_mouse_position(const Point2 &p_posf);
void action_press(const StringName &p_action, float p_strength = 1.f);
@ -382,12 +450,13 @@ public:
CursorShape get_default_cursor_shape() const;
void set_default_cursor_shape(CursorShape p_shape);
CursorShape get_current_cursor_shape() const;
void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CursorShape::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
void parse_mapping(const String &p_mapping);
void joy_button(int p_device, JoyButton p_button, bool p_pressed);
void joy_axis(int p_device, JoyAxis p_axis, float p_value);
void joy_hat(int p_device, BitField<HatMask> p_val);
void joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, const Vector3 &p_gyroscope);
void add_joy_mapping(const String &p_mapping, bool p_update_existing = false);
void remove_joy_mapping(const String &p_guid);

View file

@ -100,7 +100,12 @@ enum class JoyButton {
PADDLE3 = 18,
PADDLE4 = 19,
TOUCHPAD = 20,
SDL_MAX = 21,
MISC2 = 21,
MISC3 = 22,
MISC4 = 23,
MISC5 = 24,
MISC6 = 25,
SDL_MAX = 26,
MAX = 128, // Android supports up to 36 buttons. DirectInput supports up to 128 buttons.
};

View file

@ -32,8 +32,11 @@
#include "core/input/input_map.h"
#include "core/input/shortcut.h"
#include "core/math/transform_2d.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/ustring.h"
void InputEvent::set_device(int p_device) {
device = p_device;
@ -131,6 +134,8 @@ void InputEvent::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device");
BIND_CONSTANT(DEVICE_ID_EMULATION);
BIND_CONSTANT(DEVICE_ID_KEYBOARD);
BIND_CONSTANT(DEVICE_ID_MOUSE);
}
///////////////////////////////////
@ -314,8 +319,7 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &p_property) const
if (p_property.name == "meta_pressed") {
p_property.usage ^= PROPERTY_USAGE_STORAGE;
p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
if (p_property.name == "ctrl_pressed") {
} else if (p_property.name == "ctrl_pressed") {
p_property.usage ^= PROPERTY_USAGE_STORAGE;
p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
@ -662,6 +666,10 @@ void InputEventKey::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo");
}
InputEventKey::InputEventKey() {
set_device(DEVICE_ID_KEYBOARD);
}
///////////////////////////////////
void InputEventMouse::set_button_mask(BitField<MouseButtonMask> p_mask) {
@ -704,6 +712,10 @@ void InputEventMouse::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px"), "set_global_position", "get_global_position");
}
InputEventMouse::InputEventMouse() {
set_device(DEVICE_ID_MOUSE);
}
///////////////////////////////////
void InputEventMouseButton::set_factor(float p_factor) {
@ -1920,7 +1932,7 @@ void InputEventShortcut::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &InputEventShortcut::set_shortcut);
ClassDB::bind_method(D_METHOD("get_shortcut"), &InputEventShortcut::get_shortcut);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, Shortcut::get_class_static()), "set_shortcut", "get_shortcut");
}
String InputEventShortcut::as_text() const {

View file

@ -32,9 +32,7 @@
#include "core/input/input_enums.h"
#include "core/io/resource.h"
#include "core/math/transform_2d.h"
#include "core/os/keyboard.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
/**
@ -43,6 +41,8 @@
*/
class Shortcut;
class String;
struct Transform2D;
/**
* Input Modifier Status
@ -63,6 +63,8 @@ protected:
public:
static constexpr int DEVICE_ID_EMULATION = -1;
static constexpr int DEVICE_ID_INTERNAL = -2;
static constexpr int DEVICE_ID_KEYBOARD = 16; // IDs 0-15 are reserved for joypads.
static constexpr int DEVICE_ID_MOUSE = 32; // IDs 17-31 are reserved for multiple keyboard support in the future.
void set_device(int p_device);
int get_device() const;
@ -199,6 +201,8 @@ public:
static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
InputEventType get_type() const final override { return InputEventType::KEY; }
InputEventKey();
};
class InputEventMouse : public InputEventWithModifiers {
@ -221,6 +225,8 @@ public:
void set_global_position(const Vector2 &p_global_pos);
Vector2 get_global_position() const;
InputEventMouse();
};
class InputEventMouseButton : public InputEventMouse {

View file

@ -32,7 +32,6 @@
#include "core/input/input.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
enum class BoolShift : uint8_t {
SHIFT = 0,

View file

@ -30,6 +30,10 @@
#ifndef DISABLE_DEPRECATED
#include "input_map.h"
#include "core/object/class_db.h"
void InputMap::_add_action_bind_compat_97281(const StringName &p_action, float p_deadzone) {
add_action(p_action, p_deadzone);
}

View file

@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/variant/typed_array.h"
@ -205,6 +206,22 @@ void InputMap::action_add_event(const StringName &p_action, RequiredParam<InputE
return; // Already added.
}
// Normalize legacy device IDs: before the device ID change,
// keyboard and mouse events defaulted to device=0.
if (p_event->get_device() == 0) {
switch (p_event->get_type()) {
case InputEventType::KEY:
p_event->set_device(InputEvent::DEVICE_ID_KEYBOARD);
break;
case InputEventType::MOUSE_BUTTON:
case InputEventType::MOUSE_MOTION:
p_event->set_device(InputEvent::DEVICE_ID_MOUSE);
break;
default:
break;
}
}
input_map[p_action].inputs.push_back(p_event);
}
@ -319,6 +336,11 @@ void InputMap::load_from_project_settings() {
String name = pi.name.substr(pi.name.find_char('/') + 1);
Dictionary action = GLOBAL_GET(pi.name);
if (!action.has("events")) {
continue;
}
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
Array events = action["events"];
@ -543,16 +565,16 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::SPACE | KeyModifierMask::CTRL));
default_builtin_cache.insert("ui_text_completion_query", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB));
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::TAB));
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::ENTER));
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::KP_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB));
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_completion_replace", inputs);
// Newlines
@ -904,7 +926,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_featur
}
void InputMap::load_default() {
HashMap<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
HashMap<String, List<Ref<InputEvent>>> builtins(get_builtins_with_feature_overrides_applied());
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
String name = E.key;

View file

@ -30,6 +30,8 @@
#include "shortcut.h"
#include "core/object/class_db.h"
void Shortcut::set_events(const Array &p_events) {
for (int i = 0; i < p_events.size(); i++) {
Ref<InputEventShortcut> ies = p_events[i];

View file

@ -30,7 +30,6 @@
#include "compression.h"
#include "core/config/project_settings.h"
#include "core/io/zip_io.h"
#include "thirdparty/misc/fastlz.h"

View file

@ -31,6 +31,7 @@
#include "config_file.h"
#include "core/io/file_access_encrypted.h"
#include "core/object/class_db.h"
#include "core/string/string_builder.h"
#include "core/variant/variant_parser.h"

View file

@ -30,6 +30,10 @@
#include "delta_encoding.h"
#include "core/error/error_list.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h" // vformat
#include <zstd.h>
#define ERR_FAIL_ZSTD_V_MSG(m_result, m_retval, m_msg) \

View file

@ -30,7 +30,12 @@
#pragma once
#include "core/io/file_access.h"
#include "core/templates/span.h"
#include <cstdint>
template <typename T>
class Vector;
class DeltaEncoding {
public:

View file

@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "core/os/time.h"
#include "core/templates/local_vector.h"

View file

@ -30,6 +30,8 @@
#include "dtls_server.h"
#include "core/object/class_db.h"
DTLSServer *DTLSServer::create(bool p_notify_postinitialize) {
if (_create) {
return _create(p_notify_postinitialize);

View file

@ -30,7 +30,6 @@
#pragma once
#include "core/io/net_socket.h"
#include "core/io/packet_peer_dtls.h"
class DTLSServer : public RefCounted {

View file

@ -30,6 +30,10 @@
#ifndef DISABLE_DEPRECATED
#include "file_access.h"
#include "core/object/class_db.h"
Ref<FileAccess> FileAccess::_open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
return open_encrypted(p_path, p_mode_flags, p_key, Vector<uint8_t>());
}
@ -123,4 +127,4 @@ void FileAccess::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text_bind_compat_110867, DEFVAL(false));
}
#endif
#endif // DISABLE_DEPRECATED

View file

@ -38,6 +38,7 @@
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/io/resource_uid.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "core/os/time.h"
@ -425,7 +426,7 @@ class CharBuffer {
int64_t written = 0;
bool grow() {
if (vector.resize(next_power_of_2((uint64_t)1 + (uint64_t)written)) != OK) {
if (vector.resize(Math::next_power_of_2((uint64_t)1 + (uint64_t)written)) != OK) {
return false;
}

View file

@ -36,6 +36,7 @@
#include "core/os/memory.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
#include "core/variant/type_info.h"
/**
* Multi-Platform abstraction for accessing to files.

View file

@ -30,6 +30,8 @@
#include "file_access_compressed.h"
#include "core/math/math_funcs_binary.h"
void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, uint32_t p_block_size) {
magic = p_magic.ascii().get_data();
magic = (magic + " ").substr(0, 4);
@ -320,7 +322,7 @@ bool FileAccessCompressed::store_buffer(const uint8_t *p_src, uint64_t p_length)
write_max = write_pos + (p_length);
}
if (write_max > write_buffer_size) {
write_buffer_size = next_power_of_2(write_max);
write_buffer_size = Math::next_power_of_2(write_max);
ERR_FAIL_COND_V(buffer.resize(write_buffer_size) != OK, false);
write_ptr = buffer.ptrw();
}

View file

@ -36,9 +36,9 @@
#include "core/os/os.h"
#include "core/version.h"
Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
for (int i = 0; i < sources.size(); i++) {
if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset, p_decryption_key)) {
return OK;
}
}
@ -46,7 +46,7 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t
return ERR_FILE_UNRECOGNIZED;
}
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted, bool p_bundle, bool p_delta) {
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted, bool p_bundle, bool p_delta, const String &p_salt) {
String simplified_path = p_path.simplify_path().trim_prefix("res://");
PathMD5 pmd5(simplified_path.md5_buffer());
@ -57,6 +57,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
pf.bundle = p_bundle;
pf.delta = p_delta;
pf.pack = p_pkg_path;
pf.salt = p_salt;
pf.offset = p_ofs;
pf.size = p_size;
for (int i = 0; i < 16; i++) {
@ -214,7 +215,7 @@ PackedData::~PackedData() {
//////////////////////////////////////////////////////////////////
bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
return false;
@ -291,22 +292,28 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
uint32_t ver_minor = f->get_32();
uint32_t ver_patch = f->get_32(); // Not used for validation.
ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION_V3 && version != PACK_FORMAT_VERSION_V2, false, vformat("Pack version unsupported: %d.", version));
ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION_V4 && version != PACK_FORMAT_VERSION_V3 && version != PACK_FORMAT_VERSION_V2, false, vformat("Pack version unsupported: %d.", version));
ERR_FAIL_COND_V_MSG(ver_major > GODOT_VERSION_MAJOR || (ver_major == GODOT_VERSION_MAJOR && ver_minor > GODOT_VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.%d.", ver_major, ver_minor, ver_patch));
uint32_t pack_flags = f->get_32();
bool enc_directory = (pack_flags & PACK_DIR_ENCRYPTED);
bool rel_filebase = (pack_flags & PACK_REL_FILEBASE); // Note: Always enabled for V3.
bool sparse_bundle = (pack_flags & PACK_SPARSE_BUNDLE);
String salt;
uint64_t file_base = f->get_64();
if ((version == PACK_FORMAT_VERSION_V3) || (version == PACK_FORMAT_VERSION_V2 && rel_filebase)) {
if ((version == PACK_FORMAT_VERSION_V4) || (version == PACK_FORMAT_VERSION_V3) || (version == PACK_FORMAT_VERSION_V2 && rel_filebase)) {
file_base += pck_start_pos;
}
if (version == PACK_FORMAT_VERSION_V3) {
// V3: Read directory offset and skip reserved part of the header.
if (version == PACK_FORMAT_VERSION_V3 || version == PACK_FORMAT_VERSION_V4) {
// V3/V4: Read directory offset and skip reserved part of the header.
uint64_t dir_offset = f->get_64() + pck_start_pos;
if (sparse_bundle && enc_directory && version == PACK_FORMAT_VERSION_V4) {
// V4: Read encrypted directory salt.
Vector<uint8_t> salt_data = f->get_buffer(32);
salt.append_latin1(Span((const char *)salt_data.ptr(), salt_data.size()));
}
f->seek(dir_offset);
} else if (version == PACK_FORMAT_VERSION_V2) {
// V2: Directory directly after the header.
@ -323,9 +330,18 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
ERR_FAIL_COND_V_MSG(fae.is_null(), false, "Can't open encrypted pack directory.");
Vector<uint8_t> key;
key.resize(32);
for (int i = 0; i < key.size(); i++) {
key.write[i] = script_encryption_key[i];
#ifdef TOOLS_ENABLED
if (!p_decryption_key.is_empty()) {
ERR_FAIL_COND_V_MSG(p_decryption_key.size() != 32, false, "Decryption key must be 256-bit.");
constexpr uint8_t empty_key[32] = {};
if (memcmp(script_encryption_key, empty_key, sizeof(empty_key)) == 0) {
key = p_decryption_key;
}
} else
#endif
{
key.resize(32);
memcpy(key.ptrw(), script_encryption_key, 32);
}
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
@ -350,15 +366,15 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
if (flags & PACK_FILE_REMOVAL) { // The file was removed.
PackedData::get_singleton()->remove_path(path);
} else {
PackedData::get_singleton()->add_path(p_path, path, file_base + ofs, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED), sparse_bundle, (flags & PACK_FILE_DELTA));
PackedData::get_singleton()->add_path(p_path, path, file_base + ofs, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED), sparse_bundle, (flags & PACK_FILE_DELTA), salt);
}
}
return true;
}
Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) {
Ref<FileAccess> file(memnew(FileAccessPack(p_path, *p_file)));
Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
Ref<FileAccess> file(memnew(FileAccessPack(p_path, *p_file, p_decryption_key)));
if (PackedData::get_singleton()->has_delta_patches(p_path)) {
Ref<FileAccessPatched> file_patched;
@ -373,7 +389,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
//////////////////////////////////////////////////////////////////
bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
// Load with offset feature only supported for PCK files.
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with directories.");
@ -384,7 +400,7 @@ bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_f
return true;
}
Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file) {
Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
Ref<FileAccess> ret = FileAccess::create_for_path(p_path);
ret->reopen(p_path, FileAccess::READ);
return ret;
@ -507,12 +523,24 @@ void FileAccessPack::close() {
f = Ref<FileAccess>();
}
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) {
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file, const Vector<uint8_t> &p_decryption_key) {
path = p_path;
pf = p_file;
if (pf.bundle) {
String simplified_path = p_path.simplify_path();
f = FileAccess::open(simplified_path, FileAccess::READ | FileAccess::SKIP_PACK);
String path_to_load = simplified_path;
#ifdef TOOLS_ENABLED
if (!pf.salt.is_empty()) {
path_to_load = pf.pack.get_base_dir().path_join((simplified_path + pf.salt).sha256_text());
} else {
path_to_load = pf.pack.get_base_dir().path_join(simplified_path.replace("res://", ""));
}
#else
if (!pf.salt.is_empty()) {
path_to_load = "res://" + (simplified_path + pf.salt).sha256_text();
}
#endif
f = FileAccess::open(path_to_load, FileAccess::READ | FileAccess::SKIP_PACK);
ERR_FAIL_COND_MSG(f.is_null(), vformat(R"(Can't open pack-referenced file "%s" from sparse pack "%s".)", simplified_path, pf.pack));
off = 0; // For the sparse pack offset is always zero.
} else {
@ -528,9 +556,18 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
ERR_FAIL_COND_MSG(fae.is_null(), vformat(R"(Can't open encrypted pack-referenced file "%s" from pack "%s".)", p_path, pf.pack));
Vector<uint8_t> key;
key.resize(32);
for (int i = 0; i < key.size(); i++) {
key.write[i] = script_encryption_key[i];
#ifdef TOOLS_ENABLED
if (!p_decryption_key.is_empty()) {
ERR_FAIL_COND_MSG(p_decryption_key.size() != 32, "Decryption key must be 256-bit.");
constexpr uint8_t empty_key[32] = {};
if (memcmp(script_encryption_key, empty_key, sizeof(empty_key)) == 0) {
key = p_decryption_key;
}
} else
#endif
{
key.resize(32);
memcpy(key.ptrw(), script_encryption_key, 32);
}
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);

View file

@ -32,6 +32,7 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/resource_uid.h"
#include "core/string/print_string.h"
#include "core/templates/hash_set.h"
#include "core/templates/list.h"
@ -41,9 +42,10 @@
#define PACK_FORMAT_VERSION_V2 2
#define PACK_FORMAT_VERSION_V3 3
#define PACK_FORMAT_VERSION_V4 4
// The current packed file format version number.
#define PACK_FORMAT_VERSION PACK_FORMAT_VERSION_V3
#define PACK_FORMAT_VERSION PACK_FORMAT_VERSION_V4
enum PackFlags {
PACK_DIR_ENCRYPTED = 1 << 0,
@ -74,6 +76,7 @@ public:
bool encrypted;
bool bundle;
bool delta;
String salt;
};
private:
@ -117,9 +120,18 @@ private:
void _free_packed_dirs(PackedDir *p_dir);
void _get_file_paths(PackedDir *p_dir, const String &p_parent_dir, HashSet<String> &r_paths) const;
_FORCE_INLINE_ PathMD5 _get_simplified_path(const String &p_path) {
String simplified_path = p_path;
if (simplified_path.begins_with("uid://")) {
simplified_path = ResourceUID::uid_to_path(simplified_path);
}
simplified_path = simplified_path.simplify_path().trim_prefix("res://");
return PathMD5(simplified_path.md5_buffer());
}
public:
void add_pack_source(PackSource *p_source);
void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false, bool p_bundle = false, bool p_delta = false); // for PackSource
void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false, bool p_bundle = false, bool p_delta = false, const String &p_salt = String()); // for PackSource
void remove_path(const String &p_path);
uint8_t *get_file_hash(const String &p_path);
Vector<PackedFile> get_delta_patches(const String &p_path) const;
@ -130,11 +142,11 @@ public:
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
static PackedData *get_singleton() { return singleton; }
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
void clear();
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
_FORCE_INLINE_ bool has_path(const String &p_path);
_FORCE_INLINE_ int64_t get_size(const String &p_path);
@ -148,23 +160,23 @@ public:
class PackSource {
public:
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) = 0;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) = 0;
virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
public:
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
};
class PackedSourceDirectory : public PackSource {
void add_directory(const String &p_path, bool p_replace_files);
public:
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
};
class FileAccessPack : public FileAccess {
@ -216,13 +228,11 @@ public:
virtual void close() override;
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
};
int64_t PackedData::get_size(const String &p_path) {
String simplified_path = p_path.simplify_path();
PathMD5 pmd5(simplified_path.md5_buffer());
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(_get_simplified_path(p_path));
if (!E) {
return -1; // File not found.
}
@ -232,19 +242,17 @@ int64_t PackedData::get_size(const String &p_path) {
return E->value.size;
}
Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
String simplified_path = p_path.simplify_path().trim_prefix("res://");
PathMD5 pmd5(simplified_path.md5_buffer());
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
Ref<FileAccess> PackedData::try_open_path(const String &p_path, const Vector<uint8_t> &p_decryption_key) {
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(_get_simplified_path(p_path));
if (!E) {
return nullptr; // Not found.
}
return E->value.src->get_file(p_path, &E->value);
return E->value.src->get_file(p_path, &E->value, p_decryption_key);
}
bool PackedData::has_path(const String &p_path) {
return files.has(PathMD5(p_path.simplify_path().trim_prefix("res://").md5_buffer()));
return files.has(_get_simplified_path(p_path));
}
bool PackedData::has_directory(const String &p_path) {

View file

@ -144,7 +144,7 @@ unzFile ZipArchive::get_file_handle(const String &p_file) const {
return pkg;
}
bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset = 0) {
bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
// load with offset feature only supported for PCK files
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives.");
@ -209,7 +209,7 @@ bool ZipArchive::file_exists(const String &p_name) const {
return files.has(p_name);
}
Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) {
Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
return memnew(FileAccessZip(p_path, *p_file));
}

View file

@ -61,8 +61,8 @@ public:
bool file_exists(const String &p_name) const;
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
static ZipArchive *get_singleton();

View file

@ -30,6 +30,8 @@
#include "http_client.h"
#include "core/object/class_db.h"
const char *HTTPClient::_methods[METHOD_MAX] = {
"GET",
"HEAD",
@ -167,7 +169,7 @@ void HTTPClient::_bind_methods() {
ClassDB::bind_method(D_METHOD("query_string_from_dict", "fields"), &HTTPClient::query_string_from_dict);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_mode_enabled"), "set_blocking_mode", "is_blocking_mode_enabled");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", PROPERTY_USAGE_NONE), "set_connection", "get_connection");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, StreamPeer::get_class_static(), PROPERTY_USAGE_NONE), "set_connection", "get_connection");
ADD_PROPERTY(PropertyInfo(Variant::INT, "read_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_read_chunk_size", "get_read_chunk_size");
BIND_ENUM_CONSTANT(METHOD_GET);

View file

@ -31,9 +31,7 @@
#pragma once
#include "core/crypto/crypto.h"
#include "core/io/ip.h"
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_tcp.h"
#include "core/object/ref_counted.h"
class HTTPClient : public RefCounted {

View file

@ -32,7 +32,10 @@
#include "http_client_tcp.h"
#include "core/io/stream_peer_tcp.h"
#include "core/io/stream_peer_tls.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "core/version.h"
HTTPClient *HTTPClientTCP::_create_func(bool p_notify_postinitialize) {

View file

@ -33,6 +33,9 @@
#include "http_client.h"
#include "core/crypto/crypto.h"
#include "core/io/ip.h"
class StreamPeerTCP;
class HTTPClientTCP : public HTTPClient {
GDSOFTCLASS(HTTPClientTCP, HTTPClient);

View file

@ -35,6 +35,7 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/templates/hash_map.h"
#include "core/variant/dictionary.h"
@ -1231,14 +1232,14 @@ static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst,
}
bool Image::is_size_po2() const {
return is_power_of_2(width) && is_power_of_2(height);
return Math::is_power_of_2(width) && Math::is_power_of_2(height);
}
void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats.");
int w = next_power_of_2((uint32_t)width);
int h = next_power_of_2((uint32_t)height);
int w = Math::next_power_of_2((uint32_t)width);
int h = Math::next_power_of_2((uint32_t)height);
if (p_square) {
w = h = MAX(w, h);
}
@ -1255,9 +1256,6 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(data.is_empty(), "Cannot resize image before creating it, use set_data() first.");
ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, vformat("Image width cannot be greater than %d pixels.", MAX_WIDTH));
@ -1268,9 +1266,19 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
return;
}
// Convert the image to 'standard' RGB(A) formats that may be resized.
Format original_format = format;
if (original_format == FORMAT_RGB565 || original_format == FORMAT_RGBA4444) {
convert(FORMAT_RGBA8);
} else if (original_format == FORMAT_RGBE9995) {
convert(FORMAT_RGBH);
}
Image dst(p_width, p_height, false, format);
// Setup mipmap-aware scaling
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
Image dst2;
int mip1 = 0;
int mip2 = 0;
@ -1614,6 +1622,11 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
_copy_internals_from(dst);
// Reconvert the image to its original format.
if (original_format != format) {
convert(original_format);
}
}
void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) {
@ -2600,24 +2613,24 @@ void Image::initialize_data(const char **p_xpm) {
#define DETECT_ALPHA_MAX_THRESHOLD 254
#define DETECT_ALPHA_MIN_THRESHOLD 2
#define DETECT_ALPHA(m_value) \
{ \
uint8_t value = m_value; \
if (value < DETECT_ALPHA_MIN_THRESHOLD) \
bit = true; \
#define DETECT_ALPHA(m_value) \
{ \
uint8_t value = m_value; \
if (value < DETECT_ALPHA_MIN_THRESHOLD) \
bit = true; \
else if (value < DETECT_ALPHA_MAX_THRESHOLD) { \
detected = true; \
break; \
} \
detected = true; \
break; \
} \
}
#define DETECT_NON_ALPHA(m_value) \
{ \
uint8_t value = m_value; \
if (value > 0) { \
detected = true; \
break; \
} \
{ \
uint8_t value = m_value; \
if (value > 0) { \
detected = true; \
break; \
} \
}
bool Image::is_invisible() const {

View file

@ -30,6 +30,8 @@
#include "image_loader.h"
#include "core/object/class_db.h"
void ImageFormatLoader::_bind_methods() {
BIND_BITFIELD_FLAG(FLAG_NONE);
BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);

View file

@ -30,14 +30,13 @@
#pragma once
#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/gdvirtual.gen.h"
#include "core/string/ustring.h"
#include "core/templates/list.h"
#include "core/variant/binder_common.h"
#include "core/variant/type_info.h"
class ImageLoader;

View file

@ -30,6 +30,7 @@
#include "ip.h"
#include "core/object/class_db.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/hash_map.h"
@ -205,7 +206,7 @@ IPAddress IP::get_resolve_item_address(ResolverID p_id) const {
return IPAddress();
}
List<IPAddress> res = resolver->queue[p_id].response;
List<IPAddress> res(resolver->queue[p_id].response);
for (const IPAddress &E : res) {
if (E.is_valid()) {
@ -224,7 +225,7 @@ Array IP::get_resolve_item_addresses(ResolverID p_id) const {
return Array();
}
List<IPAddress> res = resolver->queue[p_id].response;
List<IPAddress> res(resolver->queue[p_id].response);
Array result;
for (const IPAddress &E : res) {

View file

@ -31,7 +31,7 @@
#pragma once
#include "core/io/ip_address.h"
#include "core/os/os.h"
#include "core/variant/type_info.h"
template <typename T>
class TypedArray;

View file

@ -32,6 +32,7 @@
#include "core/config/engine.h"
#include "core/io/file_access.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/variant/container_type_validate.h"
@ -155,6 +156,11 @@ void JSON::_stringify(String &r_result, const Variant &p_var, const String &p_in
ERR_FAIL_MSG("Converting circular structure to JSON.");
}
if (d.is_empty()) {
r_result += "{}";
return;
}
r_result += '{';
r_result += end_statement;
p_markers.insert(d.id());
@ -668,10 +674,10 @@ static bool _encode_container_type(Dictionary &r_dict, const String &p_key, cons
}
Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_depth) {
#define RETURN_ARGS \
Dictionary ret; \
#define RETURN_ARGS \
Dictionary ret; \
ret[TYPE] = Variant::get_type_name(p_variant.get_type()); \
ret[ARGS] = args; \
ret[ARGS] = args; \
return ret
switch (p_variant.get_type()) {
@ -1093,18 +1099,18 @@ Variant JSON::_to_native(const Variant &p_json, bool p_allow_objects, int p_dept
ERR_FAIL_COND_V(!dict.has(TYPE), Variant());
#define LOAD_ARGS() \
#define LOAD_ARGS() \
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
const Array args = dict[ARGS]
#define LOAD_ARGS_CHECK_SIZE(m_size) \
#define LOAD_ARGS_CHECK_SIZE(m_size) \
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
const Array args = dict[ARGS]; \
const Array args = dict[ARGS]; \
ERR_FAIL_COND_V(args.size() != (m_size), Variant())
#define LOAD_ARGS_CHECK_FACTOR(m_factor) \
#define LOAD_ARGS_CHECK_FACTOR(m_factor) \
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
const Array args = dict[ARGS]; \
const Array args = dict[ARGS]; \
ERR_FAIL_COND_V(args.size() % (m_factor) != 0, Variant())
switch (Variant::get_type_by_name(dict[TYPE])) {

Some files were not shown because too many files have changed in this diff Show more