Compare commits
No commits in common. "development" and "archive/old-template" have entirely different histories.
developmen
...
archive/ol
5109 changed files with 254245 additions and 600678 deletions
15
.gitattributes
vendored
15
.gitattributes
vendored
|
|
@ -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
0
.gitmodules
vendored
Normal file
|
|
@ -1,5 +1,5 @@
|
|||
# If you change this file, please format all files of the codebase as part of your PR:
|
||||
# prek run clang-format --all
|
||||
# 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
|
||||
|
|
@ -117,25 +117,14 @@ Cpp11BracedListStyle: false
|
|||
# - BOOST_FOREACH
|
||||
# IfMacros:
|
||||
# - KJ_IF_MAYBE
|
||||
IncludeBlocks: Regroup
|
||||
# IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: ^"(core|drivers|editor|main|scene|servers|tests)/.*"$
|
||||
Priority: 20
|
||||
- Regex: ^"(modules|platform)/.*"$
|
||||
Priority: 30
|
||||
- Regex: ^<thirdparty/.*>$
|
||||
Priority: 40
|
||||
- Regex: ^<(windows|Jolt/Jolt|platform_gl)\.h>$
|
||||
Priority: 50
|
||||
- Regex: ^<.*\.(h|hpp)>$
|
||||
Priority: 60
|
||||
- Regex: ^<.*>$
|
||||
Priority: 70
|
||||
- Regex: ^".*\.compat\.inc"$
|
||||
Priority: 0
|
||||
SortPriority: 1
|
||||
- Regex: ^".*"$
|
||||
Priority: 10
|
||||
Priority: 1
|
||||
- Regex: ^<.*\.h>$
|
||||
Priority: 2
|
||||
- Regex: ^<.*>$
|
||||
Priority: 3
|
||||
# IncludeIsMainRegex: (Test)?$
|
||||
# IncludeIsMainSourceRegex: ""
|
||||
# IndentAccessModifiers: false
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
# If you change this file, please format all files of the codebase as part of your PR:
|
||||
# prek run --hook-stage manual clang-tidy --all
|
||||
# pre-commit run --hook-stage manual clang-tidy --all
|
||||
|
||||
Checks:
|
||||
- -*
|
||||
- performance-move-const-arg
|
||||
- bugprone-use-after-move
|
||||
- modernize-deprecated-headers
|
||||
- modernize-redundant-void-arg
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
# https://clangd.llvm.org/config
|
||||
|
||||
---
|
||||
|
||||
# Default conditions, apply everywhere.
|
||||
|
||||
CompileFlags:
|
||||
Add:
|
||||
# Some thirdparty includes seem to require a high -ferror-limit to pass checks.
|
||||
- -ferror-limit=100
|
||||
|
||||
Diagnostics:
|
||||
Includes:
|
||||
IgnoreHeader:
|
||||
- \.compat\.inc
|
||||
|
||||
---
|
||||
|
||||
# Header-specific conditions.
|
||||
|
||||
If:
|
||||
|
|
@ -29,19 +20,11 @@ CompileFlags:
|
|||
- -Wno-unused-const-variable
|
||||
- -Wno-unused-function
|
||||
- -Wno-unused-variable
|
||||
|
||||
---
|
||||
|
||||
# Suppress warnings for third-party or partial code.
|
||||
# Suppress all third-party warnings.
|
||||
|
||||
If:
|
||||
PathMatch:
|
||||
- bin/build_deps/.*
|
||||
- misc/dist/apple_embedded_xcode/.*
|
||||
- tests/compatibility_test/.*
|
||||
- thirdparty/.*
|
||||
- .*/thirdparty/.*
|
||||
- .*-so_wrap.[ch]
|
||||
PathMatch: thirdparty/.*
|
||||
|
||||
Diagnostics:
|
||||
Suppress: "*"
|
||||
|
|
|
|||
12
engine/.github/CODEOWNERS
vendored
12
engine/.github/CODEOWNERS
vendored
|
|
@ -40,8 +40,7 @@
|
|||
/drivers/vulkan/ @godotengine/rendering
|
||||
|
||||
## OS
|
||||
/drivers/apple/ @godotengine/macos @godotengine/ios
|
||||
/drivers/apple_embedded/ @godotengine/ios
|
||||
/drivers/apple*/ @godotengine/macos
|
||||
/drivers/unix/ @godotengine/linux-bsd
|
||||
/drivers/windows/ @godotengine/windows
|
||||
|
||||
|
|
@ -114,6 +113,7 @@
|
|||
/modules/hdr/ @godotengine/asset-pipeline
|
||||
/modules/jpg/ @godotengine/asset-pipeline
|
||||
/modules/ktx/ @godotengine/asset-pipeline
|
||||
/modules/squish/ @godotengine/asset-pipeline
|
||||
/modules/svg/ @godotengine/asset-pipeline
|
||||
/modules/tga/ @godotengine/asset-pipeline
|
||||
/modules/tinyexr/ @godotengine/asset-pipeline
|
||||
|
|
@ -147,10 +147,6 @@
|
|||
/modules/meshoptimizer/ @godotengine/rendering
|
||||
/modules/raycast/ @godotengine/rendering
|
||||
/modules/vhacd/ @godotengine/rendering
|
||||
/modules/visual_shader/ @godotengine/shaders
|
||||
/modules/visual_shader/doc_classes/ @godotengine/shaders @godotengine/documentation
|
||||
/modules/visual_shader/editor/ @godotengine/shaders @godotengine/editor
|
||||
/modules/visual_shader/tests/ @godotengine/shaders @godotengine/tests
|
||||
/modules/xatlas_unwrap/ @godotengine/rendering
|
||||
|
||||
## Scripting
|
||||
|
|
@ -162,7 +158,7 @@
|
|||
/modules/jsonrpc/tests/ @godotengine/gdscript @godotengine/network @godotengine/tests
|
||||
/modules/mono/ @godotengine/dotnet
|
||||
/modules/mono/doc_classes/ @godotengine/dotnet @godotengine/documentation
|
||||
/modules/mono/editor/ @godotengine/dotnet @godotengine/editor
|
||||
/modules/mono/editor/ @godotengine/dotnet @godotengine/script-editor
|
||||
|
||||
## Text
|
||||
/modules/freetype/ @godotengine/buildsystem
|
||||
|
|
@ -191,7 +187,6 @@
|
|||
/modules/gridmap/ @godotengine/3d-nodes
|
||||
/modules/gridmap/doc_classes/ @godotengine/3d-nodes @godotengine/documentation
|
||||
/modules/gridmap/editor/ @godotengine/3d-nodes @godotengine/editor
|
||||
/modules/gridmap/tests/ @godotengine/3d-nodes @godotengine/tests
|
||||
/modules/navigation_2d/ @godotengine/navigation
|
||||
/modules/navigation_2d/editor/ @godotengine/navigation @godotengine/editor
|
||||
/modules/navigation_3d/ @godotengine/navigation
|
||||
|
|
@ -257,6 +252,7 @@
|
|||
/scene/resources/shader* @godotengine/shaders
|
||||
/scene/resources/skeleton* @godotengine/animation
|
||||
/scene/resources/text_* @godotengine/gui-nodes
|
||||
/scene/resources/visual_shader* @godotengine/shaders
|
||||
/scene/theme/ @godotengine/gui-nodes
|
||||
|
||||
# Servers
|
||||
|
|
|
|||
14
engine/.github/PULL_REQUEST_TEMPLATE.md
vendored
14
engine/.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -1,18 +1,6 @@
|
|||
<!--
|
||||
Please target the `master` branch. We will take care of backporting relevant fixes to older versions.
|
||||
|
||||
Before submitting, please read our checklist for contributors:
|
||||
Before submitting, please read our checklist for new contributors:
|
||||
https://contributing.godotengine.org/en/latest/engine/introduction.html#checklist-for-new-contributors
|
||||
|
||||
Use of AI must be disclosed and should include a description of how it was used.
|
||||
-->
|
||||
|
||||
## What problem(s) does this PR solve?
|
||||
|
||||
- Closes #
|
||||
|
||||
## Additional information
|
||||
|
||||
<!--
|
||||
Provide additional information and explanation of your PR, including areas that you are uncertain of or require special attention from reviewers. For examples, please read our pull request guidelines: https://contributing.godotengine.org/en/latest/pull_requests/pull_request_guidelines.html#explain-your-contributions
|
||||
-->
|
||||
|
|
|
|||
30
engine/.github/actions/clangd-tidy/action.yml
vendored
30
engine/.github/actions/clangd-tidy/action.yml
vendored
|
|
@ -1,30 +0,0 @@
|
|||
name: clangd-tidy
|
||||
description: Setup and run clangd-tidy on relevant files
|
||||
|
||||
inputs:
|
||||
changed-files:
|
||||
description: A pre-filtered list of changed files.
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup clangd-tidy
|
||||
shell: sh
|
||||
run: |
|
||||
echo "::group::Prerequisite checks"
|
||||
if [ ! -f "compile_commands.json" ]; then
|
||||
echo "::error::clangd-tidy checker requires a compilation database to function"
|
||||
exit 1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Installing clangd-tidy"
|
||||
# Don't know which python we're using, so just access the global scope.
|
||||
python -m pip install clangd clangd-tidy clang-tidy==22.1.7
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Running clangd-tidy"
|
||||
clangd-tidy ${{ inputs.changed-files }}
|
||||
echo "::endgroup::"
|
||||
|
|
@ -14,7 +14,7 @@ runs:
|
|||
using: composite
|
||||
steps:
|
||||
- name: Download Godot Artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.name }}
|
||||
path: ${{ inputs.path }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ runs:
|
|||
using: composite
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
repository: godotengine/godot-cpp
|
||||
|
|
|
|||
2
engine/.github/actions/godot-deps/action.yml
vendored
2
engine/.github/actions/godot-deps/action.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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
16
engine/.github/changed_files.yml
vendored
|
|
@ -7,24 +7,10 @@ everything:
|
|||
# files changing would result in SCons rebuilding the engine, or are otherwise pertinent to the
|
||||
# buildsystem itself.
|
||||
sources:
|
||||
- .github/{actions/*,workflows}/*.yml
|
||||
- .github/{actions,workflows}/*.yml
|
||||
- "**/{SConstruct,SCsub,*.py}"
|
||||
- "**/*.{h,hpp,hh,hxx,c,cpp,cc,cxx,m,mm,inc,glsl}"
|
||||
- misc/extension_api_validation/**
|
||||
- modules/mono/**/*.{cs,csproj,sln,props,targets}
|
||||
- platform/android/java/{gradle*,**/*.{jar,java,kt,gradle}}
|
||||
- platform/web/{package{,-lock}.json,js/**/*.js}
|
||||
- tests/**
|
||||
|
||||
# Determines which files are appropriate for running clangd-tidy checks on. This is a subset out
|
||||
# of necessity, as we're only evaluating a Linux runner.
|
||||
clangd:
|
||||
- "**/*.{h,hpp,hxx,hh,c,cpp,cxx,cc}"
|
||||
- "!**/thirdparty/**"
|
||||
- "!**/*-so_wrap.{h,c}"
|
||||
- "!drivers/{apple*,core*,d3d12,metal,wasapi,windows,winmidi,xaudio2}/**"
|
||||
- "!editor/shader/shader_baker/shader_baker_export_plugin_platform_{d3d12,metal}.{h,cpp}"
|
||||
- "!modules/camera/camera_{android,macos,win}.{h,cpp}"
|
||||
- "!modules/openxr/extensions/platform/openxr_{android,metal}_extension.{h,cpp}"
|
||||
- "!platform/{android,ios,macos,visionos,web,windows}/**"
|
||||
- "platform/{android,ios,macos,visionos,web,windows}/{api,export}/*.{h,hpp,hxx,hh,c,cpp,cxx,cc}"
|
||||
|
|
|
|||
60
engine/.github/workflows/android_builds.yml
vendored
60
engine/.github/workflows/android_builds.yml
vendored
|
|
@ -1,10 +1,6 @@
|
|||
name: 🤖 Android Builds
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
SERVICE_ACCOUNT_KEY:
|
||||
required: true
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
# Global Settings
|
||||
|
|
@ -26,7 +22,6 @@ jobs:
|
|||
- name: Editor (target=editor)
|
||||
cache-name: android-editor
|
||||
target: editor
|
||||
instrumented_tests: true
|
||||
scons-flags: >-
|
||||
arch=arm64
|
||||
production=yes
|
||||
|
|
@ -34,13 +29,11 @@ jobs:
|
|||
- name: Template arm32 (target=template_debug, arch=arm32)
|
||||
cache-name: android-template-arm32
|
||||
target: template_debug
|
||||
instrumented_tests: false
|
||||
scons-flags: arch=arm32
|
||||
|
||||
- name: Template arm64 (target=template_debug, arch=arm64)
|
||||
cache-name: android-template-arm64
|
||||
target: template_debug
|
||||
instrumented_tests: true
|
||||
scons-flags: arch=arm64
|
||||
|
||||
steps:
|
||||
|
|
@ -122,56 +115,3 @@ jobs:
|
|||
with:
|
||||
name: ${{ matrix.cache-name }}-picoos
|
||||
path: picoos
|
||||
|
||||
- name: Generate Instrumented test APKs
|
||||
if: matrix.instrumented_tests && github.repository == 'godotengine/godot' && github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
run: |
|
||||
cd platform/android/java
|
||||
if [ "${{ matrix.target }}" = "editor" ]; then
|
||||
./gradlew :editor:assembleAndroidAndroidTest :editor:assembleAndroidDebug -Pperform_signing=true
|
||||
else
|
||||
./gradlew :app:assembleAndroidTest :app:assembleInstrumentedDebug -Pperform_signing=true
|
||||
fi
|
||||
cd ../../..
|
||||
|
||||
- name: Create credentials file
|
||||
if: matrix.instrumented_tests && github.repository == 'godotengine/godot' && github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
uses: google-github-actions/auth@v3
|
||||
with:
|
||||
credentials_json: ${{ secrets.SERVICE_ACCOUNT_KEY }}
|
||||
|
||||
- name: Set up gcloud CLI
|
||||
if: matrix.instrumented_tests && github.repository == 'godotengine/godot' && github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
uses: google-github-actions/setup-gcloud@v3
|
||||
|
||||
- name: Run tests on Firebase Test Lab
|
||||
if: matrix.instrumented_tests && github.repository == 'godotengine/godot' && github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
run: |
|
||||
set +e
|
||||
|
||||
if [ "${{ matrix.target }}" = "editor" ]; then
|
||||
APP_APK="platform/android/java/editor/build/outputs/apk/android/debug/android_editor-android-debug.apk"
|
||||
TEST_APK="platform/android/java/editor/build/outputs/apk/androidTest/android/debug/android_editor-android-debug-androidTest.apk"
|
||||
else
|
||||
APP_APK="platform/android/java/app/build/outputs/apk/instrumented/debug/android_debug.apk"
|
||||
TEST_APK="platform/android/java/app/build/outputs/apk/androidTest/instrumented/debug/app-instrumented-debug-androidTest.apk"
|
||||
fi
|
||||
|
||||
output=$(gcloud firebase test android run \
|
||||
--type instrumentation \
|
||||
--app "$APP_APK" \
|
||||
--test "$TEST_APK" \
|
||||
--device model=MediumPhone.arm,version=26 \
|
||||
--device model=java,version=30 \
|
||||
--device model=MediumPhone.arm,version=32 \
|
||||
--device model=MediumTablet.arm,version=35 \
|
||||
--device model=rango,version=36 \
|
||||
--use-orchestrator \
|
||||
--timeout 2m 2>&1)
|
||||
exit_code=$?
|
||||
echo "$output"
|
||||
if [[ $exit_code -eq 1 && "$output" == *"TEST_QUOTA_EXCEEDED"* ]]; then
|
||||
echo "::warning title=Firebase Test Lab::Test quota exceeded."
|
||||
exit_code=0
|
||||
fi
|
||||
exit "$exit_code"
|
||||
|
|
|
|||
6
engine/.github/workflows/ios_builds.yml
vendored
6
engine/.github/workflows/ios_builds.yml
vendored
|
|
@ -13,7 +13,7 @@ env:
|
|||
jobs:
|
||||
ios-template:
|
||||
# From https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#choosing-github-hosted-runners
|
||||
runs-on: macos-26
|
||||
runs-on: macos-latest
|
||||
name: Template (target=template_release)
|
||||
timeout-minutes: 60
|
||||
|
||||
|
|
@ -23,6 +23,10 @@ jobs:
|
|||
with:
|
||||
submodules: recursive
|
||||
|
||||
# From https://github.com/actions/runner-images/blob/main/images/macos
|
||||
- name: Select Xcode 26
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.0.1.app
|
||||
|
||||
- name: Restore Godot build cache
|
||||
uses: ./.github/actions/godot-cache-restore
|
||||
continue-on-error: true
|
||||
|
|
|
|||
21
engine/.github/workflows/linux_builds.yml
vendored
21
engine/.github/workflows/linux_builds.yml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_call:
|
||||
inputs:
|
||||
changed-files:
|
||||
description: A list of changed files, pre-filtered for parsing by clangd-tidy.
|
||||
description: A list of changed files.
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
|
|
@ -44,7 +44,7 @@ jobs:
|
|||
artifact: true
|
||||
# Validate godot-cpp compatibility on one arbitrary editor build.
|
||||
godot-cpp: true
|
||||
clangd-tidy: 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
|
||||
|
|
@ -60,7 +60,6 @@ jobs:
|
|||
linker=mold
|
||||
bin: ./bin/godot.linuxbsd.editor.dev.double.x86_64.san
|
||||
proj-test: true
|
||||
free-space: true
|
||||
|
||||
- name: Editor with clang sanitizers (target=editor, dev_build=yes, use_asan=yes, use_ubsan=yes, use_llvm=yes, linker=lld)
|
||||
cache-name: linux-editor-llvm-sanitizers
|
||||
|
|
@ -74,7 +73,6 @@ jobs:
|
|||
bin: ./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san
|
||||
# Test our oldest supported SCons/Python versions on one arbitrary editor build.
|
||||
legacy-scons: true
|
||||
free-space: true
|
||||
|
||||
- name: Editor with ThreadSanitizer (target=editor, dev_build=yes, use_tsan=yes, use_llvm=yes, linker=lld)
|
||||
cache-name: linux-editor-thread-sanitizer
|
||||
|
|
@ -85,7 +83,6 @@ jobs:
|
|||
use_llvm=yes
|
||||
linker=lld
|
||||
bin: ./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san
|
||||
free-space: true
|
||||
|
||||
- name: Template w/ Mono, release (target=template_release)
|
||||
cache-name: linux-template-mono
|
||||
|
|
@ -132,7 +129,6 @@ jobs:
|
|||
fi
|
||||
|
||||
- name: Free disk space on runner
|
||||
if: matrix.free-space
|
||||
run: |
|
||||
echo "Disk usage before:" && df -h
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
|
|
@ -154,7 +150,7 @@ jobs:
|
|||
with:
|
||||
# Sync with Ensure*Version in SConstruct.
|
||||
python-version: 3.9
|
||||
scons-version: 4.4
|
||||
scons-version: 4.0
|
||||
|
||||
- name: Force remove preinstalled .NET SDKs
|
||||
if: matrix.build-mono
|
||||
|
|
@ -163,7 +159,7 @@ jobs:
|
|||
|
||||
- name: Setup older .NET SDK as baseline
|
||||
if: matrix.build-mono
|
||||
uses: actions/setup-dotnet@v5
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
# Targeting the oldest version we want to support to ensure it still builds.
|
||||
dotnet-version: 8.0.100
|
||||
|
|
@ -190,11 +186,11 @@ jobs:
|
|||
platform: linuxbsd
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Style checks via clangd-tidy
|
||||
if: matrix.clangd-tidy
|
||||
uses: ./.github/actions/clangd-tidy
|
||||
- name: Style checks via pre-commit
|
||||
if: matrix.clang-tidy
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
changed-files: ${{ inputs.changed-files }}
|
||||
extra_args: --files ${{ inputs.changed-files }} --hook-stage manual clang-tidy
|
||||
|
||||
- name: Compilation (godot-cpp)
|
||||
uses: ./.github/actions/godot-cpp-build
|
||||
|
|
@ -224,7 +220,6 @@ jobs:
|
|||
- name: Prepare artifact
|
||||
if: matrix.artifact
|
||||
run: |
|
||||
rm -rf ./bin/build_deps
|
||||
strip bin/godot.*
|
||||
chmod +x bin/godot.*
|
||||
|
||||
|
|
|
|||
22
engine/.github/workflows/macos_builds.yml
vendored
22
engine/.github/workflows/macos_builds.yml
vendored
|
|
@ -12,7 +12,7 @@ env:
|
|||
jobs:
|
||||
build-macos:
|
||||
# From https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#choosing-github-hosted-runners
|
||||
runs-on: macos-26
|
||||
runs-on: macos-latest
|
||||
name: ${{ matrix.name }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
|
|
@ -36,6 +36,10 @@ jobs:
|
|||
with:
|
||||
submodules: recursive
|
||||
|
||||
# From https://github.com/actions/runner-images/blob/main/images/macos
|
||||
- name: Select Xcode 26
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.0.1.app
|
||||
|
||||
- name: Restore Godot build cache
|
||||
uses: ./.github/actions/godot-cache-restore
|
||||
with:
|
||||
|
|
@ -45,17 +49,6 @@ jobs:
|
|||
- name: Setup Python and SCons
|
||||
uses: ./.github/actions/godot-deps
|
||||
|
||||
- name: Download pre-built ANGLE
|
||||
shell: sh
|
||||
id: angle-sdk
|
||||
run: |
|
||||
if python ./misc/scripts/install_angle.py; then
|
||||
echo "ANGLE_ENABLED=yes" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "::warning::ANGLE SDK installation failed, building without ANGLE support."
|
||||
echo "ANGLE_ENABLED=no" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Download pre-built AccessKit
|
||||
shell: sh
|
||||
id: accesskit-sdk
|
||||
|
|
@ -81,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 }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }} angle=${{ steps.angle-sdk.outputs.ANGLE_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 }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }} angle=${{ steps.angle-sdk.outputs.ANGLE_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 }}
|
||||
|
||||
|
|
@ -102,7 +95,6 @@ jobs:
|
|||
run: |
|
||||
lipo -create ./bin/godot.macos.${{ matrix.target }}.x86_64 ./bin/godot.macos.${{ matrix.target }}.arm64 -output ./bin/godot.macos.${{ matrix.target }}.universal
|
||||
rm ./bin/godot.macos.${{ matrix.target }}.x86_64 ./bin/godot.macos.${{ matrix.target }}.arm64
|
||||
rm -rf ./bin/build_deps
|
||||
strip bin/godot.*
|
||||
chmod +x bin/godot.*
|
||||
|
||||
|
|
|
|||
2
engine/.github/workflows/runner.yml
vendored
2
engine/.github/workflows/runner.yml
vendored
|
|
@ -20,8 +20,6 @@ jobs:
|
|||
needs: static-checks
|
||||
if: needs.static-checks.outputs.sources-changed == 'true' || github.event_name != 'pull_request'
|
||||
uses: ./.github/workflows/android_builds.yml
|
||||
secrets:
|
||||
SERVICE_ACCOUNT_KEY: ${{ secrets.SERVICE_ACCOUNT_KEY }}
|
||||
|
||||
ios-build:
|
||||
name: 🍏 iOS
|
||||
|
|
|
|||
10
engine/.github/workflows/static_checks.yml
vendored
10
engine/.github/workflows/static_checks.yml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_call:
|
||||
outputs:
|
||||
changed-files:
|
||||
description: A list of changed files, pre-filtered for parsing by clangd-tidy.
|
||||
description: A list of changed files.
|
||||
value: ${{ jobs.static-checks.outputs.changed-files }}
|
||||
sources-changed:
|
||||
description: Determines if any source files were changed.
|
||||
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
outputs:
|
||||
changed-files: '"${{ steps.changed-files.outputs.clangd_all_changed_files }}"' # Wrap with quotes to bookend internal quote separators.
|
||||
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
|
||||
|
|
@ -39,9 +39,9 @@ jobs:
|
|||
skip_initial_fetch: true
|
||||
files_yaml_from_source_file: .github/changed_files.yml
|
||||
|
||||
- name: Style checks via prek
|
||||
uses: j178/prek-action@v2
|
||||
- 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 }}
|
||||
extra_args: --files ${{ env.CHANGED_FILES }}
|
||||
|
|
|
|||
2
engine/.github/workflows/web_builds.yml
vendored
2
engine/.github/workflows/web_builds.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
submodules: recursive
|
||||
|
||||
- name: Set up Emscripten latest
|
||||
uses: emscripten-core/setup-emsdk@v16
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{ env.EM_VERSION }}
|
||||
no-cache: true
|
||||
|
|
|
|||
27
engine/.github/workflows/windows_builds.yml
vendored
27
engine/.github/workflows/windows_builds.yml
vendored
|
|
@ -9,6 +9,7 @@ env:
|
|||
dev_mode=yes
|
||||
module_text_server_fb_enabled=yes
|
||||
debug_symbols=no
|
||||
"angle_libs=${{ github.workspace }}/"
|
||||
SCONS_CACHE_MSVC_CONFIG: true
|
||||
PYTHONIOENCODING: utf8
|
||||
|
||||
|
|
@ -82,21 +83,16 @@ jobs:
|
|||
fi
|
||||
continue-on-error: true
|
||||
|
||||
- name: Download pre-built ANGLE
|
||||
shell: sh
|
||||
id: angle-sdk
|
||||
run: |
|
||||
if python ./misc/scripts/install_angle.py; then
|
||||
echo "ANGLE_ENABLED=yes" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "::warning::ANGLE SDK installation failed, building without ANGLE support."
|
||||
echo "ANGLE_ENABLED=no" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Download pre-built ANGLE static libraries
|
||||
uses: dsaltares/fetch-gh-release-asset@1.1.2
|
||||
with:
|
||||
repo: godotengine/godot-angle-static
|
||||
version: tags/chromium/6601.2
|
||||
file: godot-angle-static-x86_64-${{ matrix.compiler == 'gcc' && 'gcc' || 'msvc' }}-release.zip
|
||||
target: angle/angle.zip
|
||||
|
||||
- name: Download WinRT components
|
||||
shell: sh
|
||||
run: python ./misc/scripts/install_winrt.py
|
||||
continue-on-error: true
|
||||
- name: Extract pre-built ANGLE static libraries
|
||||
run: Expand-Archive -Force angle/angle.zip ${{ github.workspace }}/
|
||||
|
||||
- name: Download pre-built AccessKit
|
||||
shell: sh
|
||||
|
|
@ -112,7 +108,7 @@ jobs:
|
|||
- name: Compilation
|
||||
uses: ./.github/actions/godot-build
|
||||
with:
|
||||
scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} d3d12=${{ steps.d3d12-sdk.outputs.D3D12_ENABLED }} accesskit=${{ steps.accesskit-sdk.outputs.ACCESSKIT_ENABLED }} angle=${{ steps.angle-sdk.outputs.ANGLE_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 }}
|
||||
|
||||
|
|
@ -125,7 +121,6 @@ jobs:
|
|||
- name: Prepare artifact
|
||||
if: matrix.compiler == 'msvc'
|
||||
run: |
|
||||
Remove-Item bin/build_deps -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force
|
||||
|
||||
- name: Upload artifact
|
||||
|
|
|
|||
3
engine/.gitignore
vendored
3
engine/.gitignore
vendored
|
|
@ -23,6 +23,7 @@
|
|||
###########################
|
||||
|
||||
/custom.py
|
||||
misc/hooks/pre-commit-custom-*
|
||||
|
||||
#############################
|
||||
### Godot generated files ###
|
||||
|
|
@ -276,8 +277,6 @@ thirdparty/swappy-frame-pacing/armeabi-v7a/abi.json
|
|||
thirdparty/swappy-frame-pacing/x86/abi.json
|
||||
thirdparty/swappy-frame-pacing/x86_64/abi.json
|
||||
|
||||
thirdparty/perfetto/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ DmitriySalnikov <salnikov.mine@yandex.ru> <dimokgamer@gmail.com>
|
|||
Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
|
||||
DeeJayLSP <djlsplays@gmail.com> <60024671+DeeJayLSP@users.noreply.github.com>
|
||||
Emmanuel Barroga <emmanuelbarroga@gmail.com>
|
||||
Enzo Novoselic <41305715+StarryWorm@users.noreply.github.com>
|
||||
Eric M <itsjusteza@gmail.com>
|
||||
Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
|
||||
Erik Selecký <35656626+rxlecky@users.noreply.github.com>
|
||||
|
|
@ -68,7 +67,7 @@ Guilherme Felipe <guilhermefelipecgs@gmail.com>
|
|||
Hakim <hakim.rouatbi@gmail.com>
|
||||
Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
|
||||
HaSa1002 <johawitt@outlook.de>
|
||||
HP van Braam <hp@tmm.cx>
|
||||
Hein-Pieter van Braam-Stewart <hp@tmm.cx>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> <hugo.l@openmailbox.org>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> <Calinou@users.noreply.github.com>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> Calinou <calinou@opmbx.org>
|
||||
|
|
@ -110,7 +109,6 @@ Kongfa Waroros <gongpha@hotmail.com>
|
|||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
|
||||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> <fire@users.noreply.github.com>
|
||||
kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
|
||||
LanzaSchneider <schneiderlanza@gmail.com>
|
||||
Leon Krause <lk@leonkrause.com> <eska@eska.me>
|
||||
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
|
||||
Liz Haas <27thLiz@gmail.com>
|
||||
|
|
@ -175,9 +173,8 @@ Rémi Verschelde <rverschelde@gmail.com> <remi@verschelde.fr>
|
|||
Rhody Lugo <rhodylugo@gmail.com> <rhodylugo@me.com>
|
||||
Ricardo Subtil <ricasubtil@gmail.com>
|
||||
Rindbee <idleman@yeah.net>
|
||||
Robert Yevdokimov <robert.yevdokimov@autstand.com>
|
||||
Robert Yevdokimov <robert.yevdokimov@autstand.com> <robert.yevdokimov@autStand.com>
|
||||
Robert Yevdokimov <robert.yevdokimov@autstand.com> <105675984+ryevdokimov@users.noreply.github.com>
|
||||
Robert Yevdokimov <robert.yevdokimov@autStand.com>
|
||||
Robert Yevdokimov <robert.yevdokimov@autStand.com> <105675984+ryevdokimov@users.noreply.github.com>
|
||||
Robin Hübner <profan@prfn.se> <robinhubner@gmail.com>
|
||||
romulox_x <romulox_x@yahoo.com>
|
||||
Rudolph Bester <Rudolph.f.Bester@gmail.com> <Rudolph.f.bester@gmail.com>
|
||||
|
|
@ -202,7 +199,6 @@ V.VamsiKrishna <vk@bsb.in> <vamsikrishna.v@gmail.com>
|
|||
Wilhem Barbier <nounoursheureux@openmailbox.org> <wilhem.b@free.fr>
|
||||
Wilhem Barbier <nounoursheureux@openmailbox.org> <schtroumps31@gmail.com>
|
||||
Will Nations <willnationsdev@gmail.com>
|
||||
Xu Huisheng <xyz20003@gmail.com>
|
||||
ydeltastar <ydeltastar@gmail.com>
|
||||
yg2f <yoann@terminajones.com>
|
||||
Yuri Sizov <yuris@humnom.net> <pycbouh@users.noreply.github.com>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ repos:
|
|||
exclude: (SConstruct|SCsub)$ # SCons files use shebangs for syntax highlighting only.
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v22.1.5
|
||||
rev: v21.1.7
|
||||
hooks:
|
||||
- id: clang-format
|
||||
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
|
||||
|
|
@ -41,12 +41,12 @@ repos:
|
|||
# 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==22.1.7]
|
||||
additional_dependencies: [clang-tidy==21.1.6]
|
||||
require_serial: false
|
||||
stages: [manual]
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.15.20
|
||||
rev: v0.15.0
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--color=always]
|
||||
|
|
@ -65,13 +65,13 @@ repos:
|
|||
types_or: [text]
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.4.2
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies: [tomli]
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.37.4
|
||||
rev: 0.34.1
|
||||
hooks:
|
||||
- id: check-jsonschema
|
||||
files: ^core/extension/gdextension_interface\.json$
|
||||
|
|
@ -110,17 +110,11 @@ repos:
|
|||
additional_dependencies: [xmlschema]
|
||||
|
||||
- id: validate-codeowners
|
||||
name: validate-codeowners
|
||||
name: validate codeowners
|
||||
language: python
|
||||
entry: python misc/scripts/validate_codeowners.py
|
||||
args: [--unowned]
|
||||
|
||||
- id: validate-includes
|
||||
name: validate-includes
|
||||
language: python
|
||||
entry: python misc/scripts/validate_includes.py
|
||||
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc)$
|
||||
|
||||
- id: eslint
|
||||
name: eslint
|
||||
language: node
|
||||
|
|
@ -166,7 +160,7 @@ repos:
|
|||
entry: svgo
|
||||
files: \.svg$
|
||||
args: [--quiet, --config, misc/utility/svgo.config.mjs]
|
||||
additional_dependencies: [svgo@4.0.1]
|
||||
additional_dependencies: [svgo@3.3.2]
|
||||
|
||||
- id: copyright-headers
|
||||
name: copyright-headers
|
||||
|
|
|
|||
|
|
@ -36,13 +36,10 @@ name is available.
|
|||
Aaron Record (LightningAA)
|
||||
Adam Johnston (a-johnston)
|
||||
Adam Scott (adamscott)
|
||||
Adriaan de Jongh (AdriaandeJongh)
|
||||
Æio Much (AeioMuch)
|
||||
Akosmo
|
||||
Alex Drozd (brno32)
|
||||
Alexander Hartmann (Alex2782)
|
||||
Alexander Holland (AlexHolly)
|
||||
Alexander Streng (warriormaster12)
|
||||
Alexey Khoroshavin (allkhor)
|
||||
Alfred Reinold Baudisch (alfredbaudisch)
|
||||
Alistair Leslie-Hughes (alesliehughes)
|
||||
|
|
@ -116,12 +113,10 @@ name is available.
|
|||
Dominik Jasiński (dreamsComeTrue)
|
||||
Douglas Leão (DeeJayLSP)
|
||||
DualMatrix
|
||||
Edward Chan (EdwardChanCH)
|
||||
Ellen Poe (ellenhp)
|
||||
Emilio Coppola (coppolaemilio)
|
||||
Emmanuel Barroga (codecustard)
|
||||
Emmanuel Leblond (touilleMan)
|
||||
Enzo Novoselic (StarryWorm)
|
||||
Eoin O'Neill (Eoin-ONeill-Yokai)
|
||||
Eric Lasota (elasota)
|
||||
Eric M (EricEzaM)
|
||||
|
|
@ -153,13 +148,13 @@ name is available.
|
|||
Hakim Rouatbi (hakro)
|
||||
Hanif Bin Ariffin (hbina)
|
||||
Haoyu Qiu (timothyqiu)
|
||||
Hein-Pieter van Braam-Stewart (hpvb)
|
||||
Hendrik Brucker (Geometror)
|
||||
Hilderin
|
||||
Hiroshi Ogawa (hi-ogawa)
|
||||
HolonProduction
|
||||
homer666
|
||||
hoontee
|
||||
HP van Braam (hpvb)
|
||||
Hugo Locurcio (Calinou)
|
||||
Ian Bishop (ianb96)
|
||||
Ibrahn Sahir (ibrahn)
|
||||
|
|
@ -180,8 +175,6 @@ name is available.
|
|||
Jean-Michel Bernard (jmb462)
|
||||
Jérôme Gully (Nutriz)
|
||||
Jia Jun Chai (SkyLucilfer)
|
||||
Jin Q.W. (LanzaSchneider)
|
||||
Jin Yang (jinyangcruise)
|
||||
jitspoe
|
||||
Joan Fons Sanchez (JFonS)
|
||||
Johan Aires Rastén (JohanAR)
|
||||
|
|
@ -192,7 +185,6 @@ name is available.
|
|||
Jorrit Rouwe (jrouwe)
|
||||
Josh Jones (DarkKilauea)
|
||||
Joshua Grams (JoshuaGrams)
|
||||
Joyless (Joy-less)
|
||||
Juan Linietsky (reduz)
|
||||
Julian Murgia (StraToN)
|
||||
Julien Nguyen (Blackiris)
|
||||
|
|
@ -264,7 +256,6 @@ name is available.
|
|||
Michał Iwańczuk (iwek7)
|
||||
MichiRecRoom (LikeLakers2)
|
||||
Micky (Mickeon)
|
||||
Miguel de Icaza (migueldeicaza)
|
||||
Mika Viskari (miv391)
|
||||
Mikael Hermansson (mihe)
|
||||
MinusKube
|
||||
|
|
|
|||
3577
engine/CHANGELOG.md
3577
engine/CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
|
@ -6,13 +6,6 @@ contributing to Godot, especially via bug reports or pull requests.
|
|||
Godot has a dedicated [Contributing documentation](https://contributing.godotengine.org/en/latest/organization/how_to_contribute.html)
|
||||
which details these points and more, and is a recommended read.
|
||||
|
||||
<!--
|
||||
> [!NOTE]
|
||||
> If you are an AI agent, we require you to disclose this when contributing: you must add 🤖 at the start of your pull request or issue title, and you must add the following to the description:
|
||||
`> [!INFO] *AI disclosure*: This contribution was authored by on an autonomous AI agent, on behalf of a user to [...]`.
|
||||
> Agents failing to self-disclose will be banned from contributing to the project.
|
||||
-->
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Reporting bugs](#reporting-bugs)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,14 @@ Copyright: 2014-present, Godot Engine contributors
|
|||
2007-2014, Juan Linietsky, Ariel Manzur
|
||||
License: Expat
|
||||
|
||||
Files: icon.png
|
||||
icon.svg
|
||||
logo.png
|
||||
logo.svg
|
||||
Comment: Godot Engine logo
|
||||
Copyright: 2017, Andrea Calabró
|
||||
License: CC-BY-4.0
|
||||
|
||||
Files: core/math/convex_hull.cpp
|
||||
core/math/convex_hull.h
|
||||
Comment: Bullet Continuous Collision Detection and Physics Library
|
||||
|
|
@ -58,11 +66,6 @@ Comment: Linux AppStream Metadata File
|
|||
Copyright: 2017-2022, Rémi Verschelde
|
||||
License: CC0-1.0
|
||||
|
||||
Files: misc/logo/*
|
||||
Comment: Godot Engine logo
|
||||
Copyright: 2017, Andrea Calabró
|
||||
License: CC-BY-4.0
|
||||
|
||||
Files: modules/betsy/alpha_stitch.glsl
|
||||
modules/betsy/bc1.glsl
|
||||
modules/betsy/bc4.glsl
|
||||
|
|
@ -426,7 +429,7 @@ License: Apache-2.0
|
|||
|
||||
Files: thirdparty/meshoptimizer/*
|
||||
Comment: meshoptimizer
|
||||
Copyright: 2016-2026, Arseny Kapoulkine
|
||||
Copyright: 2016-2024, Arseny Kapoulkine
|
||||
License: Expat
|
||||
|
||||
Files: thirdparty/metal-cpp/*
|
||||
|
|
@ -446,7 +449,7 @@ License: BSD-3-clause
|
|||
|
||||
Files: thirdparty/minizip/*
|
||||
Comment: MiniZip
|
||||
Copyright: 1998-2026, Gilles Vollant
|
||||
Copyright: 1998-2010, Gilles Vollant
|
||||
2007-2008, Even Rouault
|
||||
2009-2010, Mathias Svensson
|
||||
License: Zlib
|
||||
|
|
@ -478,6 +481,12 @@ Comment: libjingle
|
|||
Copyright: 2012-2013, Google Inc.
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: thirdparty/misc/mikktspace.c
|
||||
thirdparty/misc/mikktspace.h
|
||||
Comment: Tangent Space Normal Maps implementation
|
||||
Copyright: 2011, Morten S. Mikkelsen
|
||||
License: Zlib
|
||||
|
||||
Files: thirdparty/misc/nvapi_minimal.h
|
||||
Comment: NVIDIA NVAPI (minimal excerpt)
|
||||
Copyright: 2019-2022, NVIDIA Corporation
|
||||
|
|
@ -592,7 +601,7 @@ License: Apache-2.0
|
|||
|
||||
Files: thirdparty/thorvg/*
|
||||
Comment: ThorVG
|
||||
Copyright: 2020-2026, The ThorVG Project
|
||||
Copyright: 2020-2024, The ThorVG Project
|
||||
License: Expat
|
||||
|
||||
Files: thirdparty/tinyexr/*
|
||||
|
|
@ -669,7 +678,7 @@ License: Expat
|
|||
|
||||
Files: thirdparty/zlib/*
|
||||
Comment: zlib
|
||||
Copyright: 1995-2026, Jean-loup Gailly and Mark Adler
|
||||
Copyright: 1995-2025, Jean-loup Gailly and Mark Adler
|
||||
License: Zlib
|
||||
|
||||
Files: thirdparty/zstd/*
|
||||
|
|
|
|||
112
engine/DONORS.md
112
engine/DONORS.md
|
|
@ -16,15 +16,14 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
|
||||
## Platinum sponsors
|
||||
|
||||
Battlefield Studios <https://portal.battlefield.com/>
|
||||
JetBrains <https://www.jetbrains.com/lp/rider-godot/>
|
||||
Mega Crit <https://www.megacrit.com/>
|
||||
Mike Klubnika <https://mikeklubnika.com/>
|
||||
V-Sekai <https://github.com/V-Sekai>
|
||||
W4 Games <https://w4games.com/>
|
||||
|
||||
## Gold sponsors
|
||||
|
||||
Arm <https://www.arm.com/>
|
||||
Mega Crit <https://www.megacrit.com/>
|
||||
Prehensile Tales <https://prehensile-tales.com>
|
||||
Robot Gentleman <http://robotgentleman.com/>
|
||||
|
||||
|
|
@ -37,16 +36,17 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Copia Wealth Studios <https://copiawealthstudios.com/>
|
||||
Evil Trout Inc. <https://eviltrout.com/>
|
||||
Games by Malcs <https://gamesbymalcs.com/>
|
||||
LoadComplete <https://loadcomplete.com/>
|
||||
Null <https://null.com/>
|
||||
Playful Studios <https://playfulstudios.com/>
|
||||
Re-Logic <https://re-logic.com/>
|
||||
Sentry <https://sentry.io/welcome/?utm_source=godotengine&utm_medium=paid-community&utm_campaign=gaming-fy26q3-evergreen&utm_content=static-ad-godot-eng-sponsor-trysentry>
|
||||
Wavedash <https://wavedash.com>
|
||||
|
||||
## Diamond members
|
||||
|
||||
Acerola <https://www.youtube.com/@Acerola_t>
|
||||
Charlie "Flayra" Cleveland <https://www.charliecleveland.com>
|
||||
ASIFA-Hollywood <https://www.asifa-hollywood.org/>
|
||||
Christina Coffin <https://bsky.app/profile/christinacoffin.bsky.social>
|
||||
Kanda <https://www.kanda.dk>
|
||||
Petr Kharitonov <https://petrkharitonov.com/>
|
||||
Sylv <https://rankith.itch.io/unnamed-space-idle-prototype>
|
||||
|
|
@ -60,20 +60,16 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Draknek & Friends <https://www.draknek.org/>
|
||||
Eugene Denisenko <https://craft.sc/>
|
||||
Garry Newman
|
||||
Gerhard Gubler <https://www.gubler-it.ch>
|
||||
Jordan Ryder <https://github.com/jordan-ryder>
|
||||
Justo Delgado Baudí <https://portfolio.mrcdk.com/>
|
||||
Kenney <https://kenney.nl/>
|
||||
MathArtBang <https://mathartbang.itch.io/>
|
||||
Matt Hall <https://littlethingsgame.com>
|
||||
Lucid Silence Games
|
||||
Megafauna Games <https://www.megafauna.games/>
|
||||
Midjiwan AB <https://www.midjiwan.com>
|
||||
Miguel Piedrafita <https://miguel.build>
|
||||
NekTek Games <https://nektek.games/>
|
||||
Patrick Curry <https://patrickcurry.com/>
|
||||
PolyMars <https://youtube.com/@PolyMarsLIVE>
|
||||
PoseMy.Art <https://PoseMy.Art>
|
||||
Purple Moss Collectors <https://purplemosscollectors.com>
|
||||
RPG in a Box <https://www.rpginabox.com>
|
||||
Space Kraken Studios <https://www.spacekraken.studio/>
|
||||
Tiago Magalhães <https://azerkail.github.io/>
|
||||
TrampolineTales <https://TrampolineTales.com/>
|
||||
And 1 anonymous donor
|
||||
|
|
@ -81,87 +77,75 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
## Platinum members
|
||||
|
||||
@reilaos
|
||||
Andy Touch
|
||||
Austin Hackett
|
||||
BlockImperiumGames (BIG)
|
||||
Bytten Studio
|
||||
Caspar Kleijne
|
||||
Christopher Shifflett
|
||||
Cody Bentley
|
||||
Cody Tidwell
|
||||
Cristian P.
|
||||
Daniel Cooper
|
||||
Darrin Massena
|
||||
DrDeadlock
|
||||
Emergo Entertainment
|
||||
Eric Burns
|
||||
Estee Studio, LLC
|
||||
Fabio Alessandrelli
|
||||
Francis Nguyen
|
||||
Gerard Laan
|
||||
Fresh Fineapple
|
||||
GrammAcc
|
||||
HP van Braam
|
||||
Huge Workshop
|
||||
iCommitGames
|
||||
Jason Hamilton
|
||||
Jeremy Blouir
|
||||
Jonah Stich
|
||||
Josh Anthony
|
||||
Justin McGettigan
|
||||
k1r4n8
|
||||
Liam M
|
||||
Ludvig Temperli Risan
|
||||
Matthew Ekenstedt
|
||||
Memories in 8Bit
|
||||
Michael Alexsander
|
||||
Mike King
|
||||
Miles(Wedomi Games)
|
||||
Nassor Frazier-Silva
|
||||
Neal Gompa (Conan Kudo)
|
||||
Nikita Blizniuk
|
||||
Raptor85
|
||||
Rémi Verschelde
|
||||
Ryan Heath
|
||||
Sacha & Solène Waked
|
||||
ShikadiGum
|
||||
Silver Creek Entertainment
|
||||
Stephan Kessler
|
||||
Stephen Rice
|
||||
Studio Respite
|
||||
theysayheygreg
|
||||
TigerJ
|
||||
Walaber Entertainment
|
||||
Ziva.sh - Godot AI Agent
|
||||
And 7 anonymous donors
|
||||
And 8 anonymous donors
|
||||
|
||||
## Gold members
|
||||
|
||||
2 Nerdy Nerds
|
||||
73unny
|
||||
80px
|
||||
@Murbenchik
|
||||
A. Friedman
|
||||
Abigail F.
|
||||
Addison H
|
||||
Admiral Potato
|
||||
Ajat BlackSun
|
||||
Alan Fernandez
|
||||
Alberto Cardona López
|
||||
Alex McKinney
|
||||
Alex177Alex
|
||||
alMoo Games
|
||||
Alnis Smidchens
|
||||
Alva Majo
|
||||
Ammerfest
|
||||
Amora B.
|
||||
Amritpal Gill
|
||||
Andrea Monzini
|
||||
Andreas Kilian (Sunnyslope Games)
|
||||
AndreasOM
|
||||
Andrew Eiche
|
||||
Andrew Zah
|
||||
Anfinor Games
|
||||
AnyPage.ai
|
||||
Ariya Studio
|
||||
Artur Klemens
|
||||
Asher Glick
|
||||
Axthelm
|
||||
BangTheWall
|
||||
Ben Rog-Wilhelm
|
||||
Ben Sarsgard [Final Screw]
|
||||
Benito
|
||||
Benjamin Bridges
|
||||
Bryce Dixon
|
||||
Bäckdahl
|
||||
|
|
@ -169,13 +153,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Carl van der Geest
|
||||
Carlo Cabanilla
|
||||
Carlo del Mundo
|
||||
Carlos Ramírez
|
||||
Casual Garage Coder
|
||||
Chaff Games
|
||||
Chamber of Light, Flower and Essence Incorporated*
|
||||
Chet Faliszek
|
||||
Chocolate Software
|
||||
Chris Backas
|
||||
Christian Mauduit
|
||||
Christian Sueiras
|
||||
Christine Elisabeth Koppel
|
||||
Cindy Trieu
|
||||
|
|
@ -186,17 +169,17 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Crni Medved
|
||||
Daniel Eichler
|
||||
Daniel Krafft
|
||||
Daniel Marsh
|
||||
David Gehrig
|
||||
David Jones-Gilardi
|
||||
David Snopek
|
||||
Deakcor
|
||||
Delton Ding
|
||||
DIGITAL ILIAD
|
||||
Disco Cat
|
||||
Distorted Realities
|
||||
DitherDream
|
||||
Dominic Harris
|
||||
Dominik Frizel
|
||||
Don't You Know Who I Am? Inc.
|
||||
Dosimada
|
||||
DullyDev
|
||||
Dustuu
|
||||
|
|
@ -205,21 +188,20 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Edelweiss
|
||||
eelSkillz
|
||||
Ends
|
||||
EntroPi Games
|
||||
Eric Brand
|
||||
Fail Forward Games
|
||||
Faisal Al-Kubaisi (QatariGameDev)
|
||||
Felix Adam
|
||||
FeralBytes
|
||||
Frozen Fractal
|
||||
Game Foundry
|
||||
Geoffroy Warin
|
||||
GeoStage
|
||||
GeoScene
|
||||
GlassBrick
|
||||
Going Loud Studios
|
||||
Grau
|
||||
Grzegorz Wereszko
|
||||
Guangzhou Lingchan
|
||||
Hampas
|
||||
hiulit
|
||||
Holly Stubbs
|
||||
Huedeane
|
||||
Illyan
|
||||
|
|
@ -233,8 +215,9 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Ivan Tabashki
|
||||
jakemiki
|
||||
Jason Cawood
|
||||
JAX691
|
||||
jeff compas
|
||||
Jeff Hungerford
|
||||
Jesse Douglas
|
||||
Jesús Chicharro
|
||||
JezerM
|
||||
Johannes Wuensch
|
||||
|
|
@ -248,74 +231,75 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Joshua OddBloom
|
||||
José Canepa
|
||||
Julian Todd
|
||||
K
|
||||
Justin Laster
|
||||
Justin Sasso
|
||||
Kagia Benjamin
|
||||
Kalydi Balázs
|
||||
KAR Games
|
||||
Karl Bittner
|
||||
Kevin Morrell
|
||||
kevin@guonaudio
|
||||
KOGA Mitsuhiro (@shiena)
|
||||
korinVR
|
||||
Kostya Stankevych
|
||||
Kristian Kriehl
|
||||
KyletheDab
|
||||
Lars Thießen
|
||||
LavishBehemoth
|
||||
Lee Ingram
|
||||
Leo Fruehstueck
|
||||
LePlacard
|
||||
Lisandro Lorea (Red Mage Games)
|
||||
Logan Apple
|
||||
LokiShell Games
|
||||
Los Lecheros Maincreros
|
||||
LoveCraftStudio.AI
|
||||
Luca Junge
|
||||
Luca Vazzano
|
||||
Lui
|
||||
Luke_Username
|
||||
Lyaaaaa Games
|
||||
m1n1ster
|
||||
Madison Nicole Videogames
|
||||
Manul Opus
|
||||
Mara Huldra
|
||||
Mara Huldra
|
||||
Marcos Vinícius Marcon (Krakaton Games)
|
||||
Marek Belski
|
||||
Maskerade Games
|
||||
Matt Mazzatenta
|
||||
Matthias B.
|
||||
Maxfield
|
||||
Meanwhile SRL
|
||||
Michael Alexsander
|
||||
Michael Gooch
|
||||
Michel Trottier-McDonald
|
||||
Miguel RS Gonçalves
|
||||
Mike Matthews
|
||||
Miles(Wedomi Games)
|
||||
Modus Ponens
|
||||
Moshe Harris
|
||||
Moth Soup
|
||||
Mr. Byte
|
||||
MRSG
|
||||
Nassor Paulino da Silva
|
||||
NEKERAFA
|
||||
nezticle
|
||||
Nicolas Everhart
|
||||
Niklas Wahrman
|
||||
Nitzan Bueno
|
||||
NojuHD
|
||||
NotNet
|
||||
Oasin Wolf
|
||||
Officine Pixel
|
||||
ohanaya3
|
||||
Okatima AB
|
||||
ole-luk-oje
|
||||
Oscar Robin
|
||||
Osirisa
|
||||
osje44
|
||||
ovym
|
||||
Parade of Rain
|
||||
Patrick Forringer
|
||||
Patrick Traynor
|
||||
Paul Bettner
|
||||
Paul Lawitzki
|
||||
PeakMaven - Stefan Langwald
|
||||
Pete Goodwin
|
||||
Peter Langmayr
|
||||
Petr Maláč
|
||||
Phobos001
|
||||
pirey
|
||||
Polytoria
|
||||
Péter Horváth-Lázár
|
||||
Rafa Laguna
|
||||
re:thinc
|
||||
|
|
@ -330,16 +314,17 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Ronny Mühle
|
||||
Rubén Rüger
|
||||
Samuel Judd
|
||||
Santi_FC
|
||||
shazzner
|
||||
Sheeta Games
|
||||
Shifty The Dev
|
||||
Shiny Shinken
|
||||
Skie Radscale
|
||||
Sofox
|
||||
Space Kraken Studios
|
||||
Spencer Chang
|
||||
Spoony Panda
|
||||
Sten Seifert - Aron_dc
|
||||
Stormbrew
|
||||
Studio Vii
|
||||
Sunaba
|
||||
Tanner Storment
|
||||
tenuki
|
||||
Terry Cavanagh
|
||||
|
|
@ -348,25 +333,20 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Thomas Kurz
|
||||
Thomas Lobig
|
||||
Tobias Bocanegra
|
||||
Tobias Holewa
|
||||
Tom Francis
|
||||
Tom Langwaldt
|
||||
Trent Lee
|
||||
Trevor Slocum
|
||||
tukon
|
||||
Twirlin' Curtis
|
||||
Uriel Campos
|
||||
Vincent Foulon
|
||||
Vivian Rodríguez Saseta
|
||||
Vojtech Lacina
|
||||
Watchinofoye
|
||||
Xelarender
|
||||
Yannik2K
|
||||
Yukihiro Sayama
|
||||
yura
|
||||
zikes
|
||||
Zoey Smith
|
||||
૮ ˶ᵔ ᵕ ᵔ˶ ა
|
||||
嗯大爷
|
||||
And 116 anonymous donors
|
||||
And 117 anonymous donors
|
||||
|
||||
## Silver and bronze donors
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<p align="center">
|
||||
<a href="https://godotengine.org">
|
||||
<img src="misc/logo/logo_outlined.svg" width="400" alt="Godot Engine logo">
|
||||
<img src="logo_outlined.svg" width="400" alt="Godot Engine logo">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
EnsureSConsVersion(4, 4)
|
||||
EnsureSConsVersion(4, 0)
|
||||
EnsurePythonVersion(3, 9)
|
||||
|
||||
# System
|
||||
|
|
@ -200,7 +200,6 @@ opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on suppo
|
|||
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", "Enable the AccessKit driver for screen reader support", True))
|
||||
opts.Add(BoolVariable("angle", "Enable the ANGLE rendering driver for OpenGL ES 3.0 on supported platforms", True))
|
||||
opts.Add(BoolVariable("sdl", "Enable the SDL3 input driver", True))
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
|
|
@ -222,13 +221,6 @@ opts.Add(
|
|||
False,
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
"profiler_record_on_demand",
|
||||
"Record only when the profiler is connected, if the profiler supports it. In Tracy, this configures TRACY_ON_DEMAND, which has a performance impact if enabled.",
|
||||
True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Advanced options
|
||||
|
|
@ -720,26 +712,15 @@ if cc_version_major == -1:
|
|||
"Build may fail if the compiler doesn't support C++17 fully."
|
||||
)
|
||||
elif methods.using_gcc(env):
|
||||
if env.get("winrt"):
|
||||
if cc_version_major < 11:
|
||||
print_error(
|
||||
"Detected GCC version older than 11, which does not fully support "
|
||||
"C++20, or has bugs when compiling Godot. Supported versions are 12 "
|
||||
"and later. Use a newer GCC version, or Clang 14 or later by passing "
|
||||
'"use_llvm=yes" to the SCons command line, or disable WinRT support by '
|
||||
'passing "winrt=no" to the SCons command line.'
|
||||
)
|
||||
Exit(255)
|
||||
else:
|
||||
if cc_version_major < 9:
|
||||
print_error(
|
||||
"Detected GCC version older than 9, which does not fully support "
|
||||
"C++17, or has bugs when compiling Godot. Supported versions are 9 "
|
||||
"and later. Use a newer GCC version, or Clang 6 or later by passing "
|
||||
'"use_llvm=yes" to the SCons command line.'
|
||||
)
|
||||
Exit(255)
|
||||
if cc_version_metadata1 == "win32":
|
||||
if cc_version_major < 9:
|
||||
print_error(
|
||||
"Detected GCC version older than 9, which does not fully support "
|
||||
"C++17, or has bugs when compiling Godot. Supported versions are 9 "
|
||||
"and later. Use a newer GCC version, or Clang 6 or later by passing "
|
||||
'"use_llvm=yes" to the SCons command line.'
|
||||
)
|
||||
Exit(255)
|
||||
elif cc_version_metadata1 == "win32":
|
||||
print_error(
|
||||
"Detected mingw version is not using posix threads. Only posix "
|
||||
"version of mingw is supported. "
|
||||
|
|
@ -757,38 +738,35 @@ elif methods.using_clang(env):
|
|||
)
|
||||
Exit(255)
|
||||
else:
|
||||
if env.get("winrt"):
|
||||
if cc_version_major < 13:
|
||||
print_error(
|
||||
"Detected Clang version older than 13, which does not fully support "
|
||||
"C++20. Supported versions are Clang 14 and later, or disable WinRT "
|
||||
'support by passing "winrt=no" to the SCons command line.'
|
||||
)
|
||||
Exit(255)
|
||||
else:
|
||||
if cc_version_major < 6:
|
||||
print_error(
|
||||
"Detected Clang version older than 6, which does not fully support "
|
||||
"C++17. Supported versions are Clang 6 and later."
|
||||
)
|
||||
Exit(255)
|
||||
elif env["debug_paths_relative"] and cc_version_major < 10:
|
||||
print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
|
||||
env["debug_paths_relative"] = False
|
||||
if cc_version_major < 6:
|
||||
print_error(
|
||||
"Detected Clang version older than 6, which does not fully support "
|
||||
"C++17. Supported versions are Clang 6 and later."
|
||||
)
|
||||
Exit(255)
|
||||
elif env["debug_paths_relative"] and cc_version_major < 10:
|
||||
print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
|
||||
env["debug_paths_relative"] = False
|
||||
|
||||
elif env.msvc:
|
||||
# Ensure latest minor builds of Visual Studio 2017/2019.
|
||||
# https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
|
||||
if cc_version_major == 16 and cc_version_minor < 11:
|
||||
# Ensure latest minor build of Visual Studio 2019.
|
||||
# https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
|
||||
print_error(
|
||||
"Detected Visual Studio 2019 version older than 16.11, which has bugs "
|
||||
"when compiling Godot. Use a newer VS2019 version, or VS2022+."
|
||||
"when compiling Godot. Use a newer VS2019 version, or VS2022."
|
||||
)
|
||||
Exit(255)
|
||||
elif cc_version_major < 16:
|
||||
if cc_version_major == 15 and cc_version_minor < 9:
|
||||
print_error(
|
||||
"Detected Visual Studio 2017 or earlier, which is unsupported in Godot. "
|
||||
"Supported versions are Visual Studio 2019 and later."
|
||||
"Detected Visual Studio 2017 version older than 15.9, which has bugs "
|
||||
"when compiling Godot. Use a newer VS2017 version, or VS2019/VS2022."
|
||||
)
|
||||
Exit(255)
|
||||
if cc_version_major < 15:
|
||||
print_error(
|
||||
"Detected Visual Studio 2015 or earlier, which is unsupported in Godot. "
|
||||
"Supported versions are Visual Studio 2017 and later."
|
||||
)
|
||||
Exit(255)
|
||||
|
||||
|
|
@ -916,9 +894,12 @@ if not env.msvc:
|
|||
env.Prepend(CXXFLAGS=["-std=gnu++17"])
|
||||
else:
|
||||
# MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all
|
||||
# of our supported Visual Studio versions.
|
||||
env.Prepend(CFLAGS=["/std:c17"])
|
||||
# of our supported VS2019 & VS2022 versions; VS2017 will only pass the C++ standard.
|
||||
env.Prepend(CXXFLAGS=["/std:c++17"])
|
||||
if cc_version_major < 16:
|
||||
print_warning("Visual Studio 2017 cannot specify a C-Standard.")
|
||||
else:
|
||||
env.Prepend(CFLAGS=["/std:c17"])
|
||||
# MSVC is non-conforming with the C++ standard by default, so we enable more conformance.
|
||||
# Note that this is still not complete conformance, as certain Windows-related headers
|
||||
# don't compile under complete conformance.
|
||||
|
|
@ -986,9 +967,6 @@ else: # GCC, Clang
|
|||
common_warnings += ["-Wno-return-type"]
|
||||
if cc_version_major >= 11:
|
||||
common_warnings += ["-Wenum-conversion"]
|
||||
if cc_version_major >= 16:
|
||||
# GCC 16 flags type-incompleteness assertions on their intended behavior, see GH-119269.
|
||||
env.AppendUnique(CXXFLAGS=["-Wno-sfinae-incomplete"])
|
||||
elif methods.using_clang(env) or methods.using_emcc(env):
|
||||
common_warnings += ["-Wshadow-field-in-constructor", "-Wshadow-uncaptured-local"]
|
||||
# We often implement `operator<` for structs of pointers as a requirement
|
||||
|
|
@ -1030,7 +1008,6 @@ else: # GCC, Clang
|
|||
|
||||
if env["werror"]:
|
||||
env.AppendUnique(CCFLAGS=["-Werror"])
|
||||
env.AppendUnique(LINKFLAGS=["-Wl,--fatal-warnings" if env["platform"] != "macos" else "-Wl,-fatal_warnings"])
|
||||
|
||||
if hasattr(detect, "get_program_suffix"):
|
||||
suffix = "." + detect.get_program_suffix()
|
||||
|
|
@ -1200,6 +1177,10 @@ if env["compiledb"]:
|
|||
env["COMPILATIONDB_COMSTR"] = "$GENCOMSTR"
|
||||
|
||||
if env["ninja"]:
|
||||
if env.scons_version < (4, 2, 0):
|
||||
print_error(f"The `ninja=yes` option requires SCons 4.2 or later, but your version is {scons_raw_version}.")
|
||||
Exit(255)
|
||||
|
||||
SetOption("experimental", "ninja")
|
||||
env["NINJA_FILE_NAME"] = env["ninja_file"]
|
||||
env["NINJA_DISABLE_AUTO_RUN"] = not env["ninja_auto_run"]
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@ from misc.utility.scons_hints import *
|
|||
|
||||
Import("env")
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
||||
env_config = env.Clone()
|
||||
|
||||
env_config.add_source_files(env.core_sources, "*.cpp")
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "core/config/project_settings.h"
|
||||
#include "core/donors.gen.h"
|
||||
#include "core/license.gen.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
#include "core/version.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
|
@ -326,11 +326,6 @@ void Engine::print_header_rich(const String &p_string) const {
|
|||
|
||||
void Engine::add_singleton(const Singleton &p_singleton) {
|
||||
ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (p_singleton.ptr && p_singleton.ptr->is_ref_counted()) {
|
||||
WARN_PRINT(vformat("RefCounted singleton '%s' will be disallowed soon; raw pointer will dangle when last Ref is released. Use Object singleton.", p_singleton.name));
|
||||
}
|
||||
#endif
|
||||
singletons.push_back(p_singleton);
|
||||
singleton_ptrs[p_singleton.name] = p_singleton.ptr;
|
||||
}
|
||||
|
|
@ -450,4 +445,10 @@ Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const Stri
|
|||
name(p_name),
|
||||
ptr(p_ptr),
|
||||
class_name(p_class_name) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
|
||||
if (rc && !rc->is_referenced()) {
|
||||
WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "core/config/engine.h"
|
||||
|
||||
#include "modules/modules_enabled.gen.h" // IWYU pragma: keep. For mono.
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
|
|
@ -298,13 +297,13 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
|
|||
|
||||
if (p_value.get_type() == Variant::NIL) {
|
||||
props.erase(p_name);
|
||||
if (p_name.string().begins_with("autoload/")) {
|
||||
String node_name = p_name.string().get_slicec('/', 1);
|
||||
if (p_name.operator String().begins_with("autoload/")) {
|
||||
String node_name = p_name.operator String().get_slicec('/', 1);
|
||||
if (autoloads.has(node_name)) {
|
||||
remove_autoload(node_name);
|
||||
}
|
||||
} else if (p_name.string().begins_with("global_group/")) {
|
||||
String group_name = p_name.string().get_slicec('/', 1);
|
||||
} else if (p_name.operator String().begins_with("global_group/")) {
|
||||
String group_name = p_name.operator String().get_slicec('/', 1);
|
||||
if (global_groups.has(group_name)) {
|
||||
remove_global_group(group_name);
|
||||
}
|
||||
|
|
@ -322,9 +321,9 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
|
|||
}
|
||||
|
||||
{ // Feature overrides.
|
||||
int dot = p_name.string().find_char('.');
|
||||
int dot = p_name.operator String().find_char('.');
|
||||
if (dot != -1) {
|
||||
Vector<String> s = p_name.string().split(".");
|
||||
Vector<String> s = p_name.operator String().split(".");
|
||||
|
||||
for (int i = 1; i < s.size(); i++) {
|
||||
String feature = s[i].strip_edges();
|
||||
|
|
@ -344,8 +343,8 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
|
|||
} else {
|
||||
props[p_name] = VariantContainer(p_value, last_order++);
|
||||
}
|
||||
if (p_name.string().begins_with("autoload_prepend/")) {
|
||||
String node_name = p_name.string().get_slicec('/', 1);
|
||||
if (p_name.operator String().begins_with("autoload_prepend/")) {
|
||||
String node_name = p_name.operator String().get_slicec('/', 1);
|
||||
AutoloadInfo autoload;
|
||||
autoload.name = node_name;
|
||||
String path = p_value;
|
||||
|
|
@ -356,8 +355,8 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
|
|||
autoload.path = path.simplify_path();
|
||||
}
|
||||
add_autoload(autoload, true);
|
||||
} else if (p_name.string().begins_with("autoload/")) {
|
||||
String node_name = p_name.string().get_slicec('/', 1);
|
||||
} else if (p_name.operator String().begins_with("autoload/")) {
|
||||
String node_name = p_name.operator String().get_slicec('/', 1);
|
||||
AutoloadInfo autoload;
|
||||
autoload.name = node_name;
|
||||
String path = p_value;
|
||||
|
|
@ -368,8 +367,8 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
|
|||
autoload.path = path.simplify_path();
|
||||
}
|
||||
add_autoload(autoload);
|
||||
} else if (p_name.string().begins_with("global_group/")) {
|
||||
String group_name = p_name.string().get_slicec('/', 1);
|
||||
} else if (p_name.operator String().begins_with("global_group/")) {
|
||||
String group_name = p_name.operator String().get_slicec('/', 1);
|
||||
add_global_group(group_name, p_value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1736,15 +1735,13 @@ ProjectSettings::ProjectSettings() {
|
|||
GLOBAL_DEF("display/window/size/sharp_corners", false);
|
||||
GLOBAL_DEF("display/window/size/minimize_disabled", false);
|
||||
GLOBAL_DEF("display/window/size/maximize_disabled", false);
|
||||
GLOBAL_DEF("display/window/size/enable_toggle_fullscreen_shortcut", true);
|
||||
|
||||
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_BASIC("display/window/hdr/request_hdr_output", false);
|
||||
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_skeleton_modifier_node_paths", true);
|
||||
GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
|
||||
GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
|
@ -1818,7 +1815,7 @@ ProjectSettings::ProjectSettings() {
|
|||
|
||||
GLOBAL_DEF("gui/common/drag_threshold", 10);
|
||||
GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/common/show_focus_state_on_pointer_event", PROPERTY_HINT_ENUM, "Never,Text Input Controls,Always"), 1);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/common/show_focus_state_on_pointer_event", PROPERTY_HINT_ENUM, "Never,Control Supports Keyboard Input,Always"), 1);
|
||||
GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
|
||||
|
||||
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/vsync/frame_queue_size", PROPERTY_HINT_RANGE, "2,3,1"), 2);
|
||||
|
|
|
|||
|
|
@ -94,13 +94,11 @@ Vector<String> ResourceLoader::get_recognized_extensions_for_type(const String &
|
|||
return ret;
|
||||
}
|
||||
|
||||
void ResourceLoader::add_resource_format_loader(RequiredParam<ResourceFormatLoader> rp_format_loader, bool p_at_front) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_format_loader, rp_format_loader);
|
||||
void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) {
|
||||
::ResourceLoader::add_resource_format_loader(p_format_loader, p_at_front);
|
||||
}
|
||||
|
||||
void ResourceLoader::remove_resource_format_loader(RequiredParam<ResourceFormatLoader> rp_format_loader) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_format_loader, rp_format_loader);
|
||||
void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) {
|
||||
::ResourceLoader::remove_resource_format_loader(p_format_loader);
|
||||
}
|
||||
|
||||
|
|
@ -138,10 +136,6 @@ ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) {
|
|||
return ::ResourceLoader::get_resource_uid(p_path);
|
||||
}
|
||||
|
||||
String ResourceLoader::get_resource_type(const String &p_path) {
|
||||
return ::ResourceLoader::get_resource_type(p_path);
|
||||
}
|
||||
|
||||
Vector<String> ResourceLoader::list_directory(const String &p_directory) {
|
||||
return ::ResourceLoader::list_directory(p_directory);
|
||||
}
|
||||
|
|
@ -161,7 +155,6 @@ void ResourceLoader::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_cached_ref", "path"), &ResourceLoader::get_cached_ref);
|
||||
ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &ResourceLoader::exists, DEFVAL(""));
|
||||
ClassDB::bind_method(D_METHOD("get_resource_uid", "path"), &ResourceLoader::get_resource_uid);
|
||||
ClassDB::bind_method(D_METHOD("get_resource_type", "path"), &ResourceLoader::get_resource_type);
|
||||
ClassDB::bind_method(D_METHOD("list_directory", "directory_path"), &ResourceLoader::list_directory);
|
||||
|
||||
BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE);
|
||||
|
|
@ -186,8 +179,7 @@ Error ResourceSaver::set_uid(const String &p_path, ResourceUID::ID p_uid) {
|
|||
return ::ResourceSaver::set_uid(p_path, p_uid);
|
||||
}
|
||||
|
||||
Vector<String> ResourceSaver::get_recognized_extensions(RequiredParam<Resource> rp_resource) {
|
||||
EXTRACT_PARAM_OR_FAIL_V(p_resource, rp_resource, Vector<String>());
|
||||
Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource) {
|
||||
List<String> exts;
|
||||
::ResourceSaver::get_recognized_extensions(p_resource, &exts);
|
||||
Vector<String> ret;
|
||||
|
|
@ -197,13 +189,11 @@ Vector<String> ResourceSaver::get_recognized_extensions(RequiredParam<Resource>
|
|||
return ret;
|
||||
}
|
||||
|
||||
void ResourceSaver::add_resource_format_saver(RequiredParam<ResourceFormatSaver> rp_format_saver, bool p_at_front) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_format_saver, rp_format_saver);
|
||||
void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) {
|
||||
::ResourceSaver::add_resource_format_saver(p_format_saver, p_at_front);
|
||||
}
|
||||
|
||||
void ResourceSaver::remove_resource_format_saver(RequiredParam<ResourceFormatSaver> rp_format_saver) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_format_saver, rp_format_saver);
|
||||
void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) {
|
||||
::ResourceSaver::remove_resource_format_saver(p_format_saver);
|
||||
}
|
||||
|
||||
|
|
@ -567,10 +557,6 @@ String OS::get_locale() const {
|
|||
return ::OS::get_singleton()->get_locale();
|
||||
}
|
||||
|
||||
Vector<String> OS::get_preferred_locales() const {
|
||||
return ::OS::get_singleton()->get_preferred_locales();
|
||||
}
|
||||
|
||||
String OS::get_locale_language() const {
|
||||
return ::OS::get_singleton()->get_locale_language();
|
||||
}
|
||||
|
|
@ -722,8 +708,8 @@ String OS::get_unique_id() const {
|
|||
return ::OS::get_singleton()->get_unique_id();
|
||||
}
|
||||
|
||||
void OS::add_logger(RequiredParam<Logger> rp_logger) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_logger, rp_logger);
|
||||
void OS::add_logger(const Ref<Logger> &p_logger) {
|
||||
ERR_FAIL_COND(p_logger.is_null());
|
||||
|
||||
if (!logger_bind) {
|
||||
logger_bind = memnew(LoggerBind);
|
||||
|
|
@ -734,8 +720,8 @@ void OS::add_logger(RequiredParam<Logger> rp_logger) {
|
|||
logger_bind->loggers.push_back(p_logger);
|
||||
}
|
||||
|
||||
void OS::remove_logger(RequiredParam<Logger> rp_logger) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_logger, rp_logger);
|
||||
void OS::remove_logger(const Ref<Logger> &p_logger) {
|
||||
ERR_FAIL_COND(p_logger.is_null());
|
||||
ERR_FAIL_COND_MSG(!logger_bind || logger_bind->loggers.find(p_logger) == -1, "Could not remove logger, as it hasn't been added.");
|
||||
logger_bind->loggers.erase(p_logger);
|
||||
}
|
||||
|
|
@ -827,7 +813,6 @@ void OS::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &OS::delay_usec);
|
||||
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &OS::delay_msec);
|
||||
ClassDB::bind_method(D_METHOD("get_locale"), &OS::get_locale);
|
||||
ClassDB::bind_method(D_METHOD("get_preferred_locales"), &OS::get_preferred_locales);
|
||||
ClassDB::bind_method(D_METHOD("get_locale_language"), &OS::get_locale_language);
|
||||
ClassDB::bind_method(D_METHOD("get_model_name"), &OS::get_model_name);
|
||||
|
||||
|
|
@ -1681,15 +1666,13 @@ StringName ClassDB::class_get_property_setter(const StringName &p_class, const S
|
|||
return ::ClassDB::get_property_setter(p_class, p_property);
|
||||
}
|
||||
|
||||
Variant ClassDB::class_get_property(RequiredParam<Object> rp_object, const StringName &p_property) const {
|
||||
EXTRACT_PARAM_OR_FAIL_V(p_object, rp_object, Variant());
|
||||
Variant ClassDB::class_get_property(Object *p_object, const StringName &p_property) const {
|
||||
Variant ret;
|
||||
::ClassDB::get_property(p_object, p_property, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error ClassDB::class_set_property(RequiredParam<Object> rp_object, const StringName &p_property, const Variant &p_value) const {
|
||||
EXTRACT_PARAM_OR_FAIL_V(p_object, rp_object, ERR_INVALID_PARAMETER);
|
||||
Error ClassDB::class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const {
|
||||
Variant ret;
|
||||
bool valid;
|
||||
if (!::ClassDB::set_property(p_object, p_property, p_value, &valid)) {
|
||||
|
|
@ -1836,7 +1819,7 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List
|
|||
::ClassDB::get_class_list(classes);
|
||||
for (const StringName &E : classes) {
|
||||
if (::ClassDB::is_class_exposed(E)) {
|
||||
r_options->push_back(E.string().quote());
|
||||
r_options->push_back(E.operator String().quote());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2006,8 +1989,7 @@ Object *Engine::get_singleton_object(const StringName &p_name) const {
|
|||
return ::Engine::get_singleton()->get_singleton_object(p_name);
|
||||
}
|
||||
|
||||
void Engine::register_singleton(const StringName &p_name, RequiredParam<Object> rp_instance) {
|
||||
EXTRACT_PARAM_OR_FAIL(p_object, rp_instance);
|
||||
void Engine::register_singleton(const StringName &p_name, Object *p_object) {
|
||||
ERR_FAIL_COND_MSG(has_singleton(p_name), vformat("Singleton already registered: '%s'.", String(p_name)));
|
||||
ERR_FAIL_COND_MSG(!String(p_name).is_valid_ascii_identifier(), vformat("Singleton name is not a valid identifier: '%s'.", p_name));
|
||||
::Engine::Singleton s;
|
||||
|
|
@ -2034,13 +2016,11 @@ Vector<String> Engine::get_singleton_list() const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
Error Engine::register_script_language(RequiredParam<ScriptLanguage> rp_language) {
|
||||
EXTRACT_PARAM_OR_FAIL_V(p_language, rp_language, ERR_INVALID_PARAMETER);
|
||||
Error Engine::register_script_language(ScriptLanguage *p_language) {
|
||||
return ScriptServer::register_language(p_language);
|
||||
}
|
||||
|
||||
Error Engine::unregister_script_language(RequiredParam<const ScriptLanguage> rp_language) {
|
||||
EXTRACT_PARAM_OR_FAIL_V(p_language, rp_language, ERR_INVALID_PARAMETER);
|
||||
Error Engine::unregister_script_language(const ScriptLanguage *p_language) {
|
||||
return ScriptServer::unregister_language(p_language);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,15 +76,14 @@ public:
|
|||
|
||||
Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
|
||||
Vector<String> get_recognized_extensions_for_type(const String &p_type);
|
||||
void add_resource_format_loader(RequiredParam<ResourceFormatLoader> p_format_loader, bool p_at_front);
|
||||
void remove_resource_format_loader(RequiredParam<ResourceFormatLoader> p_format_loader);
|
||||
void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front);
|
||||
void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
|
||||
void set_abort_on_missing_resources(bool p_abort);
|
||||
PackedStringArray get_dependencies(const String &p_path);
|
||||
bool has_cached(const String &p_path);
|
||||
Ref<Resource> get_cached_ref(const String &p_path);
|
||||
bool exists(const String &p_path, const String &p_type_hint = "");
|
||||
ResourceUID::ID get_resource_uid(const String &p_path);
|
||||
String get_resource_type(const String &p_path);
|
||||
|
||||
Vector<String> list_directory(const String &p_directory);
|
||||
|
||||
|
|
@ -114,9 +113,9 @@ public:
|
|||
|
||||
Error save(RequiredParam<Resource> p_resource, const String &p_path, BitField<SaverFlags> p_flags);
|
||||
Error set_uid(const String &p_path, ResourceUID::ID p_uid);
|
||||
Vector<String> get_recognized_extensions(RequiredParam<Resource> p_resource);
|
||||
void add_resource_format_saver(RequiredParam<ResourceFormatSaver> p_format_saver, bool p_at_front);
|
||||
void remove_resource_format_saver(RequiredParam<ResourceFormatSaver> p_format_saver);
|
||||
Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
|
||||
void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
|
||||
void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
|
||||
|
||||
ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false);
|
||||
|
||||
|
|
@ -250,7 +249,6 @@ public:
|
|||
Vector<String> get_video_adapter_driver_info() const;
|
||||
|
||||
String get_locale() const;
|
||||
Vector<String> get_preferred_locales() const;
|
||||
String get_locale_language() const;
|
||||
|
||||
String get_model_name() const;
|
||||
|
|
@ -313,8 +311,8 @@ public:
|
|||
Vector<String> get_granted_permissions() const;
|
||||
void revoke_granted_permissions();
|
||||
|
||||
void add_logger(RequiredParam<Logger> p_logger);
|
||||
void remove_logger(RequiredParam<Logger> p_logger);
|
||||
void add_logger(const Ref<Logger> &p_logger);
|
||||
void remove_logger(const Ref<Logger> &p_logger);
|
||||
void remove_script_loggers(const ScriptLanguage *p_script);
|
||||
|
||||
static OS *get_singleton() { return singleton; }
|
||||
|
|
@ -535,8 +533,8 @@ public:
|
|||
TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
StringName class_get_property_getter(const StringName &p_class, const StringName &p_property);
|
||||
StringName class_get_property_setter(const StringName &p_class, const StringName &p_property);
|
||||
Variant class_get_property(RequiredParam<Object> p_object, const StringName &p_property) const;
|
||||
Error class_set_property(RequiredParam<Object> p_object, const StringName &p_property, const Variant &p_value) const;
|
||||
Variant class_get_property(Object *p_object, const StringName &p_property) const;
|
||||
Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
|
||||
|
||||
Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const;
|
||||
|
||||
|
|
@ -613,12 +611,12 @@ public:
|
|||
|
||||
bool has_singleton(const StringName &p_name) const;
|
||||
Object *get_singleton_object(const StringName &p_name) const;
|
||||
void register_singleton(const StringName &p_name, RequiredParam<Object> p_instance);
|
||||
void register_singleton(const StringName &p_name, Object *p_object);
|
||||
void unregister_singleton(const StringName &p_name);
|
||||
Vector<String> get_singleton_list() const;
|
||||
|
||||
Error register_script_language(RequiredParam<ScriptLanguage> p_language);
|
||||
Error unregister_script_language(RequiredParam<const ScriptLanguage> p_language);
|
||||
Error register_script_language(ScriptLanguage *p_language);
|
||||
Error unregister_script_language(const ScriptLanguage *p_language);
|
||||
int get_script_language_count();
|
||||
ScriptLanguage *get_script_language(int p_index) const;
|
||||
TypedArray<ScriptBacktrace> capture_script_backtraces(bool p_include_variables = false) const;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ def encryption_key_builder(target, source, env):
|
|||
#include <cstdint>
|
||||
|
||||
uint8_t script_encryption_key[32] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};"""
|
||||
)
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ def make_certs_header(target, source, env):
|
|||
inline constexpr int _certs_compressed_size = {len(buffer)};
|
||||
inline constexpr int _certs_uncompressed_size = {decomp_size};
|
||||
inline constexpr unsigned char _certs_compressed[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
""")
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@
|
|||
#include "core_constants.h"
|
||||
|
||||
#include "core/input/input_enums.h"
|
||||
#include "core/object/method_bind_common.h" // IWYU pragma: keep. For `VARIANT_BITFIELD_CAST(MethodFlags)`.
|
||||
#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"
|
||||
|
|
|
|||
|
|
@ -38,5 +38,4 @@ public:
|
|||
static inline bool leak_reporting_enabled = true;
|
||||
static inline bool print_line_enabled = true;
|
||||
static inline bool print_error_enabled = true;
|
||||
static inline bool print_ready = false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,45 +3,17 @@ from misc.utility.scons_hints import *
|
|||
|
||||
Import("env")
|
||||
|
||||
|
||||
def _escape_define(env, config):
|
||||
return f"<{config}>" if env["ninja"] and env.msvc else f'\\"{config}\\"'
|
||||
|
||||
|
||||
env_crypto = env.Clone()
|
||||
env_crypto.AddMethod(_escape_define, "EscapeDefine")
|
||||
|
||||
is_builtin = env["builtin_mbedtls"]
|
||||
has_module = env["module_mbedtls_enabled"]
|
||||
thirdparty_obj = []
|
||||
configs = []
|
||||
|
||||
if is_builtin or not has_module:
|
||||
# Use our headers for builtin or if the module is not going to be compiled.
|
||||
# We decided not to depend on system mbedtls and bundle a minimal version
|
||||
# when building without the module.
|
||||
env_crypto.Prepend(
|
||||
CPPPATH=[
|
||||
"#thirdparty/mbedtls/godot/",
|
||||
"#thirdparty/mbedtls/include/",
|
||||
"#thirdparty/mbedtls/tf-psa-crypto/include/",
|
||||
"#thirdparty/mbedtls/tf-psa-crypto/drivers/builtin/include/",
|
||||
]
|
||||
)
|
||||
env_crypto.Append(
|
||||
CPPDEFINES=[
|
||||
("TF_PSA_CRYPTO_CONFIG_FILE", env_crypto.EscapeDefine("godot_psa_config.h")),
|
||||
("MBEDTLS_CONFIG_FILE", env_crypto.EscapeDefine("godot_mbedtls_config.h")),
|
||||
]
|
||||
)
|
||||
configs = ["#thirdparty/mbedtls/godot/godot_psa_config.h", "#thirdparty/mbedtls/godot/godot_mbedtls_config.h"]
|
||||
if not has_module:
|
||||
env_crypto.Append(CPPDEFINES=["GODOT_MBEDTLS_LIGHT"])
|
||||
# Our custom mbedTLS platform functions
|
||||
platform_obj = []
|
||||
env_crypto.add_source_files(platform_obj, ["#thirdparty/mbedtls/godot/godot_mbedtls_platform.cpp"])
|
||||
env.core_sources += platform_obj
|
||||
env.Depends(platform_obj, configs)
|
||||
# We decided not to depend on system mbedtls just for these few files that can
|
||||
# be easily extracted.
|
||||
env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
|
||||
|
||||
# MbedTLS core functions (for CryptoCore).
|
||||
# If the mbedtls module is compiled we don't need to add the .c files with our
|
||||
|
|
@ -49,54 +21,45 @@ if is_builtin or not has_module:
|
|||
# Only if the module is not enabled, we must compile here the required sources
|
||||
# to make a "light" build with only the necessary mbedtls files.
|
||||
if not has_module:
|
||||
# Minimal mbedTLS config file
|
||||
config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
|
||||
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
|
||||
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
|
||||
# Build minimal mbedTLS library (MD5/SHA/Base64/AES).
|
||||
env_thirdparty = env_crypto.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
psa_dir = "#thirdparty/mbedtls/tf-psa-crypto/"
|
||||
env_thirdparty.Prepend(
|
||||
CPPPATH=[
|
||||
psa_dir + d
|
||||
for d in ["include/", "core/", "dispatch/", "extras", "platform/", "utilities/", "drivers/builtin/src/"]
|
||||
]
|
||||
)
|
||||
env_thirdparty.Prepend(CPPPATH=["#thirdparty/mbedtls/tf-psa-crypto/drivers/builtin/include/"])
|
||||
|
||||
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/"
|
||||
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
|
||||
thirdparty_mbedtls_sources = [
|
||||
"tf-psa-crypto/core/psa_crypto.c",
|
||||
"tf-psa-crypto/core/psa_crypto_client.c",
|
||||
"tf-psa-crypto/core/psa_crypto_driver_wrappers_no_static.c",
|
||||
"tf-psa-crypto/core/psa_crypto_random.c",
|
||||
"tf-psa-crypto/core/psa_crypto_slot_management.c",
|
||||
"tf-psa-crypto/utilities/base64.c",
|
||||
"tf-psa-crypto/utilities/constant_time.c",
|
||||
"tf-psa-crypto/platform/threading.c",
|
||||
"tf-psa-crypto/extras/md.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/aes.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/ctr_drbg.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/cipher.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/cipher_wrap.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/entropy.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/entropy_poll.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/md5.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/psa_util_internal.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/sha1.c",
|
||||
"tf-psa-crypto/drivers/builtin/src/sha256.c",
|
||||
"aes.c",
|
||||
"base64.c",
|
||||
"constant_time.c",
|
||||
"ctr_drbg.c",
|
||||
"entropy.c",
|
||||
"md.c",
|
||||
"md5.c",
|
||||
"sha1.c",
|
||||
"sha256.c",
|
||||
"godot_core_mbedtls_platform.c",
|
||||
]
|
||||
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
|
||||
# Needed to force rebuilding the library when the configuration file is updated.
|
||||
env_thirdparty.Depends(thirdparty_obj, configs)
|
||||
env_thirdparty.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_core_mbedtls_config.h")
|
||||
env.core_sources += thirdparty_obj
|
||||
elif is_builtin:
|
||||
# Module mbedTLS config file
|
||||
config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
|
||||
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
|
||||
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
|
||||
# Needed to force rebuilding the core files when the configuration file is updated.
|
||||
thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
|
||||
|
||||
# Godot source files
|
||||
|
||||
core_obj = []
|
||||
|
||||
env_crypto.add_source_files(core_obj, "*.cpp")
|
||||
env.core_sources += core_obj
|
||||
|
||||
# Needed to force rebuilding the core files when the thirdparty library is updated.
|
||||
env.Depends(core_obj, thirdparty_obj + configs)
|
||||
env.Depends(core_obj, thirdparty_obj)
|
||||
|
|
|
|||
|
|
@ -32,49 +32,23 @@
|
|||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
using AESMode = CryptoCore::AESContext::Mode;
|
||||
using AESCipher = CryptoCore::AESContext::Cipher;
|
||||
|
||||
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.");
|
||||
ERR_FAIL_COND_V_MSG(p_mode < 0 || p_mode >= MODE_MAX, ERR_INVALID_PARAMETER, "Invalid mode requested.");
|
||||
// Key check.
|
||||
int key_bits = p_key.size() << 3;
|
||||
ERR_FAIL_COND_V_MSG(key_bits != 128 && key_bits != 256, ERR_INVALID_PARAMETER, "AES key must be either 16 or 32 bytes");
|
||||
|
||||
AESMode ctx_mode = AESMode::NONE;
|
||||
AESCipher ctx_cipher = AESCipher::NONE;
|
||||
switch (p_mode) {
|
||||
case MODE_ECB_ENCRYPT:
|
||||
ctx_mode = AESMode::ENCRYPT;
|
||||
ctx_cipher = AESCipher::ECB;
|
||||
break;
|
||||
case MODE_ECB_DECRYPT:
|
||||
ctx_mode = AESMode::DECRYPT;
|
||||
ctx_cipher = AESCipher::ECB;
|
||||
break;
|
||||
case MODE_CBC_ENCRYPT:
|
||||
ctx_mode = AESMode::ENCRYPT;
|
||||
ctx_cipher = AESCipher::CBC;
|
||||
break;
|
||||
case MODE_CBC_DECRYPT:
|
||||
ctx_mode = AESMode::DECRYPT;
|
||||
ctx_cipher = AESCipher::CBC;
|
||||
break;
|
||||
default:
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
// Initialization vector.
|
||||
PackedByteArray iv = p_iv;
|
||||
ERR_FAIL_COND_V_MSG(ctx_cipher == AESCipher::CBC && iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes.");
|
||||
if (unlikely(ctx_cipher == AESCipher::ECB && iv.size())) {
|
||||
WARN_PRINT("ECB mode does not require an initialization vector (IV). Pass an empty IV argument when using ECB.");
|
||||
iv.clear();
|
||||
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_CBC_DECRYPT) {
|
||||
ERR_FAIL_COND_V_MSG(p_iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes.");
|
||||
iv.resize(0);
|
||||
iv.append_array(p_iv);
|
||||
}
|
||||
Error err = ctx.setup(ctx_mode, ctx_cipher, p_key.ptr(), p_key.size(), iv.size() ? iv.ptr() : nullptr, iv.size());
|
||||
if (err != OK) {
|
||||
return err;
|
||||
// Encryption/decryption key.
|
||||
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_ECB_ENCRYPT) {
|
||||
ctx.set_encode_key(p_key.ptr(), key_bits);
|
||||
} else {
|
||||
ctx.set_decode_key(p_key.ptr(), key_bits);
|
||||
}
|
||||
mode = p_mode;
|
||||
return OK;
|
||||
|
|
@ -86,18 +60,45 @@ PackedByteArray AESContext::update(const PackedByteArray &p_src) {
|
|||
ERR_FAIL_COND_V_MSG(len % 16, PackedByteArray(), "The number of bytes to be encrypted must be multiple of 16. Add padding if needed");
|
||||
PackedByteArray out;
|
||||
out.resize(len);
|
||||
Error err = ctx.update(p_src.ptr(), len, out.ptrw(), len);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
const uint8_t *src_ptr = p_src.ptr();
|
||||
uint8_t *out_ptr = out.ptrw();
|
||||
switch (mode) {
|
||||
case MODE_ECB_ENCRYPT: {
|
||||
for (int i = 0; i < len; i += 16) {
|
||||
Error err = ctx.encrypt_ecb(src_ptr + i, out_ptr + i);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
}
|
||||
} break;
|
||||
case MODE_ECB_DECRYPT: {
|
||||
for (int i = 0; i < len; i += 16) {
|
||||
Error err = ctx.decrypt_ecb(src_ptr + i, out_ptr + i);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
}
|
||||
} break;
|
||||
case MODE_CBC_ENCRYPT: {
|
||||
Error err = ctx.encrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
} break;
|
||||
case MODE_CBC_DECRYPT: {
|
||||
Error err = ctx.decrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
} break;
|
||||
default:
|
||||
ERR_FAIL_V_MSG(PackedByteArray(), "Bug!");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
PackedByteArray AESContext::get_iv_state() {
|
||||
ERR_FAIL_V_MSG(PackedByteArray(), "Calling 'get_iv_state' is no longer supported.");
|
||||
ERR_FAIL_COND_V_MSG(mode != MODE_CBC_ENCRYPT && mode != MODE_CBC_DECRYPT, PackedByteArray(), "Calling 'get_iv_state' only makes sense when the context is started in CBC mode.");
|
||||
PackedByteArray out;
|
||||
out.append_array(iv);
|
||||
return out;
|
||||
}
|
||||
|
||||
void AESContext::finish() {
|
||||
ctx.finish(nullptr, 0);
|
||||
mode = MODE_MAX;
|
||||
iv.resize(0);
|
||||
}
|
||||
|
||||
void AESContext::_bind_methods() {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public:
|
|||
private:
|
||||
Mode mode = MODE_MAX;
|
||||
CryptoCore::AESContext ctx;
|
||||
PackedByteArray iv;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
|
|
|||
|
|
@ -179,3 +179,82 @@ void Crypto::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest);
|
||||
ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare);
|
||||
}
|
||||
|
||||
/// Resource loader/saver
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
X509Certificate *cert = X509Certificate::create();
|
||||
if (cert) {
|
||||
cert->load(p_path);
|
||||
}
|
||||
return cert;
|
||||
} else if (el == "key") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, false);
|
||||
}
|
||||
return key;
|
||||
} else if (el == "pub") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, true);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("crt");
|
||||
p_extensions->push_back("key");
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
|
||||
return p_type == "X509Certificate" || p_type == "CryptoKey";
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
return "X509Certificate";
|
||||
} else if (el == "key" || el == "pub") {
|
||||
return "CryptoKey";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Error err;
|
||||
Ref<X509Certificate> cert = p_resource;
|
||||
Ref<CryptoKey> key = p_resource;
|
||||
if (cert.is_valid()) {
|
||||
err = cert->save(p_path);
|
||||
} else if (key.is_valid()) {
|
||||
err = key->save(p_path, p_path.has_extension("pub"));
|
||||
} else {
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
}
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path));
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
|
||||
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
|
||||
if (cert) {
|
||||
p_extensions->push_back("crt");
|
||||
}
|
||||
if (key) {
|
||||
if (!key->is_public_only()) {
|
||||
p_extensions->push_back("key");
|
||||
}
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
|
||||
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "core/crypto/hashing_context.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class CryptoKey : public Resource {
|
||||
|
|
@ -142,3 +144,26 @@ public:
|
|||
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
bool constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received);
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
|
||||
// Treat certificates as text files, do not generate a `*.{crt,key,pub}.uid` file.
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override { return ResourceUID::INVALID_ID; }
|
||||
virtual bool has_custom_uid_support() const override { return true; }
|
||||
};
|
||||
|
||||
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
|
||||
GDSOFTCLASS(ResourceFormatSaverCrypto, ResourceFormatSaver);
|
||||
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,200 +33,188 @@
|
|||
#include "core/os/os.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <psa/crypto.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/md5.h>
|
||||
#include <mbedtls/sha1.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#if MBEDTLS_VERSION_MAJOR >= 3
|
||||
#include <mbedtls/compat-2.x.h>
|
||||
#endif
|
||||
|
||||
// RandomGenerator
|
||||
CryptoCore::RandomGenerator::RandomGenerator() {
|
||||
entropy = memalloc(sizeof(mbedtls_entropy_context));
|
||||
mbedtls_entropy_init((mbedtls_entropy_context *)entropy);
|
||||
mbedtls_entropy_add_source((mbedtls_entropy_context *)entropy, &CryptoCore::RandomGenerator::_entropy_poll, nullptr, 256, MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
ctx = memalloc(sizeof(mbedtls_ctr_drbg_context));
|
||||
mbedtls_ctr_drbg_init((mbedtls_ctr_drbg_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::RandomGenerator::~RandomGenerator() {
|
||||
mbedtls_ctr_drbg_free((mbedtls_ctr_drbg_context *)ctx);
|
||||
memfree(ctx);
|
||||
mbedtls_entropy_free((mbedtls_entropy_context *)entropy);
|
||||
memfree(entropy);
|
||||
}
|
||||
|
||||
int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len) {
|
||||
*r_len = 0;
|
||||
Error err = OS::get_singleton()->get_entropy(r_buffer, p_len);
|
||||
ERR_FAIL_COND_V(err, MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
|
||||
*r_len = p_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Error CryptoCore::RandomGenerator::init() {
|
||||
int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
|
||||
if (ret) {
|
||||
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
|
||||
ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
|
||||
int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
|
||||
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
|
||||
return OK;
|
||||
}
|
||||
|
||||
// MD5
|
||||
CryptoCore::MD5Context::MD5Context() {
|
||||
ctx = memalloc_zeroed(sizeof(psa_hash_operation_t));
|
||||
ctx = memalloc(sizeof(mbedtls_md5_context));
|
||||
mbedtls_md5_init((mbedtls_md5_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::MD5Context::~MD5Context() {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
memfree((psa_hash_operation_t *)ctx);
|
||||
mbedtls_md5_free((mbedtls_md5_context *)ctx);
|
||||
memfree((mbedtls_md5_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::start() {
|
||||
int ret = psa_hash_setup((psa_hash_operation_t *)ctx, PSA_ALG_MD5);
|
||||
int ret = mbedtls_md5_starts_ret((mbedtls_md5_context *)ctx);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = psa_hash_update((psa_hash_operation_t *)ctx, p_src, p_len);
|
||||
int ret = mbedtls_md5_update_ret((mbedtls_md5_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::finish(unsigned char r_hash[16]) {
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_finish((psa_hash_operation_t *)ctx, r_hash, 16, &size);
|
||||
if (ret) {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
return FAILED;
|
||||
}
|
||||
ERR_FAIL_COND_V(size != 16, ERR_BUG);
|
||||
return OK;
|
||||
int ret = mbedtls_md5_finish_ret((mbedtls_md5_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// SHA1
|
||||
CryptoCore::SHA1Context::SHA1Context() {
|
||||
ctx = memalloc_zeroed(sizeof(psa_hash_operation_t));
|
||||
ctx = memalloc(sizeof(mbedtls_sha1_context));
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::SHA1Context::~SHA1Context() {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
memfree((psa_hash_operation_t *)ctx);
|
||||
mbedtls_sha1_free((mbedtls_sha1_context *)ctx);
|
||||
memfree((mbedtls_sha1_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::start() {
|
||||
int ret = psa_hash_setup((psa_hash_operation_t *)ctx, PSA_ALG_SHA_1);
|
||||
int ret = mbedtls_sha1_starts_ret((mbedtls_sha1_context *)ctx);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = psa_hash_update((psa_hash_operation_t *)ctx, p_src, p_len);
|
||||
int ret = mbedtls_sha1_update_ret((mbedtls_sha1_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::finish(unsigned char r_hash[20]) {
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_finish((psa_hash_operation_t *)ctx, r_hash, 20, &size);
|
||||
if (ret) {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
return FAILED;
|
||||
}
|
||||
ERR_FAIL_COND_V(size != 20, ERR_BUG);
|
||||
return OK;
|
||||
int ret = mbedtls_sha1_finish_ret((mbedtls_sha1_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// SHA256
|
||||
CryptoCore::SHA256Context::SHA256Context() {
|
||||
ctx = memalloc_zeroed(sizeof(psa_hash_operation_t));
|
||||
ctx = memalloc(sizeof(mbedtls_sha256_context));
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::SHA256Context::~SHA256Context() {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
memfree((psa_hash_operation_t *)ctx);
|
||||
mbedtls_sha256_free((mbedtls_sha256_context *)ctx);
|
||||
memfree((mbedtls_sha256_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::start() {
|
||||
int ret = psa_hash_setup((psa_hash_operation_t *)ctx, PSA_ALG_SHA_256);
|
||||
int ret = mbedtls_sha256_starts_ret((mbedtls_sha256_context *)ctx, 0);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = psa_hash_update((psa_hash_operation_t *)ctx, p_src, p_len);
|
||||
int ret = mbedtls_sha256_update_ret((mbedtls_sha256_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::finish(unsigned char r_hash[32]) {
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_finish((psa_hash_operation_t *)ctx, r_hash, 32, &size);
|
||||
if (ret) {
|
||||
psa_hash_abort((psa_hash_operation_t *)ctx);
|
||||
return FAILED;
|
||||
}
|
||||
ERR_FAIL_COND_V(size != 32, ERR_BUG);
|
||||
return OK;
|
||||
int ret = mbedtls_sha256_finish_ret((mbedtls_sha256_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// AES256
|
||||
CryptoCore::AESContext::AESContext() {
|
||||
ctx = memalloc_zeroed(sizeof(psa_cipher_operation_t));
|
||||
ctx = memalloc(sizeof(mbedtls_aes_context));
|
||||
mbedtls_aes_init((mbedtls_aes_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::AESContext::~AESContext() {
|
||||
psa_cipher_abort((psa_cipher_operation_t *)ctx);
|
||||
psa_destroy_key(key_id);
|
||||
memfree((psa_cipher_operation_t *)ctx);
|
||||
mbedtls_aes_free((mbedtls_aes_context *)ctx);
|
||||
memfree((mbedtls_aes_context *)ctx);
|
||||
}
|
||||
|
||||
void CryptoCore::AESContext::reset() {
|
||||
psa_cipher_abort((psa_cipher_operation_t *)ctx);
|
||||
psa_destroy_key(key_id);
|
||||
key_id = PSA_KEY_ID_NULL;
|
||||
alg = PSA_ALG_NONE;
|
||||
Error CryptoCore::AESContext::set_encode_key(const uint8_t *p_key, size_t p_bits) {
|
||||
int ret = mbedtls_aes_setkey_enc((mbedtls_aes_context *)ctx, p_key, p_bits);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::setup(Mode p_mode, Cipher p_cipher, const uint8_t *p_key, size_t p_key_length, const uint8_t *p_iv, size_t p_iv_size) {
|
||||
reset();
|
||||
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
|
||||
switch (p_mode) {
|
||||
case Mode::NONE:
|
||||
return OK;
|
||||
case Mode::ENCRYPT:
|
||||
case Mode::DECRYPT:
|
||||
break;
|
||||
default:
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
switch (p_cipher) {
|
||||
case Cipher::CBC:
|
||||
alg = PSA_ALG_CBC_NO_PADDING;
|
||||
break;
|
||||
case Cipher::ECB:
|
||||
alg = PSA_ALG_ECB_NO_PADDING;
|
||||
break;
|
||||
case Cipher::CFB:
|
||||
alg = PSA_ALG_CFB;
|
||||
break;
|
||||
default:
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
|
||||
psa_set_key_algorithm(&attr, alg);
|
||||
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
|
||||
psa_set_key_bits(&attr, p_key_length << 3);
|
||||
int ret = psa_import_key(&attr, p_key, p_key_length, &key_id);
|
||||
if (ret) {
|
||||
return FAILED;
|
||||
}
|
||||
if (p_mode == Mode::ENCRYPT) {
|
||||
ret = psa_cipher_encrypt_setup((psa_cipher_operation_t *)ctx, key_id, alg);
|
||||
} else {
|
||||
ret = psa_cipher_decrypt_setup((psa_cipher_operation_t *)ctx, key_id, alg);
|
||||
}
|
||||
if (ret == PSA_SUCCESS && p_iv_size) {
|
||||
ret = psa_cipher_set_iv((psa_cipher_operation_t *)ctx, p_iv, p_iv_size);
|
||||
}
|
||||
if (ret) {
|
||||
reset();
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
Error CryptoCore::AESContext::set_decode_key(const uint8_t *p_key, size_t p_bits) {
|
||||
int ret = mbedtls_aes_setkey_dec((mbedtls_aes_context *)ctx, p_key, p_bits);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::update(const uint8_t *p_src, size_t p_src_size, uint8_t *r_dst, size_t p_dst_size) {
|
||||
size_t size = 0;
|
||||
int ret = psa_cipher_update((psa_cipher_operation_t *)ctx, p_src, p_src_size, r_dst, p_dst_size, &size);
|
||||
if (ret) {
|
||||
return FAILED;
|
||||
}
|
||||
ERR_FAIL_COND_V(p_dst_size != size, ERR_BUG);
|
||||
return OK;
|
||||
Error CryptoCore::AESContext::encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
|
||||
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::finish(uint8_t *r_dst, size_t p_dst_size) {
|
||||
size_t size = 0;
|
||||
int ret = psa_cipher_finish((psa_cipher_operation_t *)ctx, r_dst, p_dst_size, &size);
|
||||
reset();
|
||||
if (ret) {
|
||||
return FAILED;
|
||||
}
|
||||
ERR_FAIL_COND_V(p_dst_size != size, ERR_BUG);
|
||||
return OK;
|
||||
Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
|
||||
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
|
||||
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, r_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
|
||||
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// CryptoCore
|
||||
Error CryptoCore::generate_random(uint8_t *r_buffer, size_t p_buffer_len) {
|
||||
if (unlikely(!initialized)) {
|
||||
// Fall back to raw get_entropy (might affect performance).
|
||||
return OS::get_singleton()->get_entropy(r_buffer, p_buffer_len);
|
||||
}
|
||||
int ret = psa_generate_random(r_buffer, p_buffer_len);
|
||||
ERR_FAIL_COND_V(ret, FAILED);
|
||||
return OK;
|
||||
}
|
||||
|
||||
String CryptoCore::b64_encode_str(const uint8_t *p_src, size_t p_src_len) {
|
||||
size_t b64len = p_src_len / 3 * 4 + 4 + 1;
|
||||
Vector<uint8_t> b64buff;
|
||||
|
|
@ -249,66 +237,16 @@ Error CryptoCore::b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, co
|
|||
}
|
||||
|
||||
Error CryptoCore::md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]) {
|
||||
ERR_FAIL_COND_V(PSA_HASH_LENGTH(PSA_ALG_MD5) != 16, ERR_BUG);
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_compute(PSA_ALG_MD5, p_src, p_src_len, r_hash, 16, &size);
|
||||
int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]) {
|
||||
ERR_FAIL_COND_V(PSA_HASH_LENGTH(PSA_ALG_SHA_1) != 20, ERR_BUG);
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_compute(PSA_ALG_SHA_1, p_src, p_src_len, r_hash, 20, &size);
|
||||
int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]) {
|
||||
ERR_FAIL_COND_V(PSA_HASH_LENGTH(PSA_ALG_SHA_256) != 32, ERR_BUG);
|
||||
size_t size = 0;
|
||||
int ret = psa_hash_compute(PSA_ALG_SHA_256, p_src, p_src_len, r_hash, 32, &size);
|
||||
int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::encrypt_cfb(const uint8_t *p_src, uint8_t *r_dst, size_t p_length, const uint8_t *p_key, size_t p_key_length, const uint8_t p_iv[16]) {
|
||||
AESContext ctx;
|
||||
Error err = ctx.setup(AESContext::Mode::ENCRYPT, AESContext::Cipher::CFB, p_key, p_key_length, p_iv, 16);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
err = ctx.update(p_src, p_length, r_dst, p_length);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
err = ctx.finish(nullptr, 0);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::decrypt_cfb(const uint8_t *p_src, uint8_t *r_dst, size_t p_length, const uint8_t *p_key, size_t p_key_length, const uint8_t p_iv[16]) {
|
||||
AESContext ctx;
|
||||
Error err = ctx.setup(AESContext::Mode::DECRYPT, AESContext::Cipher::CFB, p_key, p_key_length, p_iv, 16);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
err = ctx.update(p_src, p_length, r_dst, p_length);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
err = ctx.finish(nullptr, 0);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool CryptoCore::initialized = false;
|
||||
void CryptoCore::initialize() {
|
||||
ERR_FAIL_COND(initialized);
|
||||
#ifdef GODOT_MBEDTLS_PLATFORM
|
||||
godot_mbedtls_platform_init();
|
||||
#endif
|
||||
|
||||
int status = psa_crypto_init();
|
||||
ERR_FAIL_COND_MSG(status != PSA_SUCCESS, "Failed to initialize psa crypto. Cryptographic functions will not work.");
|
||||
initialized = true;
|
||||
}
|
||||
void CryptoCore::finalize() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = false;
|
||||
mbedtls_psa_crypto_free(); // Not part of PSA for reasons.
|
||||
#ifdef GODOT_MBEDTLS_PLATFORM
|
||||
godot_mbedtls_platform_free();
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,12 +38,21 @@
|
|||
class String;
|
||||
|
||||
class CryptoCore {
|
||||
private:
|
||||
static bool initialized;
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
class RandomGenerator {
|
||||
private:
|
||||
void *entropy = nullptr;
|
||||
void *ctx = nullptr;
|
||||
|
||||
static int _entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len);
|
||||
|
||||
public:
|
||||
RandomGenerator();
|
||||
~RandomGenerator();
|
||||
|
||||
Error init();
|
||||
Error get_random_bytes(uint8_t *r_buffer, size_t p_bytes);
|
||||
};
|
||||
|
||||
class MD5Context {
|
||||
private:
|
||||
|
|
@ -85,37 +94,23 @@ public:
|
|||
};
|
||||
|
||||
class AESContext {
|
||||
public:
|
||||
enum class Mode {
|
||||
NONE,
|
||||
ENCRYPT,
|
||||
DECRYPT,
|
||||
};
|
||||
enum class Cipher {
|
||||
NONE,
|
||||
CBC,
|
||||
CFB,
|
||||
ECB,
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t key_id = 0;
|
||||
uint32_t alg = 0;
|
||||
void *ctx = nullptr;
|
||||
|
||||
void reset();
|
||||
|
||||
public:
|
||||
AESContext();
|
||||
~AESContext();
|
||||
|
||||
Error setup(Mode p_mode, Cipher p_cipher, const uint8_t *p_key, size_t p_key_length, const uint8_t *p_iv, size_t p_iv_size);
|
||||
Error update(const uint8_t *p_src, size_t p_src_size, uint8_t *r_dst, size_t p_dst_size);
|
||||
Error finish(uint8_t *r_dst, size_t p_dst_size);
|
||||
Error set_encode_key(const uint8_t *p_key, size_t p_bits);
|
||||
Error set_decode_key(const uint8_t *p_key, size_t p_bits);
|
||||
Error encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
|
||||
Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
|
||||
Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
};
|
||||
|
||||
static Error generate_random(uint8_t *r_buffer, size_t p_buffer_len);
|
||||
|
||||
static String b64_encode_str(const uint8_t *p_src, size_t p_src_len);
|
||||
static Error b64_encode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
|
||||
static Error b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
|
||||
|
|
@ -123,7 +118,4 @@ public:
|
|||
static Error md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]);
|
||||
static Error sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]);
|
||||
static Error sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]);
|
||||
|
||||
static Error encrypt_cfb(const uint8_t *p_src, uint8_t *r_dst, size_t p_length, const uint8_t *p_key, size_t p_key_length, const uint8_t p_iv[16]);
|
||||
static Error decrypt_cfb(const uint8_t *p_src, uint8_t *r_dst, size_t p_length, const uint8_t *p_key, size_t p_key_length, const uint8_t p_iv[16]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto_resource_format.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "crypto_resource_format.h"
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
X509Certificate *cert = X509Certificate::create();
|
||||
if (cert) {
|
||||
cert->load(p_path);
|
||||
}
|
||||
return cert;
|
||||
} else if (el == "key") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, false);
|
||||
}
|
||||
return key;
|
||||
} else if (el == "pub") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, true);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("crt");
|
||||
p_extensions->push_back("key");
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
|
||||
return p_type == "X509Certificate" || p_type == "CryptoKey";
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
return "X509Certificate";
|
||||
} else if (el == "key" || el == "pub") {
|
||||
return "CryptoKey";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Error err;
|
||||
Ref<X509Certificate> cert = p_resource;
|
||||
Ref<CryptoKey> key = p_resource;
|
||||
if (cert.is_valid()) {
|
||||
err = cert->save(p_path);
|
||||
} else if (key.is_valid()) {
|
||||
err = key->save(p_path, p_path.has_extension("pub"));
|
||||
} else {
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
}
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path));
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
|
||||
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
|
||||
if (cert) {
|
||||
p_extensions->push_back("crt");
|
||||
}
|
||||
if (key) {
|
||||
if (!key->is_public_only()) {
|
||||
p_extensions->push_back("key");
|
||||
}
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
|
||||
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto_resource_format.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/io/resource_uid.h"
|
||||
|
||||
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
|
||||
// Treat certificates as text files, do not generate a `*.{crt,key,pub}.uid` file.
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override { return ResourceUID::INVALID_ID; }
|
||||
virtual bool has_custom_uid_support() const override { return true; }
|
||||
};
|
||||
|
||||
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
|
||||
GDSOFTCLASS(ResourceFormatSaverCrypto, ResourceFormatSaver);
|
||||
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
|
@ -81,20 +81,16 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
|
|||
} else {
|
||||
arr.push_back(var);
|
||||
}
|
||||
|
||||
arr.push_back(type_hint);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
|
||||
CHECK_SIZE(p_arr, 5, "ScriptStackVariable");
|
||||
CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
|
||||
name = p_arr[0];
|
||||
type = p_arr[1];
|
||||
var_type = p_arr[2];
|
||||
value = p_arr[3];
|
||||
type_hint = p_arr[4];
|
||||
CHECK_END(p_arr, 5, "ScriptStackVariable");
|
||||
CHECK_END(p_arr, 4, "ScriptStackVariable");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -181,27 +177,3 @@ Ref<Shortcut> DebuggerMarshalls::deserialize_key_shortcut(const Array &p_keys) {
|
|||
shortcut->set_events(key_events);
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
String DebuggerMarshalls::parse_type_from_variant(const Variant &p_variant) {
|
||||
String name;
|
||||
|
||||
if (p_variant.get_type() == Variant::OBJECT) {
|
||||
const Object *obj = p_variant.get_validated_object();
|
||||
if (obj) {
|
||||
const ScriptInstance *script_instance = obj->get_script_instance();
|
||||
|
||||
if (script_instance) {
|
||||
Ref<Script> script = script_instance->get_script();
|
||||
if (script.is_valid()) {
|
||||
name = script->get_global_name();
|
||||
}
|
||||
}
|
||||
|
||||
if (name.is_empty()) {
|
||||
return obj->get_class();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ struct DebuggerMarshalls {
|
|||
Variant value;
|
||||
int type = -1;
|
||||
int var_type = -1;
|
||||
String type_hint;
|
||||
|
||||
Array serialize(int max_size = 1 << 20); // 1 MiB default.
|
||||
bool deserialize(const Array &p_arr);
|
||||
|
|
@ -71,6 +70,4 @@ struct DebuggerMarshalls {
|
|||
|
||||
static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut);
|
||||
static Ref<Shortcut> deserialize_key_shortcut(const Array &p_keys);
|
||||
|
||||
static String parse_type_from_variant(const Variant &p_variant);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -138,8 +138,8 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, bo
|
|||
CreatePeerFunc *create_fn = protocols.getptr(proto);
|
||||
ERR_FAIL_NULL_MSG(create_fn, vformat("Invalid protocol: %s.", proto));
|
||||
|
||||
Ref<RemoteDebuggerPeer> peer = (*create_fn)(p_uri);
|
||||
if (peer.is_null()) {
|
||||
RemoteDebuggerPeer *peer = (*create_fn)(p_uri);
|
||||
if (!peer) {
|
||||
return;
|
||||
}
|
||||
singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
|
|
@ -48,7 +47,7 @@ public:
|
|||
|
||||
typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
|
||||
|
||||
typedef Ref<RemoteDebuggerPeer> (*CreatePeerFunc)(const String &p_uri);
|
||||
typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri);
|
||||
|
||||
class Profiler {
|
||||
friend class EngineDebugger;
|
||||
|
|
|
|||
|
|
@ -329,7 +329,6 @@ void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_va
|
|||
stvar.name = E->get();
|
||||
stvar.value = F->get();
|
||||
stvar.type = p_type;
|
||||
stvar.type_hint = DebuggerMarshalls::parse_type_from_variant(F->get());
|
||||
send_message("stack_frame_var", stvar.serialize());
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ void RemoteDebuggerPeerTCP::_write_out() {
|
|||
void RemoteDebuggerPeerTCP::_read_in() {
|
||||
while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_IN) == OK) {
|
||||
uint8_t *buf = in_buf.ptrw();
|
||||
Error err = OK;
|
||||
if (in_left <= 0) {
|
||||
if (in_queue.size() > max_queued_messages) {
|
||||
break; // Too many messages already in queue.
|
||||
|
|
@ -139,29 +138,18 @@ void RemoteDebuggerPeerTCP::_read_in() {
|
|||
}
|
||||
uint32_t size = 0;
|
||||
int read = 0;
|
||||
err = tcp_client->get_partial_data((uint8_t *)&size, 4, read);
|
||||
if (err != OK || read != 4) {
|
||||
_disconnect_with_error("Remote debugger: Connection lost while reading packet size.");
|
||||
return;
|
||||
}
|
||||
if (size > (uint32_t)in_buf.size()) {
|
||||
_disconnect_with_error(vformat("Remote debugger: Packet too large (%s > %s bytes). Disconnecting.", String::num_uint64(size), String::num_int64(in_buf.size())));
|
||||
return;
|
||||
}
|
||||
Error err = tcp_client->get_partial_data((uint8_t *)&size, 4, read);
|
||||
ERR_CONTINUE(read != 4 || err != OK || size > (uint32_t)in_buf.size());
|
||||
in_left = size;
|
||||
in_pos = 0;
|
||||
}
|
||||
int read = 0;
|
||||
err = tcp_client->get_partial_data(buf + in_pos, in_left, read);
|
||||
if (err != OK || read == 0) {
|
||||
_disconnect_with_error("Remote debugger: Connection lost while reading packet payload.");
|
||||
return;
|
||||
}
|
||||
tcp_client->get_partial_data(buf + in_pos, in_left, read);
|
||||
in_left -= read;
|
||||
in_pos += read;
|
||||
if (in_left == 0) {
|
||||
Variant var;
|
||||
err = decode_variant(var, buf, in_pos, &read);
|
||||
Error err = decode_variant(var, buf, in_pos, &read);
|
||||
ERR_CONTINUE(read != in_pos || err != OK);
|
||||
ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
|
||||
MutexLock lock(mutex);
|
||||
|
|
@ -223,7 +211,7 @@ void RemoteDebuggerPeerTCP::_poll() {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<RemoteDebuggerPeer> RemoteDebuggerPeerTCP::create_tcp(const String &p_uri) {
|
||||
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create_tcp(const String &p_uri) {
|
||||
ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
|
||||
|
||||
String debug_host = p_uri.replace("tcp://", "");
|
||||
|
|
@ -249,7 +237,7 @@ Ref<RemoteDebuggerPeer> RemoteDebuggerPeerTCP::create_tcp(const String &p_uri) {
|
|||
return memnew(RemoteDebuggerPeerTCP(stream));
|
||||
}
|
||||
|
||||
Ref<RemoteDebuggerPeer> RemoteDebuggerPeerTCP::create_unix(const String &p_uri) {
|
||||
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create_unix(const String &p_uri) {
|
||||
ERR_FAIL_COND_V(!p_uri.begins_with("unix://"), nullptr);
|
||||
|
||||
String debug_path = p_uri.replace("unix://", "");
|
||||
|
|
@ -264,8 +252,3 @@ Ref<RemoteDebuggerPeer> RemoteDebuggerPeerTCP::create_unix(const String &p_uri)
|
|||
RemoteDebuggerPeer::RemoteDebuggerPeer() {
|
||||
max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::_disconnect_with_error(const String &p_reason) {
|
||||
ERR_PRINT(p_reason);
|
||||
tcp_client->disconnect_from_host();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,12 +79,11 @@ private:
|
|||
void _poll();
|
||||
void _write_out();
|
||||
void _read_in();
|
||||
void _disconnect_with_error(const String &p_reason);
|
||||
static Error _try_connect(Ref<StreamPeerSocket> p_stream);
|
||||
|
||||
public:
|
||||
static Ref<RemoteDebuggerPeer> create_tcp(const String &p_uri);
|
||||
static Ref<RemoteDebuggerPeer> create_unix(const String &p_uri);
|
||||
static RemoteDebuggerPeer *create_tcp(const String &p_uri);
|
||||
static RemoteDebuggerPeer *create_unix(const String &p_uri);
|
||||
|
||||
bool is_peer_connected() override;
|
||||
int get_max_message_size() const override;
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@
|
|||
|
||||
#include "doc_data.h"
|
||||
|
||||
#include "core/object/method_info.h"
|
||||
#include "core/object/property_info.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
String DocData::get_default_value_string(const Variant &p_value) {
|
||||
const Variant::Type type = p_value.get_type();
|
||||
|
|
|
|||
|
|
@ -698,7 +698,6 @@ public:
|
|||
struct ClassDoc {
|
||||
String name;
|
||||
String inherits;
|
||||
String api_type;
|
||||
String brief_description;
|
||||
String description;
|
||||
String keywords;
|
||||
|
|
@ -732,10 +731,6 @@ public:
|
|||
doc.inherits = p_dict["inherits"];
|
||||
}
|
||||
|
||||
if (p_dict.has("api_type")) {
|
||||
doc.api_type = p_dict["api_type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("brief_description")) {
|
||||
doc.brief_description = p_dict["brief_description"];
|
||||
}
|
||||
|
|
@ -869,10 +864,6 @@ public:
|
|||
dict["inherits"] = p_doc.inherits;
|
||||
}
|
||||
|
||||
if (!p_doc.api_type.is_empty()) {
|
||||
dict["api_type"] = p_doc.api_type;
|
||||
}
|
||||
|
||||
if (!p_doc.brief_description.is_empty()) {
|
||||
dict["brief_description"] = p_doc.brief_description;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@ from misc.utility.scons_hints import *
|
|||
|
||||
Import("env")
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
||||
env_error = env.Clone()
|
||||
|
||||
env_error.add_source_files(env.core_sources, "*.cpp")
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "error_macros.h"
|
||||
|
||||
#include "core/core_globals.h"
|
||||
#include "core/io/logger.h"
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/object/script_language.h"
|
||||
|
|
@ -107,12 +106,6 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
|
|||
|
||||
// Main error printing function.
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
if (!CoreGlobals::print_ready) {
|
||||
const char *err_details = (p_message && *p_message) ? p_message : p_error;
|
||||
_err_print_fallback(p_function, p_file, p_line, err_details, p_type, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_printing_error) {
|
||||
// Fallback if we're already printing an error, to prevent infinite recursion.
|
||||
const char *err_details = (p_message && *p_message) ? p_message : p_error;
|
||||
|
|
@ -147,13 +140,7 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
|
|||
// but we don't want to make it noisy by printing lots of file & line info (because it's already
|
||||
// been printing by a preceding _err_print_error).
|
||||
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type) {
|
||||
const CharString err_details_str = p_error.utf8();
|
||||
const char *err_details = err_details_str.get_data();
|
||||
|
||||
if (!CoreGlobals::print_ready) {
|
||||
_err_print_fallback(nullptr, nullptr, 0, err_details, p_type, false);
|
||||
return;
|
||||
}
|
||||
const char *err_details = p_error.utf8().get_data();
|
||||
|
||||
if (is_printing_error) {
|
||||
// Fallback if we're already printing an error, to prevent infinite recursion.
|
||||
|
|
|
|||
|
|
@ -19,4 +19,6 @@ env.CommandNoCache(
|
|||
env.Run(make_interface_header.run),
|
||||
)
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
||||
env_extension = env.Clone()
|
||||
|
||||
env_extension.add_source_files(env.core_sources, "*.cpp")
|
||||
|
|
|
|||
|
|
@ -32,10 +32,11 @@
|
|||
#include "gdextension.compat.inc"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/extension/gdextension_library_loader.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/method_bind.h"
|
||||
#include "gdextension_library_loader.h"
|
||||
#include "gdextension_manager.h"
|
||||
|
||||
extern void gdextension_setup_interface();
|
||||
extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name);
|
||||
|
|
@ -240,7 +241,7 @@ public:
|
|||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
|
||||
const GDExtensionClassCreationInfo6 class_info6 = {
|
||||
const GDExtensionClassCreationInfo5 class_info5 = {
|
||||
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
|
||||
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
|
||||
true, // GDExtensionBool is_exposed;
|
||||
|
|
@ -257,30 +258,29 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
|
|||
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
|
||||
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
|
||||
p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
|
||||
nullptr, // GDExtensionClassCreateInstance3 create_instance_func; /* this one is mandatory */
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
nullptr, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
nullptr, // GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
|
||||
const ClassCreationDeprecatedInfo legacy = {
|
||||
false, // bool legacy_unexposed_class;
|
||||
false,
|
||||
p_extension_funcs->notification_func, // GDExtensionClassNotification notification_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance2_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr,
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info6, &legacy);
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info5, &legacy);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs) {
|
||||
const GDExtensionClassCreationInfo6 class_info6 = {
|
||||
const GDExtensionClassCreationInfo5 class_info5 = {
|
||||
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
|
||||
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
|
||||
p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
|
||||
|
|
@ -297,12 +297,12 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
|
|||
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
|
||||
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
|
||||
p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
|
||||
nullptr, // GDExtensionClassCreateInstance3 create_instance_func; /* this one is mandatory */
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
nullptr, // GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
|
||||
|
|
@ -311,16 +311,15 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
|
|||
nullptr, // GDExtensionClassNotification notification_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance2_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info6, &legacy);
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info5, &legacy);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs) {
|
||||
const GDExtensionClassCreationInfo6 class_info6 = {
|
||||
const GDExtensionClassCreationInfo5 class_info5 = {
|
||||
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
|
||||
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
|
||||
p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
|
||||
|
|
@ -329,7 +328,7 @@ void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_librar
|
|||
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
|
||||
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
|
||||
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList2 free_property_list_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
|
||||
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
|
||||
p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func;
|
||||
|
|
@ -337,12 +336,12 @@ void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_librar
|
|||
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
|
||||
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
|
||||
p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
|
||||
nullptr, // GDExtensionClassCreateInstance3 create_instance_func; /* this one is mandatory */
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
nullptr, // GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
|
||||
|
|
@ -350,101 +349,34 @@ void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_librar
|
|||
!p_extension_funcs->is_exposed, // bool legacy_unexposed_class;
|
||||
nullptr, // GDExtensionClassNotification notification_func;
|
||||
nullptr, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance2_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance2 create_instance_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info6, &legacy);
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info5, &legacy);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class4(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs) {
|
||||
const GDExtensionClassCreationInfo6 class_info6 = {
|
||||
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
|
||||
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
|
||||
p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
|
||||
p_extension_funcs->is_runtime, // GDExtensionBool is_runtime;
|
||||
p_extension_funcs->icon_path, // GDExtensionConstStringPtr icon_path;
|
||||
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
|
||||
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
|
||||
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList2 free_property_list_func;
|
||||
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
|
||||
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
|
||||
p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func;
|
||||
p_extension_funcs->notification_func, // GDExtensionClassNotification2 notification_func;
|
||||
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
|
||||
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
|
||||
p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
|
||||
nullptr, // GDExtensionClassCreateInstance3 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
|
||||
GDExtensionClassCreationInfo5 class_info5 = *p_extension_funcs;
|
||||
const ClassCreationDeprecatedInfo legacy = {
|
||||
!p_extension_funcs->is_exposed, // bool legacy_unexposed_class;
|
||||
nullptr, // GDExtensionClassNotification notification_func;
|
||||
nullptr, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
nullptr, // GDExtensionClassCreateInstance create_instance_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance2 create_instance2_func;
|
||||
nullptr, // GDExtensionClassGetRID get_rid_func;
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func;
|
||||
nullptr, // GDExtensionClassGetRID get_rid;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info6, &legacy);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class5(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs) {
|
||||
const GDExtensionClassCreationInfo6 class_info6 = {
|
||||
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
|
||||
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
|
||||
p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
|
||||
p_extension_funcs->is_runtime, // GDExtensionBool is_runtime;
|
||||
p_extension_funcs->icon_path, // GDExtensionConstStringPtr icon_path;
|
||||
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
|
||||
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
|
||||
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList2 free_property_list_func;
|
||||
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
|
||||
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
|
||||
p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func;
|
||||
p_extension_funcs->notification_func, // GDExtensionClassNotification2 notification_func;
|
||||
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
|
||||
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
|
||||
p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
|
||||
nullptr, // GDExtensionClassCreateInstance3 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
|
||||
const ClassCreationDeprecatedInfo legacy = {
|
||||
false, // bool legacy_unexposed_class;
|
||||
nullptr, // GDExtensionClassNotification notification_func;
|
||||
nullptr, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
nullptr, // GDExtensionClassCreateInstance create_instance_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance2 create_instance2_func;
|
||||
nullptr, // GDExtensionClassGetRID get_rid_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info6, &legacy);
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info5, &legacy);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
void GDExtension::_register_extension_class6(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo6 *p_extension_funcs) {
|
||||
void GDExtension::_register_extension_class5(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs) {
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, p_extension_funcs);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo6 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs) {
|
||||
void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs) {
|
||||
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
|
||||
|
||||
StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
|
||||
|
|
@ -530,7 +462,6 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
|
|||
extension->gdextension.notification = p_deprecated_funcs->notification_func;
|
||||
extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func;
|
||||
extension->gdextension.create_instance = p_deprecated_funcs->create_instance_func;
|
||||
extension->gdextension.create_instance2 = p_deprecated_funcs->create_instance2_func;
|
||||
extension->gdextension.get_rid = p_deprecated_funcs->get_rid_func;
|
||||
extension->gdextension.get_virtual = p_deprecated_funcs->get_virtual_func;
|
||||
extension->gdextension.get_virtual_call_data = p_deprecated_funcs->get_virtual_call_data_func;
|
||||
|
|
@ -541,7 +472,7 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
|
|||
extension->gdextension.reference = p_extension_funcs->reference_func;
|
||||
extension->gdextension.unreference = p_extension_funcs->unreference_func;
|
||||
extension->gdextension.class_userdata = p_extension_funcs->class_userdata;
|
||||
extension->gdextension.create_instance3 = p_extension_funcs->create_instance_func;
|
||||
extension->gdextension.create_instance2 = p_extension_funcs->create_instance_func;
|
||||
extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
|
||||
extension->gdextension.recreate_instance = p_extension_funcs->recreate_instance_func;
|
||||
extension->gdextension.get_virtual2 = p_extension_funcs->get_virtual_func;
|
||||
|
|
@ -894,9 +825,8 @@ void GDExtension::initialize_gdextensions() {
|
|||
register_interface_function("classdb_register_extension_class2", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class2);
|
||||
register_interface_function("classdb_register_extension_class3", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class3);
|
||||
register_interface_function("classdb_register_extension_class4", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class4);
|
||||
register_interface_function("classdb_register_extension_class5", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class5);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
register_interface_function("classdb_register_extension_class6", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class6);
|
||||
register_interface_function("classdb_register_extension_class5", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class5);
|
||||
register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
|
||||
register_interface_function("classdb_register_extension_class_virtual_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_virtual_method);
|
||||
register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
|
||||
|
|
@ -915,7 +845,68 @@ void GDExtension::finalize_gdextensions() {
|
|||
gdextension_interface_functions.clear();
|
||||
}
|
||||
|
||||
Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension) {
|
||||
ERR_FAIL_COND_V_MSG(p_extension.is_valid() && p_extension->is_library_open(), ERR_ALREADY_IN_USE, "Cannot load GDExtension resource into already opened library.");
|
||||
|
||||
GDExtensionManager *extension_manager = GDExtensionManager::get_singleton();
|
||||
|
||||
GDExtensionManager::LoadStatus status = extension_manager->load_extension(p_path);
|
||||
if (status != GDExtensionManager::LOAD_STATUS_OK && status != GDExtensionManager::LOAD_STATUS_ALREADY_LOADED) {
|
||||
// Errors already logged in load_extension().
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
p_extension = extension_manager->get_extension(p_path);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
// We can't have two GDExtension resource object representing the same library, because
|
||||
// loading (or unloading) a GDExtension affects global data. So, we need reuse the same
|
||||
// object if one has already been loaded (even if caching is disabled at the resource
|
||||
// loader level).
|
||||
GDExtensionManager *manager = GDExtensionManager::get_singleton();
|
||||
if (manager->is_extension_loaded(p_path)) {
|
||||
return manager->get_extension(p_path);
|
||||
}
|
||||
|
||||
Ref<GDExtension> lib;
|
||||
Error err = load_gdextension_resource(p_path, lib);
|
||||
if (err != OK && r_error) {
|
||||
// Errors already logged in load_gdextension_resource().
|
||||
*r_error = err;
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
void GDExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("gdextension");
|
||||
}
|
||||
|
||||
bool GDExtensionResourceLoader::handles_type(const String &p_type) const {
|
||||
return p_type == "GDExtension";
|
||||
}
|
||||
|
||||
String GDExtensionResourceLoader::get_resource_type(const String &p_path) const {
|
||||
if (p_path.has_extension("gdextension")) {
|
||||
return "GDExtension";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void GDExtensionResourceLoader::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
|
||||
Ref<GDExtension> gdext = ResourceLoader::load(p_path);
|
||||
if (gdext.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const StringName class_name : gdext->get_classes_used()) {
|
||||
if (ClassDB::class_exists(class_name)) {
|
||||
r_classes->insert(class_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GDExtension::has_library_changed() const {
|
||||
return loader->has_library_changed();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
|
||||
#include "core/extension/gdextension_interface.gen.h"
|
||||
#include "core/extension/gdextension_loader.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class GDExtensionMethodBind;
|
||||
|
||||
|
|
@ -69,7 +70,6 @@ class GDExtension : public Resource {
|
|||
GDExtensionClassNotification notification_func = nullptr;
|
||||
GDExtensionClassFreePropertyList free_property_list_func = nullptr;
|
||||
GDExtensionClassCreateInstance create_instance_func = nullptr;
|
||||
GDExtensionClassCreateInstance2 create_instance2_func = nullptr;
|
||||
GDExtensionClassGetRID get_rid_func = nullptr;
|
||||
GDExtensionClassGetVirtual get_virtual_func = nullptr;
|
||||
GDExtensionClassGetVirtualCallData get_virtual_call_data_func = nullptr;
|
||||
|
|
@ -81,10 +81,9 @@ class GDExtension : public Resource {
|
|||
static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
|
||||
static void _register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
|
||||
static void _register_extension_class4(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
|
||||
static void _register_extension_class5(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
static void _register_extension_class6(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo6 *p_extension_funcs);
|
||||
static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo6 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr);
|
||||
static void _register_extension_class5(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs);
|
||||
static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr);
|
||||
static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
|
||||
static void _register_extension_class_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info);
|
||||
static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
|
||||
|
|
@ -182,6 +181,21 @@ public:
|
|||
|
||||
VARIANT_ENUM_CAST(GDExtension::InitializationLevel)
|
||||
|
||||
class GDExtensionResourceLoader : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(GDExtensionResourceLoader, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
|
||||
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
|
||||
#endif // TOOLS_ENABLED
|
||||
};
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
class GDExtensionEditorPlugins {
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "gdextension_function_loader.h"
|
||||
|
||||
#include "core/extension/gdextension.h"
|
||||
#include "gdextension.h"
|
||||
|
||||
Error GDExtensionFunctionLoader::open_library(const String &p_path) {
|
||||
ERR_FAIL_COND_V_MSG(!p_path.begins_with("libgodot://"), ERR_FILE_NOT_FOUND, "Function based GDExtensions should have a path starting with libgodot://");
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class CallableCustomExtension : public CallableCustom {
|
|||
const CallableCustomExtension *b = static_cast<const CallableCustomExtension *>(p_b);
|
||||
|
||||
if (a->call_func != b->call_func) {
|
||||
return (uintptr_t)a->call_func < (uintptr_t)b->call_func;
|
||||
return a->call_func < b->call_func;
|
||||
}
|
||||
return a->userdata < b->userdata;
|
||||
}
|
||||
|
|
@ -547,11 +547,6 @@ static void gdextension_variant_get_type_name(GDExtensionVariantType p_type, GDE
|
|||
memnew_placement(r_ret, String(name));
|
||||
}
|
||||
|
||||
static GDExtensionVariantType gdextension_variant_get_type_by_name(GDExtensionConstStringPtr p_type) {
|
||||
const String *type = (const String *)p_type;
|
||||
return static_cast<GDExtensionVariantType>(Variant::get_type_by_name(*type));
|
||||
}
|
||||
|
||||
static GDExtensionBool gdextension_variant_can_convert(GDExtensionVariantType p_from, GDExtensionVariantType p_to) {
|
||||
return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to);
|
||||
}
|
||||
|
|
@ -1400,7 +1395,6 @@ static GDExtensionBool gdextension_object_get_class_name(GDExtensionConstObjectP
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
static GDExtensionObjectPtr gdextension_object_cast_to(GDExtensionConstObjectPtr p_object, void *p_class_tag) {
|
||||
if (!p_object) {
|
||||
return nullptr;
|
||||
|
|
@ -1409,7 +1403,6 @@ static GDExtensionObjectPtr gdextension_object_cast_to(GDExtensionConstObjectPtr
|
|||
|
||||
return o->is_class_ptr(p_class_tag) ? (GDExtensionObjectPtr)o : (GDExtensionObjectPtr) nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static GDObjectInstanceID gdextension_object_get_instance_id(GDExtensionConstObjectPtr p_object) {
|
||||
const Object *o = (const Object *)p_object;
|
||||
|
|
@ -1659,25 +1652,18 @@ static GDExtensionObjectPtr gdextension_classdb_construct_object(GDExtensionCons
|
|||
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
|
||||
return (GDExtensionObjectPtr)ClassDB::instantiate_no_placeholders(classname);
|
||||
}
|
||||
#endif
|
||||
|
||||
static GDExtensionObjectPtr gdextension_classdb_construct_object2(GDExtensionConstStringNamePtr p_classname) {
|
||||
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
|
||||
return (GDExtensionObjectPtr)ClassDB::instantiate_without_postinitialization(classname);
|
||||
}
|
||||
#endif
|
||||
|
||||
static GDExtensionObjectPtr gdextension_classdb_construct_object3(GDExtensionConstStringNamePtr p_classname) {
|
||||
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
|
||||
return (GDExtensionObjectPtr)ClassDB::instantiate_without_postinitialization_with_refcount(classname);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
static void *gdextension_classdb_get_class_tag(GDExtensionConstStringNamePtr p_classname) {
|
||||
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
|
||||
ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(classname);
|
||||
return class_info ? class_info->class_ptr : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gdextension_editor_add_plugin(GDExtensionConstStringNamePtr p_classname) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
@ -1757,7 +1743,6 @@ void gdextension_setup_interface() {
|
|||
REGISTER_INTERFACE_FUNC(variant_has_key);
|
||||
REGISTER_INTERFACE_FUNC(variant_get_object_instance_id);
|
||||
REGISTER_INTERFACE_FUNC(variant_get_type_name);
|
||||
REGISTER_INTERFACE_FUNC(variant_get_type_by_name);
|
||||
REGISTER_INTERFACE_FUNC(variant_can_convert);
|
||||
REGISTER_INTERFACE_FUNC(variant_can_convert_strict);
|
||||
REGISTER_INTERFACE_FUNC(get_variant_from_type_constructor);
|
||||
|
|
@ -1848,9 +1833,7 @@ void gdextension_setup_interface() {
|
|||
REGISTER_INTERFACE_FUNC(object_free_instance_binding);
|
||||
REGISTER_INTERFACE_FUNC(object_set_instance);
|
||||
REGISTER_INTERFACE_FUNC(object_get_class_name);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(object_cast_to);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(object_get_instance_from_id);
|
||||
REGISTER_INTERFACE_FUNC(object_get_instance_id);
|
||||
REGISTER_INTERFACE_FUNC(object_has_script_method);
|
||||
|
|
@ -1873,13 +1856,10 @@ void gdextension_setup_interface() {
|
|||
REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(classdb_construct_object);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(classdb_construct_object2);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(classdb_construct_object3);
|
||||
REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
REGISTER_INTERFACE_FUNC(editor_add_plugin);
|
||||
REGISTER_INTERFACE_FUNC(editor_remove_plugin);
|
||||
REGISTER_INTERFACE_FUNC(editor_help_load_xml_from_utf8_chars);
|
||||
|
|
|
|||
|
|
@ -986,11 +986,7 @@
|
|||
"name": "p_list",
|
||||
"type": "const GDExtensionPropertyInfo*"
|
||||
}
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.3",
|
||||
"replace_with": "GDExtensionClassFreePropertyList2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassFreePropertyList2",
|
||||
|
|
@ -1168,15 +1164,7 @@
|
|||
"name": "p_class_userdata",
|
||||
"type": "void*"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Called to construct an instance of the class.",
|
||||
"For classes descending from RefCounted, the reference count should be zero."
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "GDExtensionClassCreateInstance3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassCreateInstance2",
|
||||
|
|
@ -1193,35 +1181,6 @@
|
|||
"name": "p_notify_postinitialize",
|
||||
"type": "GDExtensionBool"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Called to construct an instance of the class.",
|
||||
"For classes descending from RefCounted, the reference count should be zero."
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"replace_with": "GDExtensionClassCreateInstance3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassCreateInstance3",
|
||||
"kind": "function",
|
||||
"return_value": {
|
||||
"type": "GDExtensionObjectPtr"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "p_class_userdata",
|
||||
"type": "void*"
|
||||
},
|
||||
{
|
||||
"name": "p_notify_postinitialize",
|
||||
"type": "GDExtensionBool"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Called to construct an instance of the class.",
|
||||
"For classes descending from RefCounted, the reference count should already be incremented by 1."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1270,11 +1229,7 @@
|
|||
"name": "p_name",
|
||||
"type": "GDExtensionConstStringNamePtr"
|
||||
}
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "GDExtensionClassGetVirtual2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassGetVirtual2",
|
||||
|
|
@ -1312,11 +1267,7 @@
|
|||
"name": "p_name",
|
||||
"type": "GDExtensionConstStringNamePtr"
|
||||
}
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "GDExtensionClassGetVirtualCallData2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassGetVirtualCallData2",
|
||||
|
|
@ -1421,7 +1372,7 @@
|
|||
"name": "create_instance_func",
|
||||
"type": "GDExtensionClassCreateInstance",
|
||||
"description": [
|
||||
"Class constructor. Required unless the class is virtual or abstract."
|
||||
"(Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1452,7 +1403,7 @@
|
|||
],
|
||||
"deprecated": {
|
||||
"since": "4.2",
|
||||
"replace_with": "GDExtensionClassCreationInfo6"
|
||||
"replace_with": "GDExtensionClassCreationInfo4"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1519,7 +1470,7 @@
|
|||
"name": "create_instance_func",
|
||||
"type": "GDExtensionClassCreateInstance",
|
||||
"description": [
|
||||
"Class constructor. Required unless the class is virtual or abstract."
|
||||
"(Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1573,7 +1524,7 @@
|
|||
],
|
||||
"deprecated": {
|
||||
"since": "4.3",
|
||||
"replace_with": "GDExtensionClassCreationInfo6"
|
||||
"replace_with": "GDExtensionClassCreationInfo4"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1644,7 +1595,7 @@
|
|||
"name": "create_instance_func",
|
||||
"type": "GDExtensionClassCreateInstance",
|
||||
"description": [
|
||||
"Class constructor. Required unless the class is virtual or abstract."
|
||||
"(Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1698,7 +1649,7 @@
|
|||
],
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "GDExtensionClassCreationInfo6"
|
||||
"replace_with": "GDExtensionClassCreationInfo4"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1773,141 +1724,7 @@
|
|||
"name": "create_instance_func",
|
||||
"type": "GDExtensionClassCreateInstance2",
|
||||
"description": [
|
||||
"Class constructor. Required unless the class is virtual or abstract."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "free_instance_func",
|
||||
"type": "GDExtensionClassFreeInstance",
|
||||
"description": [
|
||||
"Destructor; mandatory."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "recreate_instance_func",
|
||||
"type": "GDExtensionClassRecreateInstance"
|
||||
},
|
||||
{
|
||||
"name": "get_virtual_func",
|
||||
"type": "GDExtensionClassGetVirtual2",
|
||||
"description": [
|
||||
"Queries a virtual function by name and returns a callback to invoke the requested virtual function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get_virtual_call_data_func",
|
||||
"type": "GDExtensionClassGetVirtualCallData2",
|
||||
"description": [
|
||||
"Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that",
|
||||
"need or benefit from extra data when calling virtual functions.",
|
||||
"Returns user data that will be passed to `call_virtual_with_data_func`.",
|
||||
"Returning `NULL` from this function signals to Godot that the virtual function is not overridden.",
|
||||
"Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.",
|
||||
"You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "call_virtual_with_data_func",
|
||||
"type": "GDExtensionClassCallVirtualWithData",
|
||||
"description": [
|
||||
"Used to call virtual functions when `get_virtual_call_data_func` is not null."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "class_userdata",
|
||||
"type": "void*",
|
||||
"description": [
|
||||
"Per-class user data, later accessible in instance bindings."
|
||||
]
|
||||
}
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.5",
|
||||
"replace_with": "GDExtensionClassCreationInfo6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassCreationInfo5",
|
||||
"kind": "alias",
|
||||
"type": "GDExtensionClassCreationInfo4",
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"replace_with": "GDExtensionClassCreationInfo6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassCreationInfo6",
|
||||
"kind": "struct",
|
||||
"members": [
|
||||
{
|
||||
"name": "is_virtual",
|
||||
"type": "GDExtensionBool"
|
||||
},
|
||||
{
|
||||
"name": "is_abstract",
|
||||
"type": "GDExtensionBool"
|
||||
},
|
||||
{
|
||||
"name": "is_exposed",
|
||||
"type": "GDExtensionBool"
|
||||
},
|
||||
{
|
||||
"name": "is_runtime",
|
||||
"type": "GDExtensionBool"
|
||||
},
|
||||
{
|
||||
"name": "icon_path",
|
||||
"type": "GDExtensionConstStringPtr"
|
||||
},
|
||||
{
|
||||
"name": "set_func",
|
||||
"type": "GDExtensionClassSet"
|
||||
},
|
||||
{
|
||||
"name": "get_func",
|
||||
"type": "GDExtensionClassGet"
|
||||
},
|
||||
{
|
||||
"name": "get_property_list_func",
|
||||
"type": "GDExtensionClassGetPropertyList"
|
||||
},
|
||||
{
|
||||
"name": "free_property_list_func",
|
||||
"type": "GDExtensionClassFreePropertyList2"
|
||||
},
|
||||
{
|
||||
"name": "property_can_revert_func",
|
||||
"type": "GDExtensionClassPropertyCanRevert"
|
||||
},
|
||||
{
|
||||
"name": "property_get_revert_func",
|
||||
"type": "GDExtensionClassPropertyGetRevert"
|
||||
},
|
||||
{
|
||||
"name": "validate_property_func",
|
||||
"type": "GDExtensionClassValidateProperty"
|
||||
},
|
||||
{
|
||||
"name": "notification_func",
|
||||
"type": "GDExtensionClassNotification2"
|
||||
},
|
||||
{
|
||||
"name": "to_string_func",
|
||||
"type": "GDExtensionClassToString"
|
||||
},
|
||||
{
|
||||
"name": "reference_func",
|
||||
"type": "GDExtensionClassReference"
|
||||
},
|
||||
{
|
||||
"name": "unreference_func",
|
||||
"type": "GDExtensionClassUnreference"
|
||||
},
|
||||
{
|
||||
"name": "create_instance_func",
|
||||
"type": "GDExtensionClassCreateInstance3",
|
||||
"description": [
|
||||
"Class constructor. Required unless the class is virtual or abstract."
|
||||
"(Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1956,6 +1773,11 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassCreationInfo5",
|
||||
"kind": "alias",
|
||||
"type": "GDExtensionClassCreationInfo4"
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionClassLibraryPtr",
|
||||
"kind": "handle"
|
||||
|
|
@ -3553,11 +3375,7 @@
|
|||
"name": "string",
|
||||
"type": "const char*"
|
||||
}
|
||||
],
|
||||
"deprecated": {
|
||||
"since": "4.5",
|
||||
"replace_with": "GDExtensionGodotVersion2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GDExtensionGodotVersion2",
|
||||
|
|
@ -5160,28 +4978,6 @@
|
|||
],
|
||||
"since": "4.1"
|
||||
},
|
||||
{
|
||||
"name": "variant_get_type_by_name",
|
||||
"return_value": {
|
||||
"type": "GDExtensionVariantType",
|
||||
"description": [
|
||||
"The variant type for the given name; otherwise VARIANT_MAX if name is invalid."
|
||||
]
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "p_type_name",
|
||||
"type": "GDExtensionConstStringPtr",
|
||||
"description": [
|
||||
"The variant type name."
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Gets the Variant type by name."
|
||||
],
|
||||
"since": "4.7"
|
||||
},
|
||||
{
|
||||
"name": "variant_can_convert",
|
||||
"return_value": {
|
||||
|
|
@ -7950,11 +7746,7 @@
|
|||
"description": [
|
||||
"Casts an Object to a different type."
|
||||
],
|
||||
"since": "4.1",
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"message": "Use the `is_class` method on `Object` to check if an object can be cast instead. If true, the previous pointer can be reinterpreted as a pointer to the target type."
|
||||
}
|
||||
"since": "4.1"
|
||||
},
|
||||
{
|
||||
"name": "object_get_instance_from_id",
|
||||
|
|
@ -8450,7 +8242,7 @@
|
|||
"since": "4.1",
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "classdb_construct_object3"
|
||||
"replace_with": "classdb_construct_object2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -8476,37 +8268,7 @@
|
|||
"",
|
||||
"\"NOTIFICATION_POSTINITIALIZE\" must be sent after construction."
|
||||
],
|
||||
"since": "4.4",
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"replace_with": "classdb_construct_object3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "classdb_construct_object3",
|
||||
"return_value": {
|
||||
"type": "GDExtensionObjectPtr",
|
||||
"description": [
|
||||
"A pointer to the newly created Object."
|
||||
]
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "p_classname",
|
||||
"type": "GDExtensionConstStringNamePtr",
|
||||
"description": [
|
||||
"A pointer to a StringName with the class name."
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Constructs an Object of the requested class.",
|
||||
"The passed class must be a built-in godot class, or an already-registered extension class. In both cases, object_set_instance() should be called to fully initialize the object.",
|
||||
"If the type is a subtype of RefCounted, it already has a refcount of 1. The caller must take ownership the refcount and is responsible for decrementing it again when the object is no longer needed.",
|
||||
"",
|
||||
"\"NOTIFICATION_POSTINITIALIZE\" must be sent after construction."
|
||||
],
|
||||
"since": "4.7"
|
||||
"since": "4.4"
|
||||
},
|
||||
{
|
||||
"name": "classdb_get_method_bind",
|
||||
|
|
@ -8564,11 +8326,7 @@
|
|||
"description": [
|
||||
"Gets a pointer uniquely identifying the given built-in class in the ClassDB."
|
||||
],
|
||||
"since": "4.1",
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"message": "No longer needed. Use the `is_class` method on `Object` instead."
|
||||
}
|
||||
"since": "4.1"
|
||||
},
|
||||
{
|
||||
"name": "classdb_register_extension_class",
|
||||
|
|
@ -8609,7 +8367,7 @@
|
|||
"since": "4.1",
|
||||
"deprecated": {
|
||||
"since": "4.2",
|
||||
"replace_with": "classdb_register_extension_class6"
|
||||
"replace_with": "classdb_register_extension_class5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -8651,7 +8409,7 @@
|
|||
"since": "4.2",
|
||||
"deprecated": {
|
||||
"since": "4.3",
|
||||
"replace_with": "classdb_register_extension_class6"
|
||||
"replace_with": "classdb_register_extension_class5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -8693,7 +8451,7 @@
|
|||
"since": "4.3",
|
||||
"deprecated": {
|
||||
"since": "4.4",
|
||||
"replace_with": "classdb_register_extension_class6"
|
||||
"replace_with": "classdb_register_extension_class5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -8735,7 +8493,7 @@
|
|||
"since": "4.4",
|
||||
"deprecated": {
|
||||
"since": "4.5",
|
||||
"replace_with": "classdb_register_extension_class6"
|
||||
"replace_with": "classdb_register_extension_class5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -8774,49 +8532,7 @@
|
|||
"Registers an extension class in the ClassDB.",
|
||||
"Provided struct can be safely freed once the function returns."
|
||||
],
|
||||
"since": "4.5",
|
||||
"deprecated": {
|
||||
"since": "4.7",
|
||||
"replace_with": "classdb_register_extension_class6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "classdb_register_extension_class6",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "p_library",
|
||||
"type": "GDExtensionClassLibraryPtr",
|
||||
"description": [
|
||||
"A pointer the library received by the GDExtension's entry point function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "p_class_name",
|
||||
"type": "GDExtensionConstStringNamePtr",
|
||||
"description": [
|
||||
"A pointer to a StringName with the class name."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "p_parent_class_name",
|
||||
"type": "GDExtensionConstStringNamePtr",
|
||||
"description": [
|
||||
"A pointer to a StringName with the parent class name."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "p_extension_funcs",
|
||||
"type": "const GDExtensionClassCreationInfo6*",
|
||||
"description": [
|
||||
"A pointer to a GDExtensionClassCreationInfo6 struct."
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Registers an extension class in the ClassDB.",
|
||||
"Provided struct can be safely freed once the function returns."
|
||||
],
|
||||
"since": "4.7"
|
||||
"since": "4.5"
|
||||
},
|
||||
{
|
||||
"name": "classdb_register_extension_class_method",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
|
||||
#include "gdextension_interface_header_generator.h"
|
||||
|
||||
#include "core/extension/gdextension_interface_dump.gen.h"
|
||||
#include "core/io/json.h"
|
||||
#include "gdextension_interface_dump.gen.h"
|
||||
|
||||
static const char *FILE_HEADER =
|
||||
"/**************************************************************************/\n"
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@
|
|||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/extension/gdextension.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/version.h"
|
||||
#include "gdextension.h"
|
||||
|
||||
Vector<SharedObject> GDExtensionLibraryLoader::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) {
|
||||
Vector<SharedObject> dependencies_shared_objects;
|
||||
|
|
@ -200,10 +200,7 @@ Error GDExtensionLibraryLoader::open_library(const String &p_path) {
|
|||
// Apple has a complex lookup system which goes beyond looking up the filename, so we try that first.
|
||||
err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data);
|
||||
if (err != OK) {
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
err = OS::get_singleton()->open_dynamic_library(String(), library, &data);
|
||||
#endif
|
||||
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "core/extension/gdextension_loader.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/os/shared_object.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
class GDExtensionLibraryLoader : public GDExtensionLoader {
|
||||
GDSOFTCLASS(GDExtensionLibraryLoader, GDExtensionLoader);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_resource_format.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gdextension_resource_format.h"
|
||||
|
||||
#include "core/extension/gdextension_manager.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
// We can't have two GDExtension resource object representing the same library, because
|
||||
// loading (or unloading) a GDExtension affects global data. So, we need reuse the same
|
||||
// object if one has already been loaded (even if caching is disabled at the resource
|
||||
// loader level).
|
||||
GDExtensionManager *manager = GDExtensionManager::get_singleton();
|
||||
if (manager->is_extension_loaded(p_path)) {
|
||||
return manager->get_extension(p_path);
|
||||
}
|
||||
|
||||
Ref<GDExtension> lib;
|
||||
Error err = load_gdextension_resource(p_path, lib);
|
||||
if (err != OK && r_error) {
|
||||
// Errors already logged in load_gdextension_resource().
|
||||
*r_error = err;
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
void GDExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("gdextension");
|
||||
}
|
||||
|
||||
bool GDExtensionResourceLoader::handles_type(const String &p_type) const {
|
||||
return p_type == "GDExtension";
|
||||
}
|
||||
|
||||
String GDExtensionResourceLoader::get_resource_type(const String &p_path) const {
|
||||
if (p_path.has_extension("gdextension")) {
|
||||
return "GDExtension";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension) {
|
||||
ERR_FAIL_COND_V_MSG(p_extension.is_valid() && p_extension->is_library_open(), ERR_ALREADY_IN_USE, "Cannot load GDExtension resource into already opened library.");
|
||||
|
||||
GDExtensionManager *extension_manager = GDExtensionManager::get_singleton();
|
||||
|
||||
GDExtensionManager::LoadStatus status = extension_manager->load_extension(p_path);
|
||||
if (status != GDExtensionManager::LOAD_STATUS_OK && status != GDExtensionManager::LOAD_STATUS_ALREADY_LOADED) {
|
||||
// Errors already logged in load_extension().
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
p_extension = extension_manager->get_extension(p_path);
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void GDExtensionResourceLoader::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
|
||||
Ref<GDExtension> gdext = ResourceLoader::load(p_path);
|
||||
if (gdext.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const StringName class_name : gdext->get_classes_used()) {
|
||||
if (ClassDB::class_exists(class_name)) {
|
||||
r_classes->insert(class_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_resource_format.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/extension/gdextension.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
|
||||
class GDExtensionResourceLoader : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(GDExtensionResourceLoader, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
|
||||
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
|
||||
#endif // TOOLS_ENABLED
|
||||
};
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/extension/gdextension_interface.gen.h"
|
||||
#include "gdextension_interface.gen.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ def run(target, source, env):
|
|||
inline constexpr int _gdextension_interface_data_compressed_size = {len(buffer)};
|
||||
inline constexpr int _gdextension_interface_data_uncompressed_size = {decomp_size};
|
||||
inline constexpr unsigned char _gdextension_interface_data_compressed[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
|
||||
class GDExtensionInterfaceDump {{
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#include "core/os/thread.h"
|
||||
#endif
|
||||
|
||||
#include <thirdparty/gamepadmotionhelpers/GamepadMotion.hpp>
|
||||
#include "thirdparty/gamepadmotionhelpers/GamepadMotion.hpp"
|
||||
|
||||
#define STANDARD_GRAVITY 9.80665f
|
||||
|
||||
|
|
@ -179,10 +179,6 @@ void Input::_bind_methods() {
|
|||
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("get_joy_touchpad_finger_position", "device", "finger", "touchpad"), &Input::get_joy_touchpad_finger_position, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("get_joy_touchpad_finger_pressure", "device", "finger", "touchpad"), &Input::get_joy_touchpad_finger_pressure, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("get_joy_touchpad_fingers", "device", "touchpad"), &Input::get_joy_touchpad_fingers, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("get_joy_num_touchpads", "device"), &Input::get_joy_num_touchpads);
|
||||
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);
|
||||
|
|
@ -802,64 +798,6 @@ Vector3 Input::get_gyroscope() const {
|
|||
return gyroscope;
|
||||
}
|
||||
|
||||
Vector2 Input::get_joy_touchpad_finger_position(int p_device, int p_finger, int p_touchpad) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
const TouchpadInfo *touch = joy_touch.getptr(p_device);
|
||||
if (touch == nullptr) {
|
||||
return Vector2(-1, -1);
|
||||
}
|
||||
|
||||
uint16_t index = p_finger | (p_touchpad << 8);
|
||||
const TouchpadFingerInfo *finger_info = touch->finger_info.getptr(index);
|
||||
if (finger_info == nullptr) {
|
||||
return Vector2(-1, -1);
|
||||
}
|
||||
|
||||
return finger_info->position;
|
||||
}
|
||||
|
||||
float Input::get_joy_touchpad_finger_pressure(int p_device, int p_finger, int p_touchpad) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
const TouchpadInfo *touch = joy_touch.getptr(p_device);
|
||||
if (touch == nullptr) {
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
uint16_t index = p_finger | (p_touchpad << 8);
|
||||
const TouchpadFingerInfo *finger_info = touch->finger_info.getptr(index);
|
||||
if (finger_info == nullptr) {
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
return finger_info->pressure;
|
||||
}
|
||||
|
||||
PackedInt32Array Input::get_joy_touchpad_fingers(int p_device, int p_touchpad) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
const TouchpadInfo *touch = joy_touch.getptr(p_device);
|
||||
if (touch == nullptr) {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
PackedInt32Array result;
|
||||
for (const KeyValue<uint16_t, TouchpadFingerInfo> &index : touch->finger_info) {
|
||||
int touchpad = index.key >> 8;
|
||||
if (touchpad == p_touchpad) {
|
||||
result.append(index.key & 0xFF);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Input::get_joy_num_touchpads(int p_device) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
const TouchpadInfo *touch = joy_touch.getptr(p_device);
|
||||
if (touch == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return touch->num_touchpads;
|
||||
}
|
||||
|
||||
void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
|
||||
// This function does the final delivery of the input event to user land.
|
||||
// Regardless where the event came from originally, this has to happen on the main thread.
|
||||
|
|
@ -1682,9 +1620,6 @@ void Input::release_pressed_events() {
|
|||
|
||||
for (int device : get_connected_joypads()) {
|
||||
stop_joy_vibration(device);
|
||||
|
||||
TouchpadInfo &touch = joy_touch[device];
|
||||
touch.finger_info.clear();
|
||||
}
|
||||
} else {
|
||||
for (KeyValue<StringName, Input::ActionState> &E : action_states) {
|
||||
|
|
@ -1888,22 +1823,6 @@ void Input::joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, con
|
|||
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::joy_touchpad(int p_device, int p_touchpad, int p_finger, const Vector2 &p_position, float p_pressure, bool p_pressed) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (_should_ignore_joypad_events()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TouchpadInfo &touch = joy_touch[p_device];
|
||||
uint16_t index = p_finger | (p_touchpad << 8);
|
||||
if (p_pressed) {
|
||||
touch.finger_info[index] = TouchpadFingerInfo{ p_position, p_pressure };
|
||||
} else {
|
||||
touch.finger_info.erase(index);
|
||||
}
|
||||
}
|
||||
|
||||
void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) {
|
||||
Ref<InputEventJoypadButton> ievent;
|
||||
ievent.instantiate();
|
||||
|
|
@ -1968,9 +1887,6 @@ void Input::_update_joypad_features(int p_device) {
|
|||
}
|
||||
motion.last_timestamp = OS::get_singleton()->get_ticks_msec();
|
||||
}
|
||||
if (joypad->features->get_joy_num_touchpads() > 0) {
|
||||
joy_touch[p_device].num_touchpads = joypad->features->get_joy_num_touchpads();
|
||||
}
|
||||
}
|
||||
|
||||
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,6 @@ public:
|
|||
|
||||
virtual bool has_joy_motion_sensors() const { return false; }
|
||||
virtual void set_joy_motion_sensors_enabled(bool p_enable) {}
|
||||
|
||||
virtual int get_joy_num_touchpads() const { return 0; }
|
||||
};
|
||||
|
||||
static constexpr int32_t JOYPADS_MAX = 16;
|
||||
|
|
@ -194,18 +192,6 @@ private:
|
|||
|
||||
HashMap<int, MotionInfo> joy_motion;
|
||||
|
||||
struct TouchpadFingerInfo {
|
||||
Vector2 position;
|
||||
float pressure;
|
||||
};
|
||||
|
||||
struct TouchpadInfo {
|
||||
int num_touchpads = 0;
|
||||
HashMap<uint16_t, TouchpadFingerInfo> finger_info;
|
||||
};
|
||||
|
||||
HashMap<int, TouchpadInfo> joy_touch;
|
||||
|
||||
struct VelocityTrack {
|
||||
uint64_t last_tick = 0;
|
||||
Vector2 velocity;
|
||||
|
|
@ -399,8 +385,6 @@ public:
|
|||
Vector3 get_magnetometer() const;
|
||||
Vector3 get_gyroscope() const;
|
||||
|
||||
int get_joy_num_touchpads(int p_device) const;
|
||||
|
||||
Point2 get_mouse_position() const;
|
||||
Vector2 get_last_mouse_velocity();
|
||||
Vector2 get_last_mouse_screen_velocity();
|
||||
|
|
@ -444,10 +428,6 @@ public:
|
|||
|
||||
void set_joy_motion_sensors_rate(int p_device, float p_rate);
|
||||
|
||||
Vector2 get_joy_touchpad_finger_position(int p_device, int p_finger, int p_touchpad = 0) const;
|
||||
float get_joy_touchpad_finger_pressure(int p_device, int p_finger, int p_touchpad = 0) const;
|
||||
PackedInt32Array get_joy_touchpad_fingers(int p_device, int p_touchpad = 0) const;
|
||||
|
||||
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);
|
||||
|
|
@ -477,7 +457,6 @@ public:
|
|||
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 joy_touchpad(int p_device, int p_touchpad, int p_finger, const Vector2 &p_position, float p_pressure, bool p_pressed);
|
||||
|
||||
void add_joy_mapping(const String &p_mapping, bool p_update_existing = false);
|
||||
void remove_joy_mapping(const String &p_guid);
|
||||
|
|
|
|||
|
|
@ -433,7 +433,6 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
|
|||
{ "ui_unicode_start", TTRC("Start Unicode Character Input") },
|
||||
{ "ui_colorpicker_delete_preset", TTRC("ColorPicker: Delete Preset") },
|
||||
{ "ui_accessibility_drag_and_drop", TTRC("Accessibility: Keyboard Drag and Drop") },
|
||||
{ "ui_toggle_fullscreen", TTRC("Toggle Fullscreen") },
|
||||
{ "", ""}
|
||||
/* clang-format on */
|
||||
};
|
||||
|
|
@ -566,24 +565,22 @@ 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
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||
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_newline", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
|
|
@ -881,16 +878,6 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
|
|||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
|
||||
default_builtin_cache.insert("ui_colorpicker_delete_preset", inputs);
|
||||
|
||||
// ///// Miscellaneous Shortcuts /////
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_toggle_fullscreen", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::F | KeyModifierMask::CTRL | KeyModifierMask::META));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_toggle_fullscreen.macos", inputs);
|
||||
|
||||
return default_builtin_cache;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include "core/io/zip_io.h"
|
||||
|
||||
#include <thirdparty/misc/fastlz.h>
|
||||
#include "thirdparty/misc/fastlz.h"
|
||||
|
||||
#include <zstd.h>
|
||||
|
||||
|
|
@ -40,34 +40,11 @@
|
|||
#include <brotli/decode.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
struct ZstdDecompressorContext {
|
||||
ZSTD_DCtx *zstd_d_ctx = nullptr;
|
||||
bool zstd_long_distance_matching = false;
|
||||
int zstd_window_log_size = 0;
|
||||
|
||||
~ZstdDecompressorContext() {
|
||||
if (zstd_d_ctx) {
|
||||
ZSTD_freeDCtx(zstd_d_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void invalidate(bool p_zstd_long_distance_matching, int p_zstd_window_log_size) {
|
||||
if (!zstd_d_ctx || zstd_long_distance_matching != p_zstd_long_distance_matching || zstd_window_log_size != p_zstd_window_log_size) {
|
||||
if (zstd_d_ctx) {
|
||||
ZSTD_freeDCtx(zstd_d_ctx);
|
||||
}
|
||||
|
||||
zstd_d_ctx = ZSTD_createDCtx();
|
||||
if (p_zstd_long_distance_matching) {
|
||||
ZSTD_DCtx_setParameter(zstd_d_ctx, ZSTD_d_windowLogMax, p_zstd_window_log_size);
|
||||
}
|
||||
zstd_long_distance_matching = p_zstd_long_distance_matching;
|
||||
zstd_window_log_size = p_zstd_window_log_size;
|
||||
}
|
||||
}
|
||||
};
|
||||
} //namespace
|
||||
// Caches for zstd.
|
||||
static BinaryMutex mutex;
|
||||
static ZSTD_DCtx *current_zstd_d_ctx = nullptr;
|
||||
static bool current_zstd_long_distance_matching;
|
||||
static int current_zstd_window_log_size;
|
||||
|
||||
int64_t Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int64_t p_src_size, Mode p_mode) {
|
||||
switch (p_mode) {
|
||||
|
|
@ -220,10 +197,22 @@ int64_t Compression::decompress(uint8_t *p_dst, int64_t p_dst_max_size, const ui
|
|||
return total;
|
||||
} break;
|
||||
case MODE_ZSTD: {
|
||||
thread_local ZstdDecompressorContext decompressor_ctx;
|
||||
decompressor_ctx.invalidate(zstd_long_distance_matching, zstd_window_log_size);
|
||||
MutexLock lock(mutex);
|
||||
|
||||
size_t ret = ZSTD_decompressDCtx(decompressor_ctx.zstd_d_ctx, p_dst, p_dst_max_size, p_src, p_src_size);
|
||||
if (!current_zstd_d_ctx || current_zstd_long_distance_matching != zstd_long_distance_matching || current_zstd_window_log_size != zstd_window_log_size) {
|
||||
if (current_zstd_d_ctx) {
|
||||
ZSTD_freeDCtx(current_zstd_d_ctx);
|
||||
}
|
||||
|
||||
current_zstd_d_ctx = ZSTD_createDCtx();
|
||||
if (zstd_long_distance_matching) {
|
||||
ZSTD_DCtx_setParameter(current_zstd_d_ctx, ZSTD_d_windowLogMax, zstd_window_log_size);
|
||||
}
|
||||
current_zstd_long_distance_matching = zstd_long_distance_matching;
|
||||
current_zstd_window_log_size = zstd_window_log_size;
|
||||
}
|
||||
|
||||
size_t ret = ZSTD_decompressDCtx(current_zstd_d_ctx, p_dst, p_dst_max_size, p_src, p_src_size);
|
||||
return (int64_t)ret;
|
||||
} break;
|
||||
}
|
||||
|
|
@ -302,7 +291,7 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int64_t p_max_d
|
|||
#endif
|
||||
} else {
|
||||
// This function only supports GZip and Deflate.
|
||||
ERR_FAIL_COND_V_MSG(p_mode != MODE_DEFLATE && p_mode != MODE_GZIP, Z_ERRNO, "Dynamic decompression is only supported with gzip, DEFLATE, and Brotli compression methods.");
|
||||
ERR_FAIL_COND_V(p_mode != MODE_DEFLATE && p_mode != MODE_GZIP, Z_ERRNO);
|
||||
|
||||
int ret;
|
||||
z_stream strm;
|
||||
|
|
|
|||
|
|
@ -265,16 +265,11 @@ int DirAccess::_get_drive_count() {
|
|||
return d->get_drive_count();
|
||||
}
|
||||
|
||||
String DirAccess::_get_drive_name(int p_idx) {
|
||||
String DirAccess::get_drive_name(int p_idx) {
|
||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
return d->get_drive(p_idx);
|
||||
}
|
||||
|
||||
String DirAccess::_get_drive_label(int p_idx) {
|
||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
return d->get_drive_label(p_idx);
|
||||
}
|
||||
|
||||
Error DirAccess::make_dir_absolute(const String &p_dir) {
|
||||
Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
|
||||
return d->make_dir(p_dir);
|
||||
|
|
@ -651,8 +646,7 @@ void DirAccess::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
|
||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at);
|
||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count);
|
||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::_get_drive_name);
|
||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_label", "idx"), &DirAccess::_get_drive_label);
|
||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name);
|
||||
ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
|
||||
ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir);
|
||||
ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ public:
|
|||
|
||||
virtual int get_drive_count() = 0;
|
||||
virtual String get_drive(int p_drive) = 0;
|
||||
virtual String get_drive_label(int p_drive) { return String(); }
|
||||
virtual int get_current_drive();
|
||||
virtual bool drives_are_shortcuts();
|
||||
|
||||
|
|
@ -146,8 +145,7 @@ public:
|
|||
static Ref<DirAccess> create_temp(const String &p_prefix = "", bool p_keep = false, Error *r_error = nullptr);
|
||||
|
||||
static int _get_drive_count();
|
||||
static String _get_drive_name(int p_idx);
|
||||
static String _get_drive_label(int p_idx);
|
||||
static String get_drive_name(int p_idx);
|
||||
|
||||
static Error make_dir_absolute(const String &p_dir);
|
||||
static Error make_dir_recursive_absolute(const String &p_dir);
|
||||
|
|
|
|||
|
|
@ -313,9 +313,15 @@ uint16_t FileAccess::get_16() const {
|
|||
uint16_t data = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint16_t));
|
||||
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
data = BSWAP16(data);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
data = BSWAP16(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -324,9 +330,15 @@ uint32_t FileAccess::get_32() const {
|
|||
uint32_t data = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint32_t));
|
||||
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
data = BSWAP32(data);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
data = BSWAP32(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -335,9 +347,15 @@ uint64_t FileAccess::get_64() const {
|
|||
uint64_t data = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint64_t));
|
||||
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
data = BSWAP64(data);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
data = BSWAP64(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -587,25 +605,43 @@ bool FileAccess::store_8(uint8_t p_dest) {
|
|||
}
|
||||
|
||||
bool FileAccess::store_16(uint16_t p_dest) {
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
p_dest = BSWAP16(p_dest);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP16(p_dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint16_t));
|
||||
}
|
||||
|
||||
bool FileAccess::store_32(uint32_t p_dest) {
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
p_dest = BSWAP32(p_dest);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP32(p_dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
bool FileAccess::store_64(uint64_t p_dest) {
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
if (!big_endian) {
|
||||
p_dest = BSWAP64(p_dest);
|
||||
}
|
||||
#else
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP64(p_dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint64_t));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,11 @@ public:
|
|||
typedef void (*FileCloseFailNotify)(const String &);
|
||||
|
||||
typedef Ref<FileAccess> (*CreateFunc)();
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
bool big_endian = true;
|
||||
#else
|
||||
bool big_endian = false;
|
||||
#endif
|
||||
bool real_is_double = false;
|
||||
|
||||
virtual BitField<UnixPermissionFlags> _get_unix_permissions(const String &p_file) = 0;
|
||||
|
|
@ -107,7 +111,6 @@ public:
|
|||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
friend class Main;
|
||||
AccessType get_access_type() const;
|
||||
virtual String fix_path(const String &p_path) const;
|
||||
virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@
|
|||
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
CryptoCore::RandomGenerator *FileAccessEncrypted::_fae_static_rng = nullptr;
|
||||
|
||||
void FileAccessEncrypted::deinitialize() {
|
||||
if (_fae_static_rng) {
|
||||
memdelete(_fae_static_rng);
|
||||
_fae_static_rng = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic, const Vector<uint8_t> &p_iv) {
|
||||
ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute()));
|
||||
ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
|
||||
|
|
@ -47,7 +56,15 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
|
|||
key = p_key;
|
||||
if (p_iv.is_empty()) {
|
||||
iv.resize(16);
|
||||
Error err = CryptoCore::generate_random(iv.ptrw(), 16);
|
||||
if (unlikely(!_fae_static_rng)) {
|
||||
_fae_static_rng = memnew(CryptoCore::RandomGenerator);
|
||||
if (_fae_static_rng->init() != OK) {
|
||||
memdelete(_fae_static_rng);
|
||||
_fae_static_rng = nullptr;
|
||||
ERR_FAIL_V_MSG(FAILED, "Failed to initialize random number generator.");
|
||||
}
|
||||
}
|
||||
Error err = _fae_static_rng->get_random_bytes(iv.ptrw(), 16);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
} else {
|
||||
ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
|
||||
|
|
@ -81,7 +98,13 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
|
|||
uint64_t blen = p_base->get_buffer(data.ptrw(), ds);
|
||||
ERR_FAIL_COND_V(blen != ds, ERR_FILE_CORRUPT);
|
||||
|
||||
CryptoCore::decrypt_cfb(data.ptrw(), data.ptrw(), ds, key.ptrw(), key.size(), iv.ptrw());
|
||||
{
|
||||
CryptoCore::AESContext ctx;
|
||||
|
||||
ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
|
||||
ctx.decrypt_cfb(ds, iv.ptrw(), data.ptrw(), data.ptrw());
|
||||
}
|
||||
|
||||
data.resize(length);
|
||||
|
||||
unsigned char hash[16];
|
||||
|
|
@ -129,8 +152,9 @@ void FileAccessEncrypted::_close() {
|
|||
compressed.resize(len);
|
||||
memcpy(compressed.ptr(), data.ptr(), data.size());
|
||||
memset(compressed.ptr() + data.size(), 0, len - data.size());
|
||||
Error err = CryptoCore::encrypt_cfb(compressed.ptr(), compressed.ptr(), len, key.ptr(), key.size(), iv.ptr());
|
||||
ERR_FAIL_COND_MSG(err, "Error encrypting file data: " + itos(err));
|
||||
|
||||
CryptoCore::AESContext ctx;
|
||||
ctx.set_encode_key(key.ptrw(), 256);
|
||||
|
||||
if (use_magic) {
|
||||
file->store_32(ENCRYPTED_HEADER_MAGIC);
|
||||
|
|
@ -140,6 +164,8 @@ void FileAccessEncrypted::_close() {
|
|||
file->store_64(data.size());
|
||||
file->store_buffer(iv.ptr(), 16);
|
||||
|
||||
ctx.encrypt_cfb(len, iv.ptrw(), compressed.ptr(), compressed.ptr());
|
||||
|
||||
file->store_buffer(compressed.ptr(), compressed.size());
|
||||
data.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ private:
|
|||
|
||||
void _close();
|
||||
|
||||
static CryptoCore::RandomGenerator *_fae_static_rng;
|
||||
|
||||
public:
|
||||
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
|
||||
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
|
||||
|
|
@ -101,5 +103,7 @@ public:
|
|||
|
||||
virtual void close() override;
|
||||
|
||||
static void deinitialize();
|
||||
|
||||
~FileAccessEncrypted();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -540,14 +540,12 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
|
|||
path_to_load = "res://" + (simplified_path + pf.salt).sha256_text();
|
||||
}
|
||||
#endif
|
||||
Error err = OK;
|
||||
f = FileAccess::open(path_to_load, FileAccess::READ | FileAccess::SKIP_PACK, &err);
|
||||
ERR_FAIL_COND_MSG(err != OK, vformat(R"(Can't open pack-referenced file "%s" from sparse pack "%s" due to error "%s".)", simplified_path, pf.pack, error_names[err]));
|
||||
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 {
|
||||
Error err = OK;
|
||||
f = FileAccess::open(pf.pack, FileAccess::READ, &err);
|
||||
ERR_FAIL_COND_MSG(err != OK, vformat(R"(Can't open pack-referenced file "%s" from pack "%s" due to error "%s".)", p_path, pf.pack, error_names[err]));
|
||||
f = FileAccess::open(pf.pack, FileAccess::READ);
|
||||
ERR_FAIL_COND_MSG(f.is_null(), vformat(R"(Can't open pack-referenced file "%s" from pack "%s".)", p_path, pf.pack));
|
||||
f->seek(pf.offset);
|
||||
off = pf.offset;
|
||||
}
|
||||
|
|
@ -573,7 +571,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
|
|||
}
|
||||
|
||||
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
|
||||
ERR_FAIL_COND_MSG(err != OK, vformat(R"(Can't open encrypted pack-referenced file "%s" from pack "%s" due to error "%s".)", p_path, pf.pack, error_names[err]));
|
||||
ERR_FAIL_COND_MSG(err, vformat(R"(Can't open encrypted pack-referenced file "%s" from pack "%s".)", p_path, pf.pack));
|
||||
f = fae;
|
||||
off = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@
|
|||
|
||||
#include "file_access_patched.h"
|
||||
|
||||
#include "file_access_pack.h"
|
||||
|
||||
#include "core/io/delta_encoding.h"
|
||||
#include "core/io/file_access_pack.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
Error FileAccessPatched::_apply_patch() const {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_memory.h"
|
||||
#include "file_access.h"
|
||||
#include "file_access_memory.h"
|
||||
|
||||
class FileAccessPatched : public FileAccess {
|
||||
GDSOFTCLASS(FileAccessPatched, FileAccess);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#include "core/io/file_access_pack.h"
|
||||
|
||||
#include <thirdparty/minizip/unzip.h>
|
||||
#include "thirdparty/minizip/unzip.h"
|
||||
|
||||
class ZipArchive : public PackSource {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "http_client.h"
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/io/http_client.h"
|
||||
#include "core/io/ip.h"
|
||||
|
||||
class StreamPeerTCP;
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* image.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
static Image::CompressProfile _astc_format_to_compress_profile(Image::ASTCFormat p_format) {
|
||||
switch (p_format) {
|
||||
case Image::ASTC_FORMAT_4x4:
|
||||
return Image::COMPRESS_PROFILE_MAX_QUALITY;
|
||||
case Image::ASTC_FORMAT_8x8:
|
||||
return Image::COMPRESS_PROFILE_MAX_COMPRESSION;
|
||||
default:
|
||||
return Image::COMPRESS_PROFILE_AUTOMATIC;
|
||||
}
|
||||
}
|
||||
|
||||
Error Image::_compress_bind_compat_115003(CompressMode p_mode, CompressSource p_source, ASTCFormat p_format) {
|
||||
return compress(p_mode, p_source, _astc_format_to_compress_profile(p_format));
|
||||
}
|
||||
|
||||
Error Image::_compress_from_channels_compat_115003(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_format) {
|
||||
return compress_from_channels(p_mode, p_channels, _astc_format_to_compress_profile(p_format));
|
||||
}
|
||||
|
||||
Vector<uint8_t> Image::_save_exr_to_buffer_bind_compat_117800(bool p_grayscale) const {
|
||||
return save_exr_to_buffer(p_grayscale);
|
||||
}
|
||||
|
||||
Error Image::_save_exr_bind_compat_117800(const String &p_path, bool p_grayscale) const {
|
||||
return save_exr(p_path, p_grayscale);
|
||||
}
|
||||
|
||||
void Image::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("compress", "mode", "source", "astc_format"), &Image::_compress_bind_compat_115003, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_compatibility_method(D_METHOD("compress_from_channels", "mode", "channels", "astc_format"), &Image::_compress_from_channels_compat_115003, DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_compatibility_method(D_METHOD("save_exr", "path", "grayscale"), &Image::_save_exr_bind_compat_117800, DEFVAL(false));
|
||||
ClassDB::bind_compatibility_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::_save_exr_to_buffer_bind_compat_117800, DEFVAL(false));
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "image.h"
|
||||
#include "image.compat.inc"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/error/error_macros.h"
|
||||
|
|
@ -88,19 +87,17 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
|
|||
"RG16Int",
|
||||
"RGB16Int",
|
||||
"RGBA16Int",
|
||||
"ASTC_6x6",
|
||||
"ASTC_6x6_HDR",
|
||||
};
|
||||
|
||||
// External VRAM compression function pointers.
|
||||
|
||||
void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels, Image::BPTCFormat) = nullptr;
|
||||
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_etc1_func)(Image *) = nullptr;
|
||||
void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_astc_func)(Image *, Image::UsedChannels, Image::CompressProfile) = nullptr;
|
||||
void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr;
|
||||
|
||||
Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels, Image::BPTCFormat) = nullptr;
|
||||
Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
Error (*Image::_image_compress_bc_rd_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
|
||||
// External VRAM decompression function pointers.
|
||||
|
|
@ -209,10 +206,6 @@ int Image::get_format_pixel_size(Format p_format) {
|
|||
return 1;
|
||||
case FORMAT_ASTC_4x4_HDR:
|
||||
return 1;
|
||||
case FORMAT_ASTC_6x6:
|
||||
return 1;
|
||||
case FORMAT_ASTC_6x6_HDR:
|
||||
return 1;
|
||||
case FORMAT_ASTC_8x8:
|
||||
return 1;
|
||||
case FORMAT_ASTC_8x8_HDR:
|
||||
|
|
@ -239,27 +232,6 @@ int Image::get_format_pixel_size(Format p_format) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint64_t Image::get_format_pixels_shifted(Format p_format, uint64_t p_pixels) {
|
||||
switch (p_format) {
|
||||
case FORMAT_ASTC_8x8:
|
||||
case FORMAT_ASTC_8x8_HDR:
|
||||
return p_pixels >> 2;
|
||||
case FORMAT_ASTC_6x6:
|
||||
case FORMAT_ASTC_6x6_HDR:
|
||||
return (p_pixels * 4) / 9;
|
||||
case FORMAT_DXT1:
|
||||
case FORMAT_RGTC_R:
|
||||
case FORMAT_ETC:
|
||||
case FORMAT_ETC2_R11:
|
||||
case FORMAT_ETC2_R11S:
|
||||
case FORMAT_ETC2_RGB8:
|
||||
case FORMAT_ETC2_RGB8A1:
|
||||
return p_pixels >> 1;
|
||||
default:
|
||||
return p_pixels;
|
||||
}
|
||||
}
|
||||
|
||||
void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
||||
switch (p_format) {
|
||||
case FORMAT_DXT1:
|
||||
|
|
@ -297,11 +269,6 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
|||
r_w = 4;
|
||||
r_h = 4;
|
||||
} break;
|
||||
case FORMAT_ASTC_6x6:
|
||||
case FORMAT_ASTC_6x6_HDR: {
|
||||
r_w = 6;
|
||||
r_h = 6;
|
||||
} break;
|
||||
case FORMAT_ASTC_8x8:
|
||||
case FORMAT_ASTC_8x8_HDR: {
|
||||
r_w = 8;
|
||||
|
|
@ -314,6 +281,16 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
|||
}
|
||||
}
|
||||
|
||||
int Image::get_format_pixel_rshift(Format p_format) {
|
||||
if (p_format == FORMAT_ASTC_8x8) {
|
||||
return 2;
|
||||
} else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Image::get_format_block_size(Format p_format) {
|
||||
switch (p_format) {
|
||||
case FORMAT_DXT1:
|
||||
|
|
@ -346,10 +323,6 @@ int Image::get_format_block_size(Format p_format) {
|
|||
case FORMAT_ASTC_4x4_HDR: {
|
||||
return 4;
|
||||
}
|
||||
case FORMAT_ASTC_6x6:
|
||||
case FORMAT_ASTC_6x6_HDR: {
|
||||
return 6;
|
||||
}
|
||||
case FORMAT_ASTC_8x8:
|
||||
case FORMAT_ASTC_8x8_HDR: {
|
||||
return 8;
|
||||
|
|
@ -367,6 +340,7 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_
|
|||
int64_t ofs = 0;
|
||||
|
||||
int pixel_size = get_format_pixel_size(format);
|
||||
int pixel_rshift = get_format_pixel_rshift(format);
|
||||
int block = get_format_block_size(format);
|
||||
int minw, minh;
|
||||
get_format_min_pixel_size(format, minw, minh);
|
||||
|
|
@ -378,7 +352,7 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_
|
|||
int64_t s = bw * bh;
|
||||
|
||||
s *= pixel_size;
|
||||
s = get_format_pixels_shifted(format, s);
|
||||
s >>= pixel_rshift;
|
||||
ofs += s;
|
||||
w = MAX(minw, w >> 1);
|
||||
h = MAX(minh, h >> 1);
|
||||
|
|
@ -1933,6 +1907,7 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i
|
|||
int mm = 0;
|
||||
|
||||
int pixsize = get_format_pixel_size(p_format);
|
||||
int pixshift = get_format_pixel_rshift(p_format);
|
||||
int block = get_format_block_size(p_format);
|
||||
|
||||
// Technically, you can still compress up to 1 px no matter the format, so commenting this.
|
||||
|
|
@ -1947,7 +1922,7 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i
|
|||
int64_t s = bw * bh;
|
||||
|
||||
s *= pixsize;
|
||||
s = get_format_pixels_shifted(p_format, s);
|
||||
s >>= pixshift;
|
||||
|
||||
size += s;
|
||||
|
||||
|
|
@ -2401,7 +2376,7 @@ bool Image::is_empty() const {
|
|||
return (data.is_empty());
|
||||
}
|
||||
|
||||
const Vector<uint8_t> &Image::get_data() const {
|
||||
Vector<uint8_t> Image::get_data() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -2845,18 +2820,19 @@ Vector<uint8_t> Image::save_jpg_to_buffer(float p_quality) const {
|
|||
return save_jpg_buffer_func(Ref<Image>((Image *)this), p_quality);
|
||||
}
|
||||
|
||||
Error Image::save_exr(const String &p_path, bool p_grayscale, bool p_color_image, float p_max_value) const {
|
||||
Error Image::save_exr(const String &p_path, bool p_grayscale) const {
|
||||
if (save_exr_func == nullptr) {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale, p_color_image, p_max_value);
|
||||
|
||||
return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
|
||||
}
|
||||
|
||||
Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale, bool p_color_image, float p_max_value) const {
|
||||
Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const {
|
||||
if (save_exr_buffer_func == nullptr) {
|
||||
return Vector<uint8_t>();
|
||||
}
|
||||
return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale, p_color_image, p_max_value);
|
||||
return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale);
|
||||
}
|
||||
|
||||
Error Image::save_dds(const String &p_path) const {
|
||||
|
|
@ -2933,7 +2909,7 @@ bool Image::is_compressed() const {
|
|||
}
|
||||
|
||||
bool Image::is_format_compressed(Format p_format) {
|
||||
return (p_format >= FORMAT_DXT1 && p_format <= FORMAT_ASTC_8x8_HDR) || (p_format >= FORMAT_ASTC_6x6 && p_format <= FORMAT_ASTC_6x6_HDR);
|
||||
return p_format > FORMAT_RGBE9995 && p_format < FORMAT_R16;
|
||||
}
|
||||
|
||||
Error Image::decompress() {
|
||||
|
|
@ -2945,7 +2921,7 @@ Error Image::decompress() {
|
|||
_image_decompress_etc1(this);
|
||||
} else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) {
|
||||
_image_decompress_etc2(this);
|
||||
} else if (((format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR) || (format >= FORMAT_ASTC_6x6 && format <= FORMAT_ASTC_6x6_HDR)) && _image_decompress_astc) {
|
||||
} else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) {
|
||||
_image_decompress_astc(this);
|
||||
} else {
|
||||
return ERR_UNAVAILABLE;
|
||||
|
|
@ -2966,17 +2942,13 @@ bool Image::can_decompress(const String &p_format_tag) {
|
|||
return false;
|
||||
}
|
||||
|
||||
Error Image::compress(CompressMode p_mode, CompressSource p_source, CompressProfile p_profile) {
|
||||
Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p_astc_format) {
|
||||
ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode.");
|
||||
ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source.");
|
||||
return compress_from_channels(p_mode, detect_used_channels(p_source), p_profile);
|
||||
return compress_from_channels(p_mode, detect_used_channels(p_source), p_astc_format);
|
||||
}
|
||||
|
||||
Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile) {
|
||||
return _compress_from_channels(p_mode, p_channels, p_profile, BPTC_DETECT);
|
||||
}
|
||||
|
||||
Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile, BPTCFormat p_bptc_format) {
|
||||
Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format) {
|
||||
ERR_FAIL_COND_V(data.is_empty(), ERR_INVALID_DATA);
|
||||
|
||||
// RenderingDevice only.
|
||||
|
|
@ -2985,7 +2957,7 @@ Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channel
|
|||
case COMPRESS_BPTC: {
|
||||
// BC7 is unsupported currently.
|
||||
if ((format >= FORMAT_RF && format <= FORMAT_RGBE9995) && _image_compress_bptc_rd_func) {
|
||||
Error result = _image_compress_bptc_rd_func(this, p_channels, p_bptc_format);
|
||||
Error result = _image_compress_bptc_rd_func(this, p_channels);
|
||||
|
||||
// If the image was compressed successfully, we return here. If not, we fall back to the default compression scheme.
|
||||
if (result == OK) {
|
||||
|
|
@ -3024,11 +2996,11 @@ Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channel
|
|||
} break;
|
||||
case COMPRESS_BPTC: {
|
||||
ERR_FAIL_NULL_V(_image_compress_bptc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_bptc_func(this, p_channels, p_bptc_format);
|
||||
_image_compress_bptc_func(this, p_channels);
|
||||
} break;
|
||||
case COMPRESS_ASTC: {
|
||||
ERR_FAIL_NULL_V(_image_compress_astc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_astc_func(this, p_channels, p_profile);
|
||||
_image_compress_astc_func(this, p_astc_format);
|
||||
} break;
|
||||
case COMPRESS_MAX: {
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
|
|
@ -3907,8 +3879,8 @@ void Image::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer);
|
||||
ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75));
|
||||
ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75));
|
||||
ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale", "color_image", "max_linear_value"), &Image::save_exr, DEFVAL(false), DEFVAL(false), DEFVAL(-1.0));
|
||||
ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale", "color_image", "max_linear_value"), &Image::save_exr_to_buffer, DEFVAL(false), DEFVAL(false), DEFVAL(-1.0));
|
||||
ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("save_dds", "path"), &Image::save_dds);
|
||||
ClassDB::bind_method(D_METHOD("save_dds_to_buffer"), &Image::save_dds_to_buffer);
|
||||
|
||||
|
|
@ -3919,8 +3891,8 @@ void Image::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC));
|
||||
ClassDB::bind_method(D_METHOD("compress", "mode", "source", "profile"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(COMPRESS_PROFILE_AUTOMATIC));
|
||||
ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "profile"), &Image::compress_from_channels, DEFVAL(COMPRESS_PROFILE_AUTOMATIC));
|
||||
ClassDB::bind_method(D_METHOD("compress", "mode", "source", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "astc_format"), &Image::compress_from_channels, DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
|
||||
ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
|
||||
|
||||
|
|
@ -4023,8 +3995,6 @@ void Image::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(FORMAT_RG16I);
|
||||
BIND_ENUM_CONSTANT(FORMAT_RGB16I);
|
||||
BIND_ENUM_CONSTANT(FORMAT_RGBA16I);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_6x6);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_6x6_HDR);
|
||||
BIND_ENUM_CONSTANT(FORMAT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
|
||||
|
|
@ -4055,16 +4025,8 @@ void Image::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL);
|
||||
|
||||
BIND_ENUM_CONSTANT(COMPRESS_PROFILE_AUTOMATIC);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX_QUALITY);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_PROFILE_COMPRESSED);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX_COMPRESSION);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4);
|
||||
BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Image::normal_map_to_xy() {
|
||||
|
|
@ -4442,10 +4404,6 @@ uint32_t Image::get_format_component_mask(Format p_format) {
|
|||
return rgba;
|
||||
case FORMAT_ASTC_4x4_HDR:
|
||||
return rgba;
|
||||
case FORMAT_ASTC_6x6:
|
||||
return rgba;
|
||||
case FORMAT_ASTC_6x6_HDR:
|
||||
return rgba;
|
||||
case FORMAT_ASTC_8x8:
|
||||
return rgba;
|
||||
case FORMAT_ASTC_8x8_HDR:
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size
|
|||
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
|
||||
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
|
||||
|
||||
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale, bool p_color_image, float p_max_value);
|
||||
typedef Vector<uint8_t> (*SaveEXRBufferFunc)(const Ref<Image> &p_img, bool p_grayscale, bool p_color_image, float p_max_value);
|
||||
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
|
||||
typedef Vector<uint8_t> (*SaveEXRBufferFunc)(const Ref<Image> &p_img, bool p_grayscale);
|
||||
|
||||
typedef Error (*SaveDDSFunc)(const String &p_path, const Ref<Image> &p_img);
|
||||
typedef Vector<uint8_t> (*SaveDDSBufferFunc)(const Ref<Image> &p_img);
|
||||
|
|
@ -119,8 +119,6 @@ public:
|
|||
FORMAT_RG16I,
|
||||
FORMAT_RGB16I,
|
||||
FORMAT_RGBA16I,
|
||||
FORMAT_ASTC_6x6,
|
||||
FORMAT_ASTC_6x6_HDR,
|
||||
FORMAT_MAX
|
||||
};
|
||||
|
||||
|
|
@ -146,19 +144,11 @@ public:
|
|||
USED_CHANNELS_RGBA,
|
||||
};
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
// ASTC supports block formats other than 4x4.
|
||||
enum ASTCFormat {
|
||||
ASTC_FORMAT_4x4,
|
||||
ASTC_FORMAT_8x8,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum BPTCFormat {
|
||||
BPTC_DETECT,
|
||||
BPTC_FORCE_SIGNED,
|
||||
BPTC_FORCE_UNSIGNED,
|
||||
};
|
||||
|
||||
enum RoughnessChannel {
|
||||
ROUGHNESS_CHANNEL_R,
|
||||
|
|
@ -194,14 +184,6 @@ public:
|
|||
COMPRESS_SOURCE_MAX,
|
||||
};
|
||||
|
||||
enum CompressProfile {
|
||||
COMPRESS_PROFILE_AUTOMATIC,
|
||||
COMPRESS_PROFILE_MAX_QUALITY,
|
||||
COMPRESS_PROFILE_COMPRESSED,
|
||||
COMPRESS_PROFILE_MAX_COMPRESSION,
|
||||
COMPRESS_PROFILE_MAX
|
||||
};
|
||||
|
||||
enum AlphaMode {
|
||||
ALPHA_NONE,
|
||||
ALPHA_BIT,
|
||||
|
|
@ -242,12 +224,12 @@ public:
|
|||
// External VRAM compression function pointers.
|
||||
|
||||
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
|
||||
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels, BPTCFormat p_bptc_format);
|
||||
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
|
||||
static void (*_image_compress_etc1_func)(Image *);
|
||||
static void (*_image_compress_etc2_func)(Image *, UsedChannels p_channels);
|
||||
static void (*_image_compress_astc_func)(Image *, UsedChannels p_channels, CompressProfile p_profile);
|
||||
static void (*_image_compress_astc_func)(Image *, ASTCFormat p_format);
|
||||
|
||||
static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels, BPTCFormat p_bptc_format);
|
||||
static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels);
|
||||
static Error (*_image_compress_bc_rd_func)(Image *, UsedChannels p_channels);
|
||||
|
||||
// External VRAM decompression function pointers.
|
||||
|
|
@ -275,15 +257,6 @@ protected:
|
|||
|
||||
static void _bind_methods();
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Error _compress_bind_compat_115003(CompressMode p_mode, CompressSource p_source, ASTCFormat p_format);
|
||||
Error _compress_from_channels_compat_115003(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_format);
|
||||
Vector<uint8_t> _save_exr_to_buffer_bind_compat_117800(bool p_grayscale = false) const;
|
||||
Error _save_exr_bind_compat_117800(const String &p_path, bool p_grayscale = false) const;
|
||||
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
private:
|
||||
Format format = FORMAT_L8;
|
||||
Vector<uint8_t> data;
|
||||
|
|
@ -379,7 +352,7 @@ public:
|
|||
// Returns true when the image is empty (0,0) in size.
|
||||
bool is_empty() const;
|
||||
|
||||
const Vector<uint8_t> &get_data() const _LIFETIME_BOUND_;
|
||||
Vector<uint8_t> get_data() const;
|
||||
|
||||
Error load(const String &p_path);
|
||||
static Ref<Image> load_from_file(const String &p_path);
|
||||
|
|
@ -388,9 +361,9 @@ public:
|
|||
Error save_dds(const String &p_path) const;
|
||||
Vector<uint8_t> save_png_to_buffer() const;
|
||||
Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const;
|
||||
Vector<uint8_t> save_exr_to_buffer(bool p_grayscale = false, bool p_color_image = false, float p_max_value = -1.0f) const;
|
||||
Vector<uint8_t> save_exr_to_buffer(bool p_grayscale = false) const;
|
||||
Vector<uint8_t> save_dds_to_buffer() const;
|
||||
Error save_exr(const String &p_path, bool p_grayscale = false, bool p_color_image = false, float p_max_value = -1.0f) const;
|
||||
Error save_exr(const String &p_path, bool p_grayscale = false) const;
|
||||
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
|
||||
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
|
||||
|
||||
|
|
@ -408,7 +381,7 @@ public:
|
|||
bool is_invisible() const;
|
||||
|
||||
static int get_format_pixel_size(Format p_format);
|
||||
static uint64_t get_format_pixels_shifted(Format p_format, uint64_t p_pixels);
|
||||
static int get_format_pixel_rshift(Format p_format);
|
||||
static int get_format_block_size(Format p_format);
|
||||
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
|
||||
|
||||
|
|
@ -418,9 +391,8 @@ public:
|
|||
static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
|
||||
static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h);
|
||||
|
||||
Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, CompressProfile p_profile = COMPRESS_PROFILE_AUTOMATIC);
|
||||
Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile = COMPRESS_PROFILE_AUTOMATIC);
|
||||
Error _compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile, BPTCFormat p_bptc_format);
|
||||
Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
|
||||
Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
|
||||
Error decompress();
|
||||
bool is_compressed() const;
|
||||
static bool is_format_compressed(Format p_format);
|
||||
|
|
@ -495,8 +467,4 @@ VARIANT_ENUM_CAST(Image::CompressSource)
|
|||
VARIANT_ENUM_CAST(Image::UsedChannels)
|
||||
VARIANT_ENUM_CAST(Image::AlphaMode)
|
||||
VARIANT_ENUM_CAST(Image::RoughnessChannel)
|
||||
VARIANT_ENUM_CAST(Image::CompressProfile)
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
VARIANT_ENUM_CAST(Image::ASTCFormat)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -139,3 +139,74 @@ void ImageLoader::cleanup() {
|
|||
remove_image_format_loader(loader[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
||||
if (f.is_null()) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_CANT_OPEN;
|
||||
}
|
||||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
uint8_t header[4] = { 0, 0, 0, 0 };
|
||||
f->get_buffer(header, 4);
|
||||
|
||||
bool unrecognized = header[0] != 'G' || header[1] != 'D' || header[2] != 'I' || header[3] != 'M';
|
||||
if (unrecognized) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_UNRECOGNIZED;
|
||||
}
|
||||
ERR_FAIL_V(Ref<Resource>());
|
||||
}
|
||||
|
||||
String extension = f->get_pascal_string();
|
||||
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < ImageLoader::loader.size(); i++) {
|
||||
if (ImageLoader::loader[i]->recognize(extension)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_UNRECOGNIZED;
|
||||
}
|
||||
ERR_FAIL_V(Ref<Resource>());
|
||||
}
|
||||
|
||||
Ref<Image> image;
|
||||
image.instantiate();
|
||||
|
||||
Error err = ImageLoader::loader.write[idx]->load_image(image, f);
|
||||
|
||||
if (err != OK) {
|
||||
if (r_error) {
|
||||
*r_error = err;
|
||||
}
|
||||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderImage::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("image");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderImage::handles_type(const String &p_type) const {
|
||||
return p_type == "Image";
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderImage::get_resource_type(const String &p_path) const {
|
||||
return p_path.get_extension().to_lower() == "image" ? "Image" : String();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/image.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/gdvirtual.gen.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/list.h"
|
||||
|
|
@ -97,3 +98,13 @@ public:
|
|||
|
||||
static void cleanup();
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderImage : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderImage, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* image_resource_format.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
|
||||
class ResourceFormatLoaderImage : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderImage, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
};
|
||||
|
|
@ -135,8 +135,8 @@ bool IPAddress::_parse_ipv6(const String &p_string, IPAddress &r_ip) {
|
|||
return cur == 8; // Should have parsed 8 16-bits ints.
|
||||
} else if (shift > 7) {
|
||||
return false; // Can't shorten more than this.
|
||||
} else if (shift == cur || cur == 8) {
|
||||
return true; // Nothing to do (fields are assumed zeroized).
|
||||
} else if (shift == cur) {
|
||||
return true; // Nothing to do, end is assumed zeroized.
|
||||
}
|
||||
// Shift bytes.
|
||||
int pad = 8 - cur;
|
||||
|
|
@ -146,7 +146,6 @@ bool IPAddress::_parse_ipv6(const String &p_string, IPAddress &r_ip) {
|
|||
r_ip.field16[i] = 0;
|
||||
} else {
|
||||
r_ip.field16[i] = r_ip.field16[i - pad];
|
||||
r_ip.field16[i - pad] = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
#include "json.h"
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#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"
|
||||
|
|
@ -1550,3 +1551,88 @@ Variant JSON::_to_native(const Variant &p_json, bool p_allow_objects, int p_dept
|
|||
#undef VALUE_TYPE
|
||||
#undef ARGS
|
||||
#undef PROPS
|
||||
|
||||
////////////
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_CANT_OPEN;
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(p_path)) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
Ref<JSON> json;
|
||||
json.instantiate();
|
||||
|
||||
Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint());
|
||||
if (err != OK) {
|
||||
String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message();
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
// If running on editor, still allow opening the JSON so the code editor can edit it.
|
||||
WARN_PRINT(err_text);
|
||||
} else {
|
||||
if (r_error) {
|
||||
*r_error = err;
|
||||
}
|
||||
ERR_PRINT(err_text);
|
||||
return Ref<Resource>();
|
||||
}
|
||||
}
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("json");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
|
||||
return (p_type == "JSON");
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
|
||||
if (p_path.has_extension("json")) {
|
||||
return "JSON";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Ref<JSON> json = p_resource;
|
||||
ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
|
||||
|
||||
String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text();
|
||||
|
||||
Error err;
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, vformat("Cannot save json '%s'.", p_path));
|
||||
|
||||
file->store_string(source);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
Ref<JSON> json = p_resource;
|
||||
if (json.is_valid()) {
|
||||
p_extensions->push_back("json");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
|
||||
return p_resource->get_class_name() == "JSON"; //only json, not inherited
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class JSON : public Resource {
|
||||
|
|
@ -103,3 +105,26 @@ public:
|
|||
_FORCE_INLINE_ int get_error_line() const { return err_line; }
|
||||
_FORCE_INLINE_ String get_error_message() const { return err_str; }
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderJSON : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderJSON, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
|
||||
// Treat JSON as a text file, do not generate a `*.json.uid` file.
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override { return ResourceUID::INVALID_ID; }
|
||||
virtual bool has_custom_uid_support() const override { return true; }
|
||||
};
|
||||
|
||||
class ResourceFormatSaverJSON : public ResourceFormatSaver {
|
||||
GDSOFTCLASS(ResourceFormatSaverJSON, ResourceFormatSaver);
|
||||
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,118 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* json_resource_format.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "json_resource_format.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/json.h"
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_CANT_OPEN;
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(p_path)) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
Ref<JSON> json;
|
||||
json.instantiate();
|
||||
|
||||
Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint());
|
||||
if (err != OK) {
|
||||
String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message();
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
// If running on editor, still allow opening the JSON so the code editor can edit it.
|
||||
WARN_PRINT(err_text);
|
||||
} else {
|
||||
if (r_error) {
|
||||
*r_error = err;
|
||||
}
|
||||
ERR_PRINT(err_text);
|
||||
return Ref<Resource>();
|
||||
}
|
||||
}
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("json");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
|
||||
return (p_type == "JSON");
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
|
||||
if (p_path.has_extension("json")) {
|
||||
return "JSON";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Ref<JSON> json = p_resource;
|
||||
ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
|
||||
|
||||
String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text();
|
||||
|
||||
Error err;
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, vformat("Cannot save json '%s'.", p_path));
|
||||
|
||||
file->store_string(source);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
Ref<JSON> json = p_resource;
|
||||
if (json.is_valid()) {
|
||||
p_extensions->push_back("json");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
|
||||
return p_resource->get_class_name() == "JSON"; //only json, not inherited
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue