feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "engine"]
path = engine
url = https://github.com/godotengine/godot.git

View file

@ -5,7 +5,6 @@
Diagnostics: Diagnostics:
Includes: Includes:
IgnoreHeader: IgnoreHeader:
- core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere.
- \.compat\.inc - \.compat\.inc
--- ---
# Header-specific conditions. # Header-specific conditions.

View file

@ -16,5 +16,6 @@ indent_style = space
indent_size = 2 indent_size = 2
indent_style = space indent_style = space
[*.svg] [{*.props,*.vcxproj}]
insert_final_newline = false indent_size = 2
indent_style = space

View file

@ -66,3 +66,9 @@ bb5f390fb9b466be35a5df7651323d7e66afca31
# Style: Enforce `AllowShortFunctionsOnASingleLine` # Style: Enforce `AllowShortFunctionsOnASingleLine`
e06d83860d798b6766b23d6eae48557387a7db85 e06d83860d798b6766b23d6eae48557387a7db85
# Style: Enforce trailing newlines on svgs
7e5baa042639ffa835271703c720e2595e90afb8
# Style: Replace header guards with `#pragma once`
324512e11c1b7663c3cf47bec6ddbe65c6b8db2b

5
engine/.gitignore vendored
View file

@ -263,6 +263,11 @@ bld/
!thirdparty/**/arm/ !thirdparty/**/arm/
!thirdparty/**/arm64/ !thirdparty/**/arm64/
thirdparty/swappy-frame-pacing/arm64-v8a/abi.json
thirdparty/swappy-frame-pacing/armeabi-v7a/abi.json
thirdparty/swappy-frame-pacing/x86/abi.json
thirdparty/swappy-frame-pacing/x86_64/abi.json
# Visual Studio 2015/2017 cache/options directory # Visual Studio 2015/2017 cache/options directory
.vs/ .vs/

View file

@ -4,24 +4,22 @@ default_language_version:
exclude: | exclude: |
(?x)^( (?x)^(
.*thirdparty/.*| .*thirdparty/.*|
.*-so_wrap\.(h|c)| .*-(dll|dylib|so)_wrap\.[ch]|
platform/android/java/editor/src/main/java/com/android/.*| platform/android/java/editor/src/main/java/com/android/.*|
platform/android/java/lib/src/com/google/.* platform/android/java/lib/src/com/google/.*
)$ )$
repos: repos:
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.3 rev: v20.1.0
hooks: hooks:
- id: clang-format - id: clang-format
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$ files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
types_or: [text] types_or: [text]
exclude: ^tests/python_build/.*
- id: clang-format - id: clang-format
name: clang-format-glsl name: clang-format-glsl
files: \.glsl$ files: \.glsl$
types_or: [text] types_or: [text]
exclude: ^tests/python_build/.*
args: [-style=file:misc/utility/clang_format_glsl.yml] args: [-style=file:misc/utility/clang_format_glsl.yml]
- repo: https://github.com/pocc/pre-commit-hooks - repo: https://github.com/pocc/pre-commit-hooks
@ -31,13 +29,12 @@ repos:
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$ files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
args: [--fix, --quiet, --use-color] args: [--fix, --quiet, --use-color]
types_or: [text] types_or: [text]
exclude: ^tests/python_build/.* additional_dependencies: [clang-tidy==20.1.0]
additional_dependencies: [clang-tidy==19.1.0]
require_serial: true require_serial: true
stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy` stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.4 rev: v0.11.4
hooks: hooks:
- id: ruff - id: ruff
args: [--fix] args: [--fix]
@ -48,14 +45,14 @@ repos:
types_or: [text] types_or: [text]
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1 rev: v1.14.1 # Latest version that supports Python 3.8
hooks: hooks:
- id: mypy - id: mypy
files: \.py$ files: \.py$
types_or: [text] types_or: [text]
- repo: https://github.com/codespell-project/codespell - repo: https://github.com/codespell-project/codespell
rev: v2.3.0 rev: v2.4.1
hooks: hooks:
- id: codespell - id: codespell
additional_dependencies: [tomli] additional_dependencies: [tomli]
@ -88,6 +85,13 @@ repos:
pass_filenames: false pass_filenames: false
files: ^(doc/classes|.*/doc_classes)/.*\.xml$ files: ^(doc/classes|.*/doc_classes)/.*\.xml$
- id: validate-builders
name: validate-builders
language: python
entry: python tests/python_build/validate_builders.py
pass_filenames: false
files: ^(gles3|glsl)_builders\.py$
- id: eslint - id: eslint
name: eslint name: eslint
language: node language: node
@ -154,7 +158,6 @@ repos:
language: python language: python
entry: python misc/scripts/header_guards.py entry: python misc/scripts/header_guards.py
files: \.(h|hpp|hh|hxx)$ files: \.(h|hpp|hh|hxx)$
exclude: ^.*/(dummy|thread|platform_config|platform_gl)\.h$
- id: file-format - id: file-format
name: file-format name: file-format

View file

@ -163,6 +163,11 @@ Comment: Temporal Anti-Aliasing resolve implementation
Copyright: 2016, Panos Karabelas Copyright: 2016, Panos Karabelas
License: Expat License: Expat
Files: thirdparty/accesskit/*
Comment: AccessKit
Copyright: 2023, The AccessKit Authors.
License: Expat
Files: thirdparty/amd-fsr/* Files: thirdparty/amd-fsr/*
Comment: AMD FidelityFX Super Resolution Comment: AMD FidelityFX Super Resolution
Copyright: 2021, Advanced Micro Devices, Inc. Copyright: 2021, Advanced Micro Devices, Inc.
@ -200,7 +205,7 @@ License: MPL-2.0
Files: thirdparty/clipper2/* Files: thirdparty/clipper2/*
Comment: Clipper2 Comment: Clipper2
Copyright: 2010-2024, Angus Johnson Copyright: 2010-2025, Angus Johnson
License: BSL-1.0 License: BSL-1.0
Files: thirdparty/cvtt/* Files: thirdparty/cvtt/*

View file

@ -14,6 +14,7 @@ from importlib.util import module_from_spec, spec_from_file_location
from types import ModuleType from types import ModuleType
from SCons import __version__ as scons_raw_version from SCons import __version__ as scons_raw_version
from SCons.Builder import ListEmitter
# Explicitly resolve the helper modules, this is done to avoid clash with # Explicitly resolve the helper modules, this is done to avoid clash with
# modules of the same name that might be randomly added (e.g. someone adding # modules of the same name that might be randomly added (e.g. someone adding
@ -57,7 +58,7 @@ import gles3_builders
import glsl_builders import glsl_builders
import methods import methods
import scu_builders import scu_builders
from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning from misc.utility.color import is_stderr_color, print_error, print_info, print_warning
from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
if ARGUMENTS.get("target", "editor") == "editor": if ARGUMENTS.get("target", "editor") == "editor":
@ -166,7 +167,7 @@ opts.Add(
"optimize", "optimize",
"Optimization level (by default inferred from 'target' and 'dev_build')", "Optimization level (by default inferred from 'target' and 'dev_build')",
"auto", "auto",
("auto", "none", "custom", "debug", "speed", "speed_trace", "size"), ("auto", "none", "custom", "debug", "speed", "speed_trace", "size", "size_extra"),
) )
) )
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", False)) opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", False))
@ -186,11 +187,12 @@ opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False)) opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False))
opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False)) opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False))
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
opts.Add(BoolVariable("accesskit", "Use AccessKit C SDK", True))
opts.Add(("accesskit_sdk_path", "Path to the AccessKit C SDK", ""))
# Advanced options # Advanced options
opts.Add( opts.Add(
@ -220,6 +222,11 @@ opts.Add("vsproj_name", "Name of the Visual Studio solution", "godot")
opts.Add("import_env_vars", "A comma-separated list of environment variables to copy from the outer environment.", "") opts.Add("import_env_vars", "A comma-separated list of environment variables to copy from the outer environment.", "")
opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False)) opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False))
opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False)) opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False))
opts.Add(BoolVariable("disable_physics_2d", "Disable 2D physics nodes and server", False))
opts.Add(BoolVariable("disable_physics_3d", "Disable 3D physics nodes and server", False))
opts.Add(BoolVariable("disable_navigation_2d", "Disable 2D navigation features", False))
opts.Add(BoolVariable("disable_navigation_3d", "Disable 3D navigation features", False))
opts.Add(BoolVariable("disable_xr", "Disable XR nodes and server", False))
opts.Add("build_profile", "Path to a file containing a feature build profile", "") opts.Add("build_profile", "Path to a file containing a feature build profile", "")
opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True)) opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True))
opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", True)) opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", True))
@ -236,6 +243,13 @@ opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False)) opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "") opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "")
opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0") opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0")
opts.Add(
BoolVariable(
"redirect_build_objects",
"Enable redirecting built objects/libraries to `bin/obj/` to declutter the repository.",
True,
)
)
# Thirdparty libraries # Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True)) opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
@ -433,10 +447,19 @@ for tool in custom_tools:
env.Tool(tool) env.Tool(tool)
# add default include paths # Add default include paths.
env.Prepend(CPPPATH=["#"]) env.Prepend(CPPPATH=["#"])
# Allow marking includes as external/system to avoid raising warnings.
env["_CCCOMCOM"] += " $_CPPEXTINCFLAGS"
env["CPPEXTPATH"] = []
if env.scons_version < (4, 2):
env["_CPPEXTINCFLAGS"] = "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"
else:
env["_CPPEXTINCFLAGS"] = (
"${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}"
)
# configure ENV for platform # configure ENV for platform
env.platform_exporters = platform_exporters env.platform_exporters = platform_exporters
env.platform_apis = platform_apis env.platform_apis = platform_apis
@ -696,83 +719,84 @@ if env["arch"] == "x86_32":
# Explicitly specify colored output. # Explicitly specify colored output.
if methods.using_gcc(env): if methods.using_gcc(env):
env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"]) env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if is_stderr_color() else "-fno-diagnostics-color"])
elif methods.using_clang(env) or methods.using_emcc(env): elif methods.using_clang(env) or methods.using_emcc(env):
env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"]) env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if is_stderr_color() else "-fno-color-diagnostics"])
if sys.platform == "win32": if sys.platform == "win32":
env.AppendUnique(CCFLAGS=["-fansi-escape-codes"]) env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
# Set optimize and debug_symbols flags. # Set optimize and debug_symbols flags.
# "custom" means do nothing and let users set their own optimization flags. # "custom" means do nothing and let users set their own optimization flags.
# Needs to happen after configure to have `env.msvc` defined. # Needs to happen after configure to have `env.msvc` defined.
env.AppendUnique(CCFLAGS=["$OPTIMIZELEVEL"])
if env.msvc: if env.msvc:
if env["debug_symbols"]: if env["debug_symbols"]:
env.Append(CCFLAGS=["/Zi", "/FS"]) env.AppendUnique(CCFLAGS=["/Zi", "/FS"])
env.Append(LINKFLAGS=["/DEBUG:FULL"]) env.AppendUnique(LINKFLAGS=["/DEBUG:FULL"])
else: else:
env.Append(LINKFLAGS=["/DEBUG:NONE"]) env.AppendUnique(LINKFLAGS=["/DEBUG:NONE"])
if env["optimize"].startswith("speed"): if env["optimize"].startswith("speed"):
env.Append(CCFLAGS=["/O2"]) env["OPTIMIZELEVEL"] = "/O2"
env.Append(LINKFLAGS=["/OPT:REF"]) env.AppendUnique(LINKFLAGS=["/OPT:REF"])
if env["optimize"] == "speed_trace": if env["optimize"] == "speed_trace":
env.Append(LINKFLAGS=["/OPT:NOICF"]) env.AppendUnique(LINKFLAGS=["/OPT:NOICF"])
elif env["optimize"] == "size": elif env["optimize"].startswith("size"):
env.Append(CCFLAGS=["/O1"]) env["OPTIMIZELEVEL"] = "/O1"
env.Append(LINKFLAGS=["/OPT:REF"]) env.AppendUnique(LINKFLAGS=["/OPT:REF"])
if env["optimize"] == "size_extra":
env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"])
elif env["optimize"] == "debug" or env["optimize"] == "none": elif env["optimize"] == "debug" or env["optimize"] == "none":
env.Append(CCFLAGS=["/Od"]) env["OPTIMIZELEVEL"] = "/Od"
else: else:
if env["debug_symbols"]: if env["debug_symbols"]:
if env["platform"] == "windows": if env["platform"] == "windows":
if methods.using_clang(env): if methods.using_clang(env):
env.Append(CCFLAGS=["-gdwarf-4"]) # clang dwarf-5 symbols are broken on Windows. env.AppendUnique(CCFLAGS=["-gdwarf-4"]) # clang dwarf-5 symbols are broken on Windows.
else: else:
env.Append(CCFLAGS=["-gdwarf-5"]) # For gcc, only dwarf-5 symbols seem usable by libbacktrace. env.AppendUnique(CCFLAGS=["-gdwarf-5"]) # For gcc, only dwarf-5 symbols seem usable by libbacktrace.
else: else:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds, # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them # otherwise addr2line doesn't understand them
env.Append(CCFLAGS=["-gdwarf-4"]) env.AppendUnique(CCFLAGS=["-gdwarf-4"])
if methods.using_emcc(env): if methods.using_emcc(env):
# Emscripten only produces dwarf symbols when using "-g3". # Emscripten only produces dwarf symbols when using "-g3".
env.Append(CCFLAGS=["-g3"]) env.AppendUnique(CCFLAGS=["-g3"])
# Emscripten linker needs debug symbols options too. # Emscripten linker needs debug symbols options too.
env.Append(LINKFLAGS=["-gdwarf-4"]) env.AppendUnique(LINKFLAGS=["-gdwarf-4"])
env.Append(LINKFLAGS=["-g3"]) env.AppendUnique(LINKFLAGS=["-g3"])
elif env.dev_build: elif env.dev_build:
env.Append(CCFLAGS=["-g3"]) env.AppendUnique(CCFLAGS=["-g3"])
else: else:
env.Append(CCFLAGS=["-g2"]) env.AppendUnique(CCFLAGS=["-g2"])
if env["debug_paths_relative"]: if env["debug_paths_relative"]:
# Remap absolute paths to relative paths for debug symbols. # Remap absolute paths to relative paths for debug symbols.
project_path = Dir("#").abspath project_path = Dir("#").abspath
env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."]) env.AppendUnique(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
else: else:
if methods.is_apple_clang(env): if methods.is_apple_clang(env):
# Apple Clang, its linker doesn't like -s. # Apple Clang, its linker doesn't like -s.
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) env.AppendUnique(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
else: else:
env.Append(LINKFLAGS=["-s"]) env.AppendUnique(LINKFLAGS=["-s"])
# Linker needs optimization flags too, at least for Emscripten. # Linker needs optimization flags too, at least for Emscripten.
# For other toolchains, this _may_ be useful for LTO too to disambiguate. # For other toolchains, this _may_ be useful for LTO too to disambiguate.
env.AppendUnique(LINKFLAGS=["$OPTIMIZELEVEL"])
if env["optimize"] == "speed": if env["optimize"] == "speed":
env.Append(CCFLAGS=["-O3"]) env["OPTIMIZELEVEL"] = "-O3"
env.Append(LINKFLAGS=["-O3"])
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
elif env["optimize"] == "speed_trace": elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["-O2"]) env["OPTIMIZELEVEL"] = "-O2"
env.Append(LINKFLAGS=["-O2"]) elif env["optimize"].startswith("size"):
elif env["optimize"] == "size": env["OPTIMIZELEVEL"] = "-Os"
env.Append(CCFLAGS=["-Os"]) if env["optimize"] == "size_extra":
env.Append(LINKFLAGS=["-Os"]) env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"])
elif env["optimize"] == "debug": elif env["optimize"] == "debug":
env.Append(CCFLAGS=["-Og"]) env["OPTIMIZELEVEL"] = "-Og"
env.Append(LINKFLAGS=["-Og"])
elif env["optimize"] == "none": elif env["optimize"] == "none":
env.Append(CCFLAGS=["-O0"]) env["OPTIMIZELEVEL"] = "-O0"
env.Append(LINKFLAGS=["-O0"])
# Needs to happen after configure to handle "auto". # Needs to happen after configure to handle "auto".
if env["lto"] != "none": if env["lto"] != "none":
@ -813,6 +837,7 @@ elif env.msvc:
env.Append(CXXFLAGS=["/EHsc"]) env.Append(CXXFLAGS=["/EHsc"])
# Configure compiler warnings # Configure compiler warnings
env.AppendUnique(CCFLAGS=["$WARNLEVEL"])
if env.msvc and not methods.using_clang(env): # MSVC if env.msvc and not methods.using_clang(env): # MSVC
# Disable warnings which we don't plan to fix. # Disable warnings which we don't plan to fix.
disabled_warnings = [ disabled_warnings = [
@ -830,19 +855,23 @@ if env.msvc and not methods.using_clang(env): # MSVC
] ]
if env["warnings"] == "extra": if env["warnings"] == "extra":
env.Append(CCFLAGS=["/W4"] + disabled_warnings) env["WARNLEVEL"] = "/W4"
env.AppendUnique(CCFLAGS=disabled_warnings)
elif env["warnings"] == "all": elif env["warnings"] == "all":
env["WARNLEVEL"] = "/W3"
# C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too. # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too.
env.Append(CCFLAGS=["/W3", "/w34458"] + disabled_warnings) env.AppendUnique(CCFLAGS=["/w34458"] + disabled_warnings)
elif env["warnings"] == "moderate": elif env["warnings"] == "moderate":
env.Append(CCFLAGS=["/W2"] + disabled_warnings) env["WARNLEVEL"] = "/W2"
env.AppendUnique(CCFLAGS=disabled_warnings)
else: # 'no' else: # 'no'
env["WARNLEVEL"] = "/w"
# C4267 is particularly finicky & needs to be explicitly disabled. # C4267 is particularly finicky & needs to be explicitly disabled.
env.Append(CCFLAGS=["/w", "/wd4267"]) env.AppendUnique(CCFLAGS=["/wd4267"])
if env["werror"]: if env["werror"]:
env.Append(CCFLAGS=["/WX"]) env.AppendUnique(CCFLAGS=["/WX"])
env.Append(LINKFLAGS=["/WX"]) env.AppendUnique(LINKFLAGS=["/WX"])
else: # GCC, Clang else: # GCC, Clang
common_warnings = [] common_warnings = []
@ -861,14 +890,14 @@ else: # GCC, Clang
# for putting them in `Set` or `Map`. We don't mind about unreliable ordering. # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
common_warnings += ["-Wno-ordered-compare-function-pointers"] common_warnings += ["-Wno-ordered-compare-function-pointers"]
# clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast # clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast.
W_ALL = "-Wall" if not env.msvc else "-W3" env["WARNLEVEL"] = "-Wall" if not env.msvc else "-W3"
if env["warnings"] == "extra": if env["warnings"] == "extra":
env.Append(CCFLAGS=[W_ALL, "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) env.AppendUnique(CCFLAGS=["-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) env.AppendUnique(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
if methods.using_gcc(env): if methods.using_gcc(env):
env.Append( env.AppendUnique(
CCFLAGS=[ CCFLAGS=[
"-Walloc-zero", "-Walloc-zero",
"-Wduplicated-branches", "-Wduplicated-branches",
@ -876,25 +905,38 @@ else: # GCC, Clang
"-Wstringop-overflow=4", "-Wstringop-overflow=4",
] ]
) )
env.Append(CXXFLAGS=["-Wplacement-new=1"]) env.AppendUnique(CXXFLAGS=["-Wplacement-new=1", "-Wvirtual-inheritance"])
# Need to fix a warning with AudioServer lambdas before enabling. # Need to fix a warning with AudioServer lambdas before enabling.
# if cc_version_major != 9: # GCC 9 had a regression (GH-36325). # if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
# env.Append(CXXFLAGS=["-Wnoexcept"]) # env.Append(CXXFLAGS=["-Wnoexcept"])
if cc_version_major >= 9: if cc_version_major >= 9:
env.Append(CCFLAGS=["-Wattribute-alias=2"]) env.AppendUnique(CCFLAGS=["-Wattribute-alias=2"])
if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11. if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11.
env.Append(CCFLAGS=["-Wlogical-op"]) env.AppendUnique(CCFLAGS=["-Wlogical-op"])
elif methods.using_clang(env) or methods.using_emcc(env): elif methods.using_clang(env) or methods.using_emcc(env):
env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) env.AppendUnique(CCFLAGS=["-Wimplicit-fallthrough"])
elif env["warnings"] == "all": elif env["warnings"] == "all":
env.Append(CCFLAGS=[W_ALL] + common_warnings) env.AppendUnique(CCFLAGS=common_warnings)
elif env["warnings"] == "moderate": elif env["warnings"] == "moderate":
env.Append(CCFLAGS=[W_ALL, "-Wno-unused"] + common_warnings) env.AppendUnique(CCFLAGS=["-Wno-unused"] + common_warnings)
else: # 'no' else: # 'no'
env.Append(CCFLAGS=["-w"]) env["WARNLEVEL"] = "-w"
if env["werror"]: if env["werror"]:
env.Append(CCFLAGS=["-Werror"]) env.AppendUnique(CCFLAGS=["-Werror"])
# Configure external includes.
if env.msvc:
if not methods.using_clang(env):
if cc_version_major < 16 or (cc_version_major == 16 and cc_version_minor < 10):
env.AppendUnique(CCFLAGS=["/experimental:external"])
env.AppendUnique(CCFLAGS=["/external:anglebrackets"])
env.AppendUnique(CCFLAGS=["/external:W0"])
env["EXTINCPREFIX"] = "/external:I"
env["EXTINCSUFFIX"] = ""
else:
env["EXTINCPREFIX"] = "-isystem "
env["EXTINCSUFFIX"] = ""
if hasattr(detect, "get_program_suffix"): if hasattr(detect, "get_program_suffix"):
suffix = "." + detect.get_program_suffix() suffix = "." + detect.get_program_suffix()
@ -918,6 +960,51 @@ suffix += env.extra_suffix
sys.path.remove(tmppath) sys.path.remove(tmppath)
sys.modules.pop("detect") sys.modules.pop("detect")
if env.editor_build:
unsupported_opts = []
for disable_opt in [
"disable_3d",
"disable_advanced_gui",
"disable_physics_2d",
"disable_physics_3d",
"disable_navigation_2d",
"disable_navigation_3d",
]:
if env[disable_opt]:
unsupported_opts.append(disable_opt)
if unsupported_opts != []:
print_error(
"The following build option(s) cannot be used for editor builds, but only for export template builds: {}.".format(
", ".join(unsupported_opts)
)
)
Exit(255)
if env["disable_3d"]:
env.Append(CPPDEFINES=["_3D_DISABLED"])
env["disable_navigation_3d"] = True
env["disable_physics_3d"] = True
env["disable_xr"] = True
if env["disable_advanced_gui"]:
env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"])
if env["disable_physics_2d"]:
env.Append(CPPDEFINES=["PHYSICS_2D_DISABLED"])
if env["disable_physics_3d"]:
env.Append(CPPDEFINES=["PHYSICS_3D_DISABLED"])
if env["disable_navigation_2d"]:
env.Append(CPPDEFINES=["NAVIGATION_2D_DISABLED"])
if env["disable_navigation_3d"]:
env.Append(CPPDEFINES=["NAVIGATION_3D_DISABLED"])
if env["disable_xr"]:
env.Append(CPPDEFINES=["XR_DISABLED"])
if env["minizip"]:
env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
if env["brotli"]:
env.Append(CPPDEFINES=["BROTLI_ENABLED"])
if not env["verbose"]:
methods.no_verbose(env)
modules_enabled = OrderedDict() modules_enabled = OrderedDict()
env.module_dependencies = {} env.module_dependencies = {}
env.module_icons_paths = [] env.module_icons_paths = []
@ -968,8 +1055,6 @@ if env.editor_build:
print_error("Not all modules required by editor builds are enabled.") print_error("Not all modules required by editor builds are enabled.")
Exit(255) Exit(255)
env.version_info = methods.get_version_info(env.module_version_string)
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"] env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"] env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
@ -989,28 +1074,6 @@ env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
env["OBJPREFIX"] = env["object_prefix"] env["OBJPREFIX"] = env["object_prefix"]
env["SHOBJPREFIX"] = env["object_prefix"] env["SHOBJPREFIX"] = env["object_prefix"]
if env["disable_3d"]:
if env.editor_build:
print_error("Build option `disable_3d=yes` cannot be used for editor builds, only for export template builds.")
Exit(255)
else:
env.Append(CPPDEFINES=["_3D_DISABLED"])
if env["disable_advanced_gui"]:
if env.editor_build:
print_error(
"Build option `disable_advanced_gui=yes` cannot be used for editor builds, only for export template builds."
)
Exit(255)
else:
env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"])
if env["minizip"]:
env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
if env["brotli"]:
env.Append(CPPDEFINES=["BROTLI_ENABLED"])
if not env["verbose"]:
methods.no_verbose(env)
GLSL_BUILDERS = { GLSL_BUILDERS = {
"RD_GLSL": env.Builder( "RD_GLSL": env.Builder(
action=env.Run(glsl_builders.build_rd_headers), action=env.Run(glsl_builders.build_rd_headers),
@ -1051,6 +1114,14 @@ if env["ninja"]:
if env["threads"]: if env["threads"]:
env.Append(CPPDEFINES=["THREADS_ENABLED"]) env.Append(CPPDEFINES=["THREADS_ENABLED"])
# Ensure build objects are put in their own folder if `redirect_build_objects` is enabled.
env.Prepend(LIBEMITTER=[methods.redirect_emitter])
env.Prepend(SHLIBEMITTER=[methods.redirect_emitter])
for key in (emitters := env.StaticObject.builder.emitter):
emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key]))
for key in (emitters := env.SharedObject.builder.emitter):
emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key]))
# Build subdirs, the build order is dependent on link order. # Build subdirs, the build order is dependent on link order.
Export("env") Export("env")
@ -1082,11 +1153,11 @@ if "check_c_headers" in env:
for header in headers: for header in headers:
if conf.CheckCHeader(header): if conf.CheckCHeader(header):
env.AppendUnique(CPPDEFINES=[headers[header]]) env.AppendUnique(CPPDEFINES=[headers[header]])
conf.Finish()
# Miscellaneous & post-build methods.
methods.show_progress(env) if not env.GetOption("clean") and not env.GetOption("help"):
# TODO: replace this with `env.Dump(format="json")` methods.dump(env)
# once we start requiring SCons 4.0 as min version. methods.show_progress(env)
methods.dump(env) methods.prepare_purge(env)
methods.prepare_purge(env) methods.prepare_timer()
methods.prepare_timer()

View file

@ -51,8 +51,8 @@ if env["brotli"] and env["builtin_brotli"]:
] ]
thirdparty_brotli_sources = [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] thirdparty_brotli_sources = [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
env_thirdparty.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_brotli_dir + "include"])
env.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) env.Prepend(CPPEXTPATH=[thirdparty_brotli_dir + "include"])
if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"): if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"]) env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
@ -69,8 +69,8 @@ if env["builtin_clipper2"]:
] ]
thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources] thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources]
env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"]) env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"])
env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"]) env.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"])
env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"]) env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
env.Append(CPPDEFINES=["CLIPPER2_ENABLED"]) env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
@ -94,9 +94,9 @@ if env["builtin_zlib"]:
] ]
thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir]) env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too # Needs to be available in main env too
env.Prepend(CPPPATH=[thirdparty_zlib_dir]) env.Prepend(CPPEXTPATH=[thirdparty_zlib_dir])
if env.dev_build: if env.dev_build:
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"]) env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
# Affects headers so it should also be defined for Godot code # Affects headers so it should also be defined for Godot code
@ -148,9 +148,9 @@ if env["builtin_zstd"]:
thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S") thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources] thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"]) env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"]) env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
env.Prepend(CPPPATH=thirdparty_zstd_dir) env.Prepend(CPPEXTPATH=thirdparty_zstd_dir)
# Also needed in main env includes will trigger warnings # Also needed in main env includes will trigger warnings
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"]) env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
@ -167,10 +167,9 @@ env.add_source_files(env.core_sources, "*.cpp")
# Generate disabled classes # Generate disabled classes
def disabled_class_builder(target, source, env): def disabled_class_builder(target, source, env):
with methods.generated_wrapper(target) as file: with methods.generated_wrapper(str(target[0])) as file:
for c in source[0].read(): for c in source[0].read():
cs = c.strip() if cs := c.strip():
if cs != "":
file.write(f"#define ClassDB_Disable_{cs} 1\n") file.write(f"#define ClassDB_Disable_{cs} 1\n")
@ -179,49 +178,51 @@ env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), en
# Generate version info # Generate version info
def version_info_builder(target, source, env): def version_info_builder(target, source, env):
with methods.generated_wrapper(target) as file: with methods.generated_wrapper(str(target[0])) as file:
file.write( file.write(
"""\ """\
#define VERSION_SHORT_NAME "{short_name}" #define GODOT_VERSION_SHORT_NAME "{short_name}"
#define VERSION_NAME "{name}" #define GODOT_VERSION_NAME "{name}"
#define VERSION_MAJOR {major} #define GODOT_VERSION_MAJOR {major}
#define VERSION_MINOR {minor} #define GODOT_VERSION_MINOR {minor}
#define VERSION_PATCH {patch} #define GODOT_VERSION_PATCH {patch}
#define VERSION_STATUS "{status}" #define GODOT_VERSION_STATUS "{status}"
#define VERSION_BUILD "{build}" #define GODOT_VERSION_BUILD "{build}"
#define VERSION_MODULE_CONFIG "{module_config}" #define GODOT_VERSION_MODULE_CONFIG "{module_config}"
#define VERSION_WEBSITE "{website}" #define GODOT_VERSION_WEBSITE "{website}"
#define VERSION_DOCS_BRANCH "{docs_branch}" #define GODOT_VERSION_DOCS_BRANCH "{docs_branch}"
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH #define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH
""".format(**env.version_info) """.format(**source[0].read())
) )
env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder)) env.CommandNoCache(
"version_generated.gen.h",
env.Value(methods.get_version_info(env.module_version_string)),
env.Run(version_info_builder),
)
# Generate version hash # Generate version hash
def version_hash_builder(target, source, env): def version_hash_builder(target, source, env):
with methods.generated_wrapper(target) as file: with methods.generated_wrapper(str(target[0])) as file:
file.write( file.write(
"""\ """\
#include "core/version.h" #include "core/version.h"
const char *const VERSION_HASH = "{git_hash}"; const char *const GODOT_VERSION_HASH = "{git_hash}";
const uint64_t VERSION_TIMESTAMP = {git_timestamp}; const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
""".format(**env.version_info) """.format(**source[0].read())
) )
gen_hash = env.CommandNoCache( gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder))
"version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
)
env.add_source_files(env.core_sources, gen_hash) env.add_source_files(env.core_sources, gen_hash)
# Generate AES256 script encryption key # Generate AES256 script encryption key
def encryption_key_builder(target, source, env): def encryption_key_builder(target, source, env):
with methods.generated_wrapper(target) as file: with methods.generated_wrapper(str(target[0])) as file:
file.write( file.write(
f"""\ f"""\
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
@ -251,30 +252,21 @@ env.add_source_files(env.core_sources, gen_encrypt)
# Certificates # Certificates
env.Depends(
"#core/io/certs_compressed.gen.h",
["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
)
env.CommandNoCache( env.CommandNoCache(
"#core/io/certs_compressed.gen.h", "#core/io/certs_compressed.gen.h",
"#thirdparty/certs/ca-certificates.crt", ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
env.Run(core_builders.make_certs_header), env.Run(core_builders.make_certs_header),
) )
# Authors # Authors
env.Depends("#core/authors.gen.h", "../AUTHORS.md") env.CommandNoCache("#core/authors.gen.h", "#AUTHORS.md", env.Run(core_builders.make_authors_header))
env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header))
# Donors # Donors
env.Depends("#core/donors.gen.h", "../DONORS.md") env.CommandNoCache("#core/donors.gen.h", "#DONORS.md", env.Run(core_builders.make_donors_header))
env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header))
# License # License
env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
env.CommandNoCache( env.CommandNoCache(
"#core/license.gen.h", "#core/license.gen.h", ["#COPYRIGHT.txt", "#LICENSE.txt"], env.Run(core_builders.make_license_header)
["../COPYRIGHT.txt", "../LICENSE.txt"],
env.Run(core_builders.make_license_header),
) )
# Chain load SCsubs # Chain load SCsubs

View file

@ -125,17 +125,17 @@ double Engine::get_unfrozen_time_scale() const {
Dictionary Engine::get_version_info() const { Dictionary Engine::get_version_info() const {
Dictionary dict; Dictionary dict;
dict["major"] = VERSION_MAJOR; dict["major"] = GODOT_VERSION_MAJOR;
dict["minor"] = VERSION_MINOR; dict["minor"] = GODOT_VERSION_MINOR;
dict["patch"] = VERSION_PATCH; dict["patch"] = GODOT_VERSION_PATCH;
dict["hex"] = VERSION_HEX; dict["hex"] = GODOT_VERSION_HEX;
dict["status"] = VERSION_STATUS; dict["status"] = GODOT_VERSION_STATUS;
dict["build"] = VERSION_BUILD; dict["build"] = GODOT_VERSION_BUILD;
String hash = String(VERSION_HASH); String hash = String(GODOT_VERSION_HASH);
dict["hash"] = hash.is_empty() ? String("unknown") : hash; dict["hash"] = hash.is_empty() ? String("unknown") : hash;
dict["timestamp"] = VERSION_TIMESTAMP; dict["timestamp"] = GODOT_VERSION_TIMESTAMP;
String stringver = String(dict["major"]) + "." + String(dict["minor"]); String stringver = String(dict["major"]) + "." + String(dict["minor"]);
if ((int)dict["patch"] != 0) { if ((int)dict["patch"] != 0) {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef ENGINE_H #pragma once
#define ENGINE_H
#include "core/os/main_loop.h" #include "core/os/main_loop.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -214,5 +213,3 @@ public:
Engine(); Engine();
virtual ~Engine(); virtual ~Engine();
}; };
#endif // ENGINE_H

View file

@ -77,7 +77,7 @@ String ProjectSettings::get_imported_files_path() const {
// This is used by the project manager to provide the initial_settings for config/features. // This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() { const PackedStringArray ProjectSettings::get_required_features() {
PackedStringArray features; PackedStringArray features;
features.append(VERSION_BRANCH); features.append(GODOT_VERSION_BRANCH);
#ifdef REAL_T_IS_DOUBLE #ifdef REAL_T_IS_DOUBLE
features.append("Double Precision"); features.append("Double Precision");
#endif #endif
@ -92,9 +92,9 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
#endif #endif
// Allow pinning to a specific patch number or build type by marking // Allow pinning to a specific patch number or build type by marking
// them as supported. They're only used if the user adds them manually. // them as supported. They're only used if the user adds them manually.
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH)); features.append(GODOT_VERSION_BRANCH "." _MKSTR(GODOT_VERSION_PATCH));
features.append(VERSION_FULL_CONFIG); features.append(GODOT_VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD); features.append(GODOT_VERSION_FULL_BUILD);
#ifdef RD_ENABLED #ifdef RD_ENABLED
features.append("Forward Plus"); features.append("Forward Plus");
@ -173,7 +173,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
if (dir->change_dir(path) == OK) { if (dir->change_dir(path) == OK) {
String cwd = dir->get_current_dir(); String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/"); cwd = cwd.replace_char('\\', '/');
// Ensure that we end with a '/'. // Ensure that we end with a '/'.
// This is important to ensure that we do not wrongly localize the resource path // This is important to ensure that we do not wrongly localize the resource path
@ -208,7 +208,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
if (plocal[plocal.length() - 1] == '/') { if (plocal[plocal.length() - 1] == '/') {
sep += 1; sep += 1;
} }
return plocal + path.substr(sep, path.size() - sep); return plocal + path.substr(sep);
} }
} }
@ -289,7 +289,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
remove_autoload(node_name); remove_autoload(node_name);
} }
} else if (p_name.operator String().begins_with("global_group/")) { } else if (p_name.operator String().begins_with("global_group/")) {
String group_name = p_name.operator String().get_slice("/", 1); String group_name = p_name.operator String().get_slicec('/', 1);
if (global_groups.has(group_name)) { if (global_groups.has(group_name)) {
remove_global_group(group_name); remove_global_group(group_name);
} }
@ -340,7 +340,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
} }
add_autoload(autoload); add_autoload(autoload);
} else if (p_name.operator String().begins_with("global_group/")) { } else if (p_name.operator String().begins_with("global_group/")) {
String group_name = p_name.operator String().get_slice("/", 1); String group_name = p_name.operator String().get_slicec('/', 1);
add_global_group(group_name, p_value); add_global_group(group_name, p_value);
} }
} }
@ -359,14 +359,14 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
return true; return true;
} }
Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const { Variant ProjectSettings::get_setting_with_override_and_custom_features(const StringName &p_name, const Vector<String> &p_features) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
StringName name = p_name; StringName name = p_name;
if (feature_overrides.has(name)) { if (feature_overrides.has(name)) {
const LocalVector<Pair<StringName, StringName>> &overrides = feature_overrides[name]; const LocalVector<Pair<StringName, StringName>> &overrides = feature_overrides[name];
for (uint32_t i = 0; i < overrides.size(); i++) { for (uint32_t i = 0; i < overrides.size(); i++) {
if (OS::get_singleton()->has_feature(overrides[i].first)) { // Custom features are checked in OS.has_feature() already. No need to check twice. if (p_features.has(String(overrides[i].first).to_lower())) {
if (props.has(overrides[i].second)) { if (props.has(overrides[i].second)) {
name = overrides[i].second; name = overrides[i].second;
break; break;
@ -376,12 +376,39 @@ Variant ProjectSettings::get_setting_with_override(const StringName &p_name) con
} }
if (!props.has(name)) { if (!props.has(name)) {
WARN_PRINT(vformat("Property not found: '%s'.", String(name))); WARN_PRINT("Property not found: " + String(name));
return Variant(); return Variant();
} }
return props[name].variant; return props[name].variant;
} }
Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const {
_THREAD_SAFE_METHOD_
const LocalVector<Pair<StringName, StringName>> *overrides = feature_overrides.getptr(p_name);
if (overrides) {
for (uint32_t i = 0; i < overrides->size(); i++) {
if (!OS::get_singleton()->has_feature((*overrides)[i].first)) {
continue;
}
// Custom features are checked in OS.has_feature() already. No need to check twice.
const RBMap<StringName, VariantContainer>::Element *override_prop = props.find((*overrides)[i].second);
if (override_prop) {
return override_prop->get().variant;
}
}
}
const RBMap<StringName, VariantContainer>::Element *prop = props.find(p_name);
if (!prop) {
WARN_PRINT(vformat("Property not found: '%s'.", p_name));
return Variant();
}
return prop->get().variant;
}
struct _VCSort { struct _VCSort {
String name; String name;
Variant::Type type = Variant::VARIANT_MAX; Variant::Type type = Variant::VARIANT_MAX;
@ -564,7 +591,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (!OS::get_singleton()->get_resource_dir().is_empty()) { if (!OS::get_singleton()->get_resource_dir().is_empty()) {
// OS will call ProjectSettings->get_resource_path which will be empty if not overridden! // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
// If the OS would rather use a specific location, then it will not be empty. // If the OS would rather use a specific location, then it will not be empty.
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); resource_path = OS::get_singleton()->get_resource_dir().replace_char('\\', '/');
if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') { if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
} }
@ -685,7 +712,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
while (true) { while (true) {
// Set the resource path early so things can be resolved when loading. // Set the resource path early so things can be resolved when loading.
resource_path = current_dir; resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case. resource_path = resource_path.replace_char('\\', '/'); // Windows path to Unix path just in case.
err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary")); err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
if (err == OK && !p_ignore_override) { if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails. // Optional, we don't mind if it fails.
@ -770,8 +797,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
cs.resize(slen + 1); cs.resize(slen + 1);
cs[slen] = 0; cs[slen] = 0;
f->get_buffer((uint8_t *)cs.ptr(), slen); f->get_buffer((uint8_t *)cs.ptr(), slen);
String key; String key = String::utf8(cs.ptr(), slen);
key.parse_utf8(cs.ptr(), slen);
uint32_t vlen = f->get_32(); uint32_t vlen = f->get_32();
Vector<uint8_t> d; Vector<uint8_t> d;
@ -1129,7 +1155,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
category = ""; category = "";
} else { } else {
category = category.substr(0, div); category = category.substr(0, div);
name = name.substr(div + 1, name.size()); name = name.substr(div + 1);
} }
save_props[category].push_back(name); save_props[category].push_back(name);
} }
@ -1141,7 +1167,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
save_features += ","; save_features += ",";
} }
String f = p_custom_features[i].strip_edges().replace("\"", ""); String f = p_custom_features[i].strip_edges().remove_char('\"');
save_features += f; save_features += f;
} }
@ -1408,6 +1434,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("get_setting_with_override", "name"), &ProjectSettings::get_setting_with_override); ClassDB::bind_method(D_METHOD("get_setting_with_override", "name"), &ProjectSettings::get_setting_with_override);
ClassDB::bind_method(D_METHOD("get_global_class_list"), &ProjectSettings::get_global_class_list); ClassDB::bind_method(D_METHOD("get_global_class_list"), &ProjectSettings::get_global_class_list);
ClassDB::bind_method(D_METHOD("get_setting_with_override_and_custom_features", "name", "features"), &ProjectSettings::get_setting_with_override_and_custom_features);
ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order); ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order);
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
@ -1434,8 +1461,8 @@ void ProjectSettings::_add_builtin_input_map() {
Array events; Array events;
// Convert list of input events into array // Convert list of input events into array
for (List<Ref<InputEvent>>::Element *I = E.value.front(); I; I = I->next()) { for (const Ref<InputEvent> &event : E.value) {
events.push_back(I->get()); events.push_back(event);
} }
Dictionary action; Dictionary action;
@ -1488,6 +1515,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/auto_accept_quit", true); GLOBAL_DEF("application/config/auto_accept_quit", true);
GLOBAL_DEF("application/config/quit_on_go_back", true); GLOBAL_DEF("application/config/quit_on_go_back", true);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/accessibility_support", PROPERTY_HINT_ENUM, "Auto (When Screen Reader is Running),Always Active,Disabled"), 0);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/updates_per_second", PROPERTY_HINT_RANGE, "1,100,1"), 60);
// The default window size is tuned to: // The default window size is tuned to:
// - Have a 16:9 aspect ratio, // - Have a 16:9 aspect ratio,
// - Have both dimensions divisible by 8 to better play along with video recording, // - Have both dimensions divisible by 8 to better play along with video recording,
@ -1497,9 +1527,10 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0);
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum. // Keep the enum values in sync with the `Window::WINDOW_INITIAL_POSITION_` enum.
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute,Center of Primary Screen,Center of Other Screen,Center of Screen With Mouse Pointer,Center of Screen With Keyboard Focus"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute:0,Center of Primary Screen:1,Center of Other Screen:3,Center of Screen With Mouse Pointer:4,Center of Screen With Keyboard Focus:5"), 1);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::VECTOR2I, "display/window/size/initial_position"), Vector2i()); GLOBAL_DEF_BASIC(PropertyInfo(Variant::VECTOR2I, "display/window/size/initial_position"), Vector2i());
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), 0); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), 0);
GLOBAL_DEF_BASIC("display/window/size/resizable", true); GLOBAL_DEF_BASIC("display/window/size/resizable", true);
@ -1509,6 +1540,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/extend_to_title", false);
GLOBAL_DEF("display/window/size/no_focus", false); GLOBAL_DEF("display/window/size/no_focus", false);
GLOBAL_DEF("display/window/size/sharp_corners", false); 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(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_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(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
@ -1543,8 +1576,13 @@ ProjectSettings::ProjectSettings() {
#else #else
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate"); custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate");
#endif #endif
#ifndef PHYSICS_2D_DISABLED
GLOBAL_DEF("physics/2d/run_on_separate_thread", false); GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
GLOBAL_DEF("physics/3d/run_on_separate_thread", false); GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
#endif // PHYSICS_3D_DISABLED
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"), "disabled"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"), "disabled");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"), "keep"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"), "keep");
@ -1612,6 +1650,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false); GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false); GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
GLOBAL_DEF("input_devices/pointing/android/override_volume_buttons", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/disable_scroll_deadzone", false);
// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix(). // These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray()); GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
@ -1620,6 +1660,19 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false); GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false);
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
GLOBAL_DEF("navigation/world/map_use_async_iterations", true);
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true);
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true);
GLOBAL_DEF("navigation/pathfinding/max_threads", 4);
GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true);
#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
ProjectSettings::get_singleton()->add_hidden_prefix("input/"); ProjectSettings::get_singleton()->add_hidden_prefix("input/");
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef PROJECT_SETTINGS_H #pragma once
#define PROJECT_SETTINGS_H
#include "core/object/class_db.h" #include "core/object/class_db.h"
@ -194,6 +193,7 @@ public:
List<String> get_input_presets() const { return input_presets; } List<String> get_input_presets() const { return input_presets; }
Variant get_setting_with_override(const StringName &p_name) const; Variant get_setting_with_override(const StringName &p_name) const;
Variant get_setting_with_override_and_custom_features(const StringName &p_name, const Vector<String> &p_features) const;
bool is_using_datapack() const; bool is_using_datapack() const;
bool is_project_loaded() const; bool is_project_loaded() const;
@ -243,5 +243,3 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p
#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true) #define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
#define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true) #define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true)
#endif // PROJECT_SETTINGS_H

View file

@ -30,7 +30,7 @@
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
namespace core_bind { namespace CoreBind {
// Semaphore // Semaphore
@ -53,10 +53,12 @@ Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const
} }
void OS::_bind_compatibility_methods() { void OS::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin);
ClassDB::bind_compatibility_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201); ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434); ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
} }
} // namespace core_bind } // namespace CoreBind
#endif // DISABLE_DEPRECATED #endif // DISABLE_DEPRECATED

View file

@ -42,7 +42,7 @@
#include "core/os/thread_safe.h" #include "core/os/thread_safe.h"
#include "core/variant/typed_array.h" #include "core/variant/typed_array.h"
namespace core_bind { namespace CoreBind {
////// ResourceLoader ////// ////// ResourceLoader //////
@ -466,8 +466,8 @@ bool OS::is_restart_on_exit_set() const {
Vector<String> OS::get_restart_on_exit_arguments() const { Vector<String> OS::get_restart_on_exit_arguments() const {
List<String> args = ::OS::get_singleton()->get_restart_on_exit_arguments(); List<String> args = ::OS::get_singleton()->get_restart_on_exit_arguments();
Vector<String> args_vector; Vector<String> args_vector;
for (List<String>::Element *E = args.front(); E; E = E->next()) { for (const String &arg : args) {
args_vector.push_back(E->get()); args_vector.push_back(arg);
} }
return args_vector; return args_vector;
@ -657,8 +657,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin); ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin, DEFVAL(1024));
ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin); ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin, DEFVAL(1024));
ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type); ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type);
ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type); ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type);
ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type); ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type);
@ -806,13 +806,11 @@ Vector<Vector2> Geometry2D::get_closest_points_between_segments(const Vector2 &p
} }
Vector2 Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) {
Vector2 s[2] = { p_a, p_b }; return ::Geometry2D::get_closest_point_to_segment(p_point, p_a, p_b);
return ::Geometry2D::get_closest_point_to_segment(p_point, s);
} }
Vector2 Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) {
Vector2 s[2] = { p_a, p_b }; return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, s);
} }
bool Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const { bool Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const {
@ -1069,13 +1067,11 @@ Vector<Vector3> Geometry3D::get_closest_points_between_segments(const Vector3 &p
} }
Vector3 Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { Vector3 Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) {
Vector3 s[2] = { p_a, p_b }; return ::Geometry3D::get_closest_point_to_segment(p_point, p_a, p_b);
return ::Geometry3D::get_closest_point_to_segment(p_point, s);
} }
Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) {
Vector3 s[2] = { p_a, p_b }; return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, s);
} }
Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) {
@ -1241,6 +1237,9 @@ Vector<uint8_t> Marshalls::base64_to_raw(const String &p_str) {
} }
String Marshalls::utf8_to_base64(const String &p_str) { String Marshalls::utf8_to_base64(const String &p_str) {
if (p_str.is_empty()) {
return String();
}
CharString cstr = p_str.utf8(); CharString cstr = p_str.utf8();
String ret = CryptoCore::b64_encode_str((unsigned char *)cstr.get_data(), cstr.length()); String ret = CryptoCore::b64_encode_str((unsigned char *)cstr.get_data(), cstr.length());
ERR_FAIL_COND_V(ret.is_empty(), ret); ERR_FAIL_COND_V(ret.is_empty(), ret);
@ -1340,6 +1339,7 @@ void Thread::_start_func(void *ud) {
// When the call returns, we will reference the thread again if possible. // When the call returns, we will reference the thread again if possible.
ObjectID th_instance_id = t->get_instance_id(); ObjectID th_instance_id = t->get_instance_id();
Callable target_callable = t->target_callable; Callable target_callable = t->target_callable;
String id = t->get_id();
t = Ref<Thread>(); t = Ref<Thread>();
Callable::CallError ce; Callable::CallError ce;
@ -1347,7 +1347,7 @@ void Thread::_start_func(void *ud) {
target_callable.callp(nullptr, 0, ret, ce); target_callable.callp(nullptr, 0, ret, ce);
// If script properly kept a reference to the thread, we should be able to re-reference it now // If script properly kept a reference to the thread, we should be able to re-reference it now
// (well, or if the call failed, since we had to break chains anyway because the outcome isn't known upfront). // (well, or if the call failed, since we had to break chains anyway because the outcome isn't known upfront).
t = Ref<Thread>(ObjectDB::get_instance(th_instance_id)); t = ObjectDB::get_ref<Thread>(th_instance_id);
if (t.is_valid()) { if (t.is_valid()) {
t->ret = ret; t->ret = ret;
t->running.clear(); t->running.clear();
@ -1357,7 +1357,7 @@ void Thread::_start_func(void *ud) {
} }
if (ce.error != Callable::CallError::CALL_OK) { if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %d: %s.", func_name, t->get_id(), Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce))); ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %s: %s.", func_name, id, Variant::get_callable_error_text(target_callable, nullptr, 0, ce)));
} }
} }
@ -1419,7 +1419,7 @@ void Thread::_bind_methods() {
BIND_ENUM_CONSTANT(PRIORITY_HIGH); BIND_ENUM_CONSTANT(PRIORITY_HIGH);
} }
namespace special { namespace Special {
////// ClassDB ////// ////// ClassDB //////
@ -1438,8 +1438,8 @@ PackedStringArray ClassDB::get_class_list() const {
} }
PackedStringArray ClassDB::get_inheriters_from_class(const StringName &p_class) const { PackedStringArray ClassDB::get_inheriters_from_class(const StringName &p_class) const {
List<StringName> classes; LocalVector<StringName> classes;
::ClassDB::get_inheriters_from_class(p_class, &classes); ::ClassDB::get_inheriters_from_class(p_class, classes);
PackedStringArray ret; PackedStringArray ret;
ret.resize(classes.size()); ret.resize(classes.size());
@ -1746,7 +1746,7 @@ void ClassDB::_bind_methods() {
BIND_ENUM_CONSTANT(API_NONE); BIND_ENUM_CONSTANT(API_NONE);
} }
} // namespace special } // namespace Special
////// Engine ////// ////// Engine //////
@ -1876,8 +1876,8 @@ Vector<String> Engine::get_singleton_list() const {
List<::Engine::Singleton> singletons; List<::Engine::Singleton> singletons;
::Engine::get_singleton()->get_singletons(&singletons); ::Engine::get_singleton()->get_singletons(&singletons);
Vector<String> ret; Vector<String> ret;
for (List<::Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { for (const ::Engine::Singleton &E : singletons) {
ret.push_back(E->get().name); ret.push_back(E.name);
} }
return ret; return ret;
} }
@ -2190,4 +2190,4 @@ void EngineDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_breakpoints"), &EngineDebugger::clear_breakpoints); ClassDB::bind_method(D_METHOD("clear_breakpoints"), &EngineDebugger::clear_breakpoints);
} }
} // namespace core_bind } // namespace CoreBind

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CORE_BIND_H #pragma once
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h" #include "core/debugger/engine_profiler.h"
#include "core/io/resource_loader.h" #include "core/io/resource_loader.h"
@ -42,7 +41,7 @@ class MainLoop;
template <typename T> template <typename T>
class TypedArray; class TypedArray;
namespace core_bind { namespace CoreBind {
class ResourceLoader : public Object { class ResourceLoader : public Object {
GDCLASS(ResourceLoader, Object); GDCLASS(ResourceLoader, Object);
@ -458,7 +457,7 @@ public:
static void set_thread_safety_checks_enabled(bool p_enabled); static void set_thread_safety_checks_enabled(bool p_enabled);
}; };
namespace special { namespace Special {
class ClassDB : public Object { class ClassDB : public Object {
GDCLASS(ClassDB, Object); GDCLASS(ClassDB, Object);
@ -524,7 +523,7 @@ public:
~ClassDB() {} ~ClassDB() {}
}; };
} // namespace special } // namespace Special
class Engine : public Object { class Engine : public Object {
GDCLASS(Engine, Object); GDCLASS(Engine, Object);
@ -652,23 +651,21 @@ public:
~EngineDebugger(); ~EngineDebugger();
}; };
} // namespace core_bind } // namespace CoreBind
VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus); VARIANT_ENUM_CAST(CoreBind::ResourceLoader::ThreadLoadStatus);
VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode); VARIANT_ENUM_CAST(CoreBind::ResourceLoader::CacheMode);
VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); VARIANT_BITFIELD_CAST(CoreBind::ResourceSaver::SaverFlags);
VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver); VARIANT_ENUM_CAST(CoreBind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir); VARIANT_ENUM_CAST(CoreBind::OS::SystemDir);
VARIANT_ENUM_CAST(core_bind::OS::StdHandleType); VARIANT_ENUM_CAST(CoreBind::OS::StdHandleType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation); VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType); VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyEndType);
VARIANT_ENUM_CAST(core_bind::Thread::Priority); VARIANT_ENUM_CAST(CoreBind::Thread::Priority);
VARIANT_ENUM_CAST(core_bind::special::ClassDB::APIType); VARIANT_ENUM_CAST(CoreBind::Special::ClassDB::APIType);
#endif // CORE_BIND_H

View file

@ -1,171 +1,104 @@
"""Functions used to generate source files during build time""" """Functions used to generate source files during build time"""
import zlib from collections import OrderedDict
from io import TextIOWrapper
import methods
def escape_string(s):
def charcode_to_c_escapes(c):
rev_result = []
while c >= 256:
c, low = (c // 256, c % 256)
rev_result.append("\\%03o" % low)
rev_result.append("\\%03o" % c)
return "".join(reversed(rev_result))
result = ""
if isinstance(s, str):
s = s.encode("utf-8")
for c in s:
if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
result += charcode_to_c_escapes(c)
else:
result += chr(c)
return result
def make_certs_header(target, source, env): def make_certs_header(target, source, env):
src = str(source[0]) buffer = methods.get_buffer(str(source[0]))
dst = str(target[0]) decomp_size = len(buffer)
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: buffer = methods.compress_buffer(buffer)
buf = f.read()
decomp_size = len(buf)
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
g.write("#define CERTS_COMPRESSED_GEN_H\n")
with methods.generated_wrapper(str(target[0])) as file:
# System certs path. Editor will use them if defined. (for package maintainers) # System certs path. Editor will use them if defined. (for package maintainers)
path = env["system_certs_path"] file.write('#define _SYSTEM_CERTS_PATH "{}"\n'.format(env["system_certs_path"]))
g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
if env["builtin_certs"]: if env["builtin_certs"]:
# Defined here and not in env so changing it does not trigger a full rebuild. # Defined here and not in env so changing it does not trigger a full rebuild.
g.write("#define BUILTIN_CERTS_ENABLED\n") file.write(f"""\
g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") #define BUILTIN_CERTS_ENABLED
g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const unsigned char _certs_compressed[] = {\n") inline constexpr int _certs_compressed_size = {len(buffer)};
for i in range(len(buf)): inline constexpr int _certs_uncompressed_size = {decomp_size};
g.write("\t" + str(buf[i]) + ",\n") inline constexpr unsigned char _certs_compressed[] = {{
g.write("};\n") {methods.format_buffer(buffer, 1)}
g.write("#endif // CERTS_COMPRESSED_GEN_H") }};
""")
def make_authors_header(target, source, env): def make_authors_header(target, source, env):
sections = [ SECTIONS = {
"Project Founders", "Project Founders": "AUTHORS_FOUNDERS",
"Lead Developer", "Lead Developer": "AUTHORS_LEAD_DEVELOPERS",
"Project Manager", "Project Manager": "AUTHORS_PROJECT_MANAGERS",
"Developers", "Developers": "AUTHORS_DEVELOPERS",
] }
sections_id = [ buffer = methods.get_buffer(str(source[0]))
"AUTHORS_FOUNDERS", reading = False
"AUTHORS_LEAD_DEVELOPERS",
"AUTHORS_PROJECT_MANAGERS",
"AUTHORS_DEVELOPERS",
]
src = str(source[0]) with methods.generated_wrapper(str(target[0])) as file:
dst = str(target[0])
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef AUTHORS_GEN_H\n")
g.write("#define AUTHORS_GEN_H\n")
reading = False
def close_section(): def close_section():
g.write("\t0\n") file.write("\tnullptr,\n};\n\n")
g.write("};\n")
for line in f: for line in buffer.decode().splitlines():
if reading: if line.startswith(" ") and reading:
if line.startswith(" "): file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
g.write('\t"' + escape_string(line.strip()) + '",\n') elif line.startswith("## "):
continue
if line.startswith("## "):
if reading: if reading:
close_section() close_section()
reading = False reading = False
for section, section_id in zip(sections, sections_id): section = SECTIONS[line[3:].strip()]
if line.strip().endswith(section): if section:
current_section = escape_string(section_id) file.write(f"inline constexpr const char *{section}[] = {{\n")
reading = True reading = True
g.write("const char *const " + current_section + "[] = {\n")
break
if reading: if reading:
close_section() close_section()
g.write("#endif // AUTHORS_GEN_H\n")
def make_donors_header(target, source, env): def make_donors_header(target, source, env):
sections = [ SECTIONS = {
"Patrons", "Patrons": "DONORS_PATRONS",
"Platinum sponsors", "Platinum sponsors": "DONORS_SPONSORS_PLATINUM",
"Gold sponsors", "Gold sponsors": "DONORS_SPONSORS_GOLD",
"Silver sponsors", "Silver sponsors": "DONORS_SPONSORS_SILVER",
"Diamond members", "Diamond members": "DONORS_MEMBERS_DIAMOND",
"Titanium members", "Titanium members": "DONORS_MEMBERS_TITANIUM",
"Platinum members", "Platinum members": "DONORS_MEMBERS_PLATINUM",
"Gold members", "Gold members": "DONORS_MEMBERS_GOLD",
] }
sections_id = [ buffer = methods.get_buffer(str(source[0]))
"DONORS_PATRONS", reading = False
"DONORS_SPONSORS_PLATINUM",
"DONORS_SPONSORS_GOLD",
"DONORS_SPONSORS_SILVER",
"DONORS_MEMBERS_DIAMOND",
"DONORS_MEMBERS_TITANIUM",
"DONORS_MEMBERS_PLATINUM",
"DONORS_MEMBERS_GOLD",
]
src = str(source[0]) with methods.generated_wrapper(str(target[0])) as file:
dst = str(target[0])
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef DONORS_GEN_H\n")
g.write("#define DONORS_GEN_H\n")
reading = False
def close_section(): def close_section():
g.write("\t0\n") file.write("\tnullptr,\n};\n\n")
g.write("};\n")
for line in f: for line in buffer.decode().splitlines():
if reading >= 0: if line.startswith(" ") and reading:
if line.startswith(" "): file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
g.write('\t"' + escape_string(line.strip()) + '",\n') elif line.startswith("## "):
continue
if line.startswith("## "):
if reading: if reading:
close_section() close_section()
reading = False reading = False
for section, section_id in zip(sections, sections_id): section = SECTIONS.get(line[3:].strip())
if line.strip().endswith(section): if section:
current_section = escape_string(section_id) file.write(f"inline constexpr const char *{section}[] = {{\n")
reading = True reading = True
g.write("const char *const " + current_section + "[] = {\n")
break
if reading: if reading:
close_section() close_section()
g.write("#endif // DONORS_GEN_H\n")
def make_license_header(target, source, env): def make_license_header(target, source, env):
src_copyright = str(source[0]) src_copyright = str(source[0])
src_license = str(source[1]) src_license = str(source[1])
dst = str(target[0])
class LicenseReader: class LicenseReader:
def __init__(self, license_file): def __init__(self, license_file: TextIOWrapper):
self._license_file = license_file self._license_file = license_file
self.line_num = 0 self.line_num = 0
self.current = self.next_line() self.current = self.next_line()
@ -188,9 +121,7 @@ def make_license_header(target, source, env):
lines.append(self.current.strip()) lines.append(self.current.strip())
return (tag, lines) return (tag, lines)
from collections import OrderedDict projects = OrderedDict()
projects: dict = OrderedDict()
license_list = [] license_list = []
with open(src_copyright, "r", encoding="utf-8") as copyright_file: with open(src_copyright, "r", encoding="utf-8") as copyright_file:
@ -212,7 +143,7 @@ def make_license_header(target, source, env):
part = {} part = {}
reader.next_line() reader.next_line()
data_list: list = [] data_list = []
for project in iter(projects.values()): for project in iter(projects.values()):
for part in project: for part in project:
part["file_index"] = len(data_list) part["file_index"] = len(data_list)
@ -220,96 +151,76 @@ def make_license_header(target, source, env):
part["copyright_index"] = len(data_list) part["copyright_index"] = len(data_list)
data_list += part["Copyright"] data_list += part["Copyright"]
with open(dst, "w", encoding="utf-8", newline="\n") as f: with open(src_license, "r", encoding="utf-8") as file:
f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") license_text = file.read()
f.write("#ifndef LICENSE_GEN_H\n")
f.write("#define LICENSE_GEN_H\n")
f.write("const char *const GODOT_LICENSE_TEXT =")
with open(src_license, "r", encoding="utf-8") as license_file: with methods.generated_wrapper(str(target[0])) as file:
for line in license_file: file.write(f"""\
escaped_string = escape_string(line.strip()) inline constexpr const char *GODOT_LICENSE_TEXT = {{
f.write('\n\t\t"' + escaped_string + '\\n"') {methods.to_raw_cstring(license_text)}
f.write(";\n\n") }};
f.write( struct ComponentCopyrightPart {{
"struct ComponentCopyrightPart {\n" const char *license;
"\tconst char *license;\n" const char *const *files;
"\tconst char *const *files;\n" const char *const *copyright_statements;
"\tconst char *const *copyright_statements;\n" int file_count;
"\tint file_count;\n" int copyright_count;
"\tint copyright_count;\n" }};
"};\n\n"
)
f.write( struct ComponentCopyright {{
"struct ComponentCopyright {\n" const char *name;
"\tconst char *name;\n" const ComponentCopyrightPart *parts;
"\tconst ComponentCopyrightPart *parts;\n" int part_count;
"\tint part_count;\n" }};
"};\n\n"
)
f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n") """)
file.write("inline constexpr const char *COPYRIGHT_INFO_DATA[] = {\n")
for line in data_list: for line in data_list:
f.write('\t"' + escape_string(line) + '",\n') file.write(f'\t"{methods.to_escaped_cstring(line)}",\n')
f.write("};\n\n") file.write("};\n\n")
f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n") file.write("inline constexpr ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
part_index = 0 part_index = 0
part_indexes = {} part_indexes = {}
for project_name, project in iter(projects.items()): for project_name, project in iter(projects.items()):
part_indexes[project_name] = part_index part_indexes[project_name] = part_index
for part in project: for part in project:
f.write( file.write(
'\t{ "' f'\t{{ "{methods.to_escaped_cstring(part["License"][0])}", '
+ escape_string(part["License"][0]) + f"&COPYRIGHT_INFO_DATA[{part['file_index']}], "
+ '", ' + f"&COPYRIGHT_INFO_DATA[{part['copyright_index']}], "
+ "&COPYRIGHT_INFO_DATA[" + f"{len(part['Files'])}, {len(part['Copyright'])} }},\n"
+ str(part["file_index"])
+ "], "
+ "&COPYRIGHT_INFO_DATA["
+ str(part["copyright_index"])
+ "], "
+ str(len(part["Files"]))
+ ", "
+ str(len(part["Copyright"]))
+ " },\n"
) )
part_index += 1 part_index += 1
f.write("};\n\n") file.write("};\n\n")
f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n") file.write(f"inline constexpr int COPYRIGHT_INFO_COUNT = {len(projects)};\n")
f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n") file.write("inline constexpr ComponentCopyright COPYRIGHT_INFO[] = {\n")
for project_name, project in iter(projects.items()): for project_name, project in iter(projects.items()):
f.write( file.write(
'\t{ "' f'\t{{ "{methods.to_escaped_cstring(project_name)}", '
+ escape_string(project_name) + f"&COPYRIGHT_PROJECT_PARTS[{part_indexes[project_name]}], "
+ '", ' + f"{len(project)} }},\n"
+ "&COPYRIGHT_PROJECT_PARTS["
+ str(part_indexes[project_name])
+ "], "
+ str(len(project))
+ " },\n"
) )
f.write("};\n\n") file.write("};\n\n")
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n") file.write(f"inline constexpr int LICENSE_COUNT = {len(license_list)};\n")
f.write("const char *const LICENSE_NAMES[] = {\n") file.write("inline constexpr const char *LICENSE_NAMES[] = {\n")
for license in license_list: for license in license_list:
f.write('\t"' + escape_string(license[0]) + '",\n') file.write(f'\t"{methods.to_escaped_cstring(license[0])}",\n')
f.write("};\n\n") file.write("};\n\n")
f.write("const char *const LICENSE_BODIES[] = {\n\n") file.write("inline constexpr const char *LICENSE_BODIES[] = {\n\n")
for license in license_list: for license in license_list:
to_raw = []
for line in license[1:]: for line in license[1:]:
if line == ".": if line == ".":
f.write('\t"\\n"\n') to_raw += [""]
else: else:
f.write('\t"' + escape_string(line) + '\\n"\n') to_raw += [line]
f.write('\t"",\n\n') file.write(f"{methods.to_raw_cstring(to_raw)},\n\n")
f.write("};\n\n") file.write("};\n\n")
f.write("#endif // LICENSE_GEN_H\n")

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CORE_CONSTANTS_H #pragma once
#define CORE_CONSTANTS_H
#include "core/string/string_name.h" #include "core/string/string_name.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
@ -47,5 +46,3 @@ public:
static bool is_global_enum(const StringName &p_enum); static bool is_global_enum(const StringName &p_enum);
static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values); static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values);
}; };
#endif // CORE_CONSTANTS_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CORE_GLOBALS_H #pragma once
#define CORE_GLOBALS_H
// Home for state needed from global functions // Home for state needed from global functions
// that cannot be stored in Engine or OS due to e.g. circular includes // that cannot be stored in Engine or OS due to e.g. circular includes
@ -40,5 +39,3 @@ public:
static bool print_line_enabled; static bool print_line_enabled;
static bool print_error_enabled; static bool print_error_enabled;
}; };
#endif // CORE_GLOBALS_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CORE_STRING_NAMES_H #pragma once
#define CORE_STRING_NAMES_H
#include "core/string/string_name.h" #include "core/string/string_name.h"
@ -87,5 +86,3 @@ public:
}; };
#define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name #define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name
#endif // CORE_STRING_NAMES_H

View file

@ -13,7 +13,7 @@ if is_builtin or not has_module:
# Use our headers for builtin or if the module is not going to be compiled. # Use our headers for builtin or if the module is not going to be compiled.
# We decided not to depend on system mbedtls just for these few files that can # We decided not to depend on system mbedtls just for these few files that can
# be easily extracted. # be easily extracted.
env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"]) env_crypto.Prepend(CPPEXTPATH=["#thirdparty/mbedtls/include"])
# MbedTLS core functions (for CryptoCore). # MbedTLS core functions (for CryptoCore).
# If the mbedtls module is compiled we don't need to add the .c files with our # If the mbedtls module is compiled we don't need to add the .c files with our

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef AES_CONTEXT_H #pragma once
#define AES_CONTEXT_H
#include "core/crypto/crypto_core.h" #include "core/crypto/crypto_core.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -64,5 +63,3 @@ public:
}; };
VARIANT_ENUM_CAST(AESContext::Mode); VARIANT_ENUM_CAST(AESContext::Mode);
#endif // AES_CONTEXT_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CRYPTO_H #pragma once
#define CRYPTO_H
#include "core/crypto/hashing_context.h" #include "core/crypto/hashing_context.h"
#include "core/io/resource.h" #include "core/io/resource.h"
@ -167,5 +166,3 @@ public:
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const 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; virtual bool recognize(const Ref<Resource> &p_resource) const override;
}; };
#endif // CRYPTO_H

View file

@ -214,8 +214,8 @@ Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], con
} }
// CryptoCore // CryptoCore
String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) { String CryptoCore::b64_encode_str(const uint8_t *p_src, size_t p_src_len) {
int b64len = p_src_len / 3 * 4 + 4 + 1; size_t b64len = p_src_len / 3 * 4 + 4 + 1;
Vector<uint8_t> b64buff; Vector<uint8_t> b64buff;
b64buff.resize(b64len); b64buff.resize(b64len);
uint8_t *w64 = b64buff.ptrw(); uint8_t *w64 = b64buff.ptrw();
@ -225,27 +225,27 @@ String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
return ret ? String() : (const char *)&w64[0]; return ret ? String() : (const char *)&w64[0];
} }
Error CryptoCore::b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) { Error CryptoCore::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) {
int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len); int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len);
return ret ? FAILED : OK; return ret ? FAILED : OK;
} }
Error CryptoCore::b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) { Error CryptoCore::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) {
int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len); int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len);
return ret ? FAILED : OK; return ret ? FAILED : OK;
} }
Error CryptoCore::md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]) { Error CryptoCore::md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]) {
int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash); int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash);
return ret ? FAILED : OK; return ret ? FAILED : OK;
} }
Error CryptoCore::sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]) { Error CryptoCore::sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]) {
int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash); int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash);
return ret ? FAILED : OK; return ret ? FAILED : OK;
} }
Error CryptoCore::sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]) { Error CryptoCore::sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]) {
int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0); int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
return ret ? FAILED : OK; return ret ? FAILED : OK;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CRYPTO_CORE_H #pragma once
#define CRYPTO_CORE_H
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -107,13 +106,11 @@ public:
Error decrypt_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 String b64_encode_str(const uint8_t *p_src, int p_src_len); static String b64_encode_str(const uint8_t *p_src, size_t p_src_len);
static Error b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int 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, int p_dst_len, size_t *r_len, const uint8_t *p_src, int 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);
static Error md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]); 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, int p_src_len, unsigned char r_hash[20]); 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, int p_src_len, unsigned char r_hash[32]); static Error sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]);
}; };
#endif // CRYPTO_CORE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef HASHING_CONTEXT_H #pragma once
#define HASHING_CONTEXT_H
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -62,5 +61,3 @@ public:
}; };
VARIANT_ENUM_CAST(HashingContext::HashType); VARIANT_ENUM_CAST(HashingContext::HashType);
#endif // HASHING_CONTEXT_H

View file

@ -36,8 +36,7 @@
#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) #define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
Array DebuggerMarshalls::ScriptStackDump::serialize() { Array DebuggerMarshalls::ScriptStackDump::serialize() {
Array arr; Array arr = { frames.size() * 3 };
arr.push_back(frames.size() * 3);
for (const ScriptLanguage::StackInfo &frame : frames) { for (const ScriptLanguage::StackInfo &frame : frames) {
arr.push_back(frame.file); arr.push_back(frame.file);
arr.push_back(frame.line); arr.push_back(frame.line);
@ -64,10 +63,7 @@ bool DebuggerMarshalls::ScriptStackDump::deserialize(const Array &p_arr) {
} }
Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) { Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
Array arr; Array arr = { name, type, value.get_type() };
arr.push_back(name);
arr.push_back(type);
arr.push_back(value.get_type());
Variant var = value; Variant var = value;
if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) { if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
@ -99,20 +95,20 @@ bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
} }
Array DebuggerMarshalls::OutputError::serialize() { Array DebuggerMarshalls::OutputError::serialize() {
Array arr;
arr.push_back(hr);
arr.push_back(min);
arr.push_back(sec);
arr.push_back(msec);
arr.push_back(source_file);
arr.push_back(source_func);
arr.push_back(source_line);
arr.push_back(error);
arr.push_back(error_descr);
arr.push_back(warning);
unsigned int size = callstack.size(); unsigned int size = callstack.size();
Array arr = {
hr,
min,
sec, msec,
source_file,
source_func,
source_line,
error,
error_descr,
warning,
size * 3
};
const ScriptLanguage::StackInfo *r = callstack.ptr(); const ScriptLanguage::StackInfo *r = callstack.ptr();
arr.push_back(size * 3);
for (int i = 0; i < callstack.size(); i++) { for (int i = 0; i < callstack.size(); i++) {
arr.push_back(r[i].file); arr.push_back(r[i].file);
arr.push_back(r[i].func); arr.push_back(r[i].func);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef DEBUGGER_MARSHALLS_H #pragma once
#define DEBUGGER_MARSHALLS_H
#include "core/input/shortcut.h" #include "core/input/shortcut.h"
#include "core/object/script_language.h" #include "core/object/script_language.h"
@ -73,5 +72,3 @@ struct DebuggerMarshalls {
static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut); static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut);
static Ref<Shortcut> deserialize_key_shortcut(const Array &p_keys); static Ref<Shortcut> deserialize_key_shortcut(const Array &p_keys);
}; };
#endif // DEBUGGER_MARSHALLS_H

View file

@ -127,7 +127,7 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks,
singleton->poll_events(true); singleton->poll_events(true);
} }
void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) { void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, bool p_ignore_error_breaks, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) {
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more. register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
if (p_uri.is_empty()) { if (p_uri.is_empty()) {
return; return;
@ -149,8 +149,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer))); singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
script_debugger = memnew(ScriptDebugger); script_debugger = memnew(ScriptDebugger);
// Notify editor of our pid (to allow focus stealing). // Notify editor of our pid (to allow focus stealing).
Array msg; Array msg = { OS::get_singleton()->get_process_id() };
msg.push_back(OS::get_singleton()->get_process_id());
singleton->send_message("set_pid", msg); singleton->send_message("set_pid", msg);
} }
if (!singleton) { if (!singleton) {
@ -160,13 +159,14 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
// There is a debugger, parse breakpoints. // There is a debugger, parse breakpoints.
ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger(); ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger();
singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints); singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints);
singleton_script_debugger->set_ignore_error_breaks(p_ignore_error_breaks);
for (int i = 0; i < p_breakpoints.size(); i++) { for (int i = 0; i < p_breakpoints.size(); i++) {
const String &bp = p_breakpoints[i]; const String &bp = p_breakpoints[i];
int sp = bp.rfind_char(':'); int sp = bp.rfind_char(':');
ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp)); ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp)); singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1).to_int(), bp.substr(0, sp));
} }
allow_focus_steal_fn = p_allow_focus_steal_fn; allow_focus_steal_fn = p_allow_focus_steal_fn;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef ENGINE_DEBUGGER_H #pragma once
#define ENGINE_DEBUGGER_H
#include "core/string/string_name.h" #include "core/string/string_name.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -107,7 +106,7 @@ public:
_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; } _FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; }
static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()); static void initialize(const String &p_uri, bool p_skip_breakpoints, bool p_ignore_error_breaks, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
static void deinitialize(); static void deinitialize();
static void register_profiler(const StringName &p_name, const Profiler &p_profiler); static void register_profiler(const StringName &p_name, const Profiler &p_profiler);
static void unregister_profiler(const StringName &p_name); static void unregister_profiler(const StringName &p_name);
@ -140,5 +139,3 @@ public:
virtual ~EngineDebugger(); virtual ~EngineDebugger();
}; };
#endif // ENGINE_DEBUGGER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef ENGINE_PROFILER_H #pragma once
#define ENGINE_PROFILER_H
#include "core/object/gdvirtual.gen.inc" #include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -59,5 +58,3 @@ public:
EngineProfiler() {} EngineProfiler() {}
virtual ~EngineProfiler(); virtual ~EngineProfiler();
}; };
#endif // ENGINE_PROFILER_H

View file

@ -242,7 +242,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (line.begins_with("br") || line.begins_with("break")) { } else if (line.begins_with("br") || line.begins_with("break")) {
if (line.get_slice_count(" ") <= 1) { if (line.get_slice_count(" ") <= 1) {
const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints(); const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
if (breakpoints.size() == 0) { if (breakpoints.is_empty()) {
print_line("No Breakpoints."); print_line("No Breakpoints.");
continue; continue;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef LOCAL_DEBUGGER_H #pragma once
#define LOCAL_DEBUGGER_H
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/object/script_language.h" #include "core/object/script_language.h"
@ -55,5 +54,3 @@ public:
LocalDebugger(); LocalDebugger();
~LocalDebugger(); ~LocalDebugger();
}; };
#endif // LOCAL_DEBUGGER_H

View file

@ -95,10 +95,7 @@ public:
}; };
Error RemoteDebugger::_put_msg(const String &p_message, const Array &p_data) { Error RemoteDebugger::_put_msg(const String &p_message, const Array &p_data) {
Array msg; Array msg = { p_message, Thread::get_caller_id(), p_data };
msg.push_back(p_message);
msg.push_back(Thread::get_caller_id());
msg.push_back(p_data);
Error err = peer->put_message(msg); Error err = peer->put_message(msg);
if (err != OK) { if (err != OK) {
n_messages_dropped++; n_messages_dropped++;
@ -235,9 +232,7 @@ void RemoteDebugger::flush_output() {
types.push_back(MESSAGE_TYPE_LOG); types.push_back(MESSAGE_TYPE_LOG);
} }
Array arr; Array arr = { strings, types };
arr.push_back(strings);
arr.push_back(types);
_put_msg("output", arr); _put_msg("output", arr);
output_strings.clear(); output_strings.clear();
} }
@ -413,17 +408,25 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} }
ScriptLanguage *script_lang = script_debugger->get_break_language(); ScriptLanguage *script_lang = script_debugger->get_break_language();
const String error_str = script_lang ? script_lang->debug_get_error() : "";
Array msg;
msg.push_back(p_can_continue);
msg.push_back(error_str);
ERR_FAIL_NULL(script_lang); ERR_FAIL_NULL(script_lang);
msg.push_back(script_lang->debug_get_stack_level_count() > 0); const bool can_break = !(p_is_error_breakpoint && script_debugger->is_ignoring_error_breaks());
msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id())); const String error_str = script_lang ? script_lang->debug_get_error() : "";
if (allow_focus_steal_fn) {
allow_focus_steal_fn(); if (can_break) {
Array msg = {
p_can_continue,
error_str,
script_lang->debug_get_stack_level_count() > 0,
Thread::get_caller_id()
};
if (allow_focus_steal_fn) {
allow_focus_steal_fn();
}
send_message("debug_enter", msg);
} else {
ERR_PRINT(error_str);
return;
} }
send_message("debug_enter", msg);
Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE; Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
@ -507,8 +510,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
script_lang->debug_get_globals(&globals, &globals_vals); script_lang->debug_get_globals(&globals, &globals_vals);
ERR_FAIL_COND(globals.size() != globals_vals.size()); ERR_FAIL_COND(globals.size() != globals_vals.size());
Array var_size; Array var_size = { local_vals.size() + member_vals.size() + globals_vals.size() };
var_size.push_back(local_vals.size() + member_vals.size() + globals_vals.size());
send_message("stack_frame_vars", var_size); send_message("stack_frame_vars", var_size);
_send_stack_vars(locals, local_vals, 0); _send_stack_vars(locals, local_vals, 0);
_send_stack_vars(members, member_vals, 1); _send_stack_vars(members, member_vals, 1);
@ -530,6 +532,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (command == "set_skip_breakpoints") { } else if (command == "set_skip_breakpoints") {
ERR_FAIL_COND(data.is_empty()); ERR_FAIL_COND(data.is_empty());
script_debugger->set_skip_breakpoints(data[0]); script_debugger->set_skip_breakpoints(data[0]);
} else if (command == "set_ignore_error_breaks") {
ERR_FAIL_COND(data.is_empty());
script_debugger->set_ignore_error_breaks(data[0]);
} else if (command == "evaluate") { } else if (command == "evaluate") {
String expression_str = data[0]; String expression_str = data[0];
int frame = data[1]; int frame = data[1];
@ -669,6 +674,9 @@ Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bo
} else if (p_cmd == "set_skip_breakpoints") { } else if (p_cmd == "set_skip_breakpoints") {
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA); ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
script_debugger->set_skip_breakpoints(p_data[0]); script_debugger->set_skip_breakpoints(p_data[0]);
} else if (p_cmd == "set_ignore_error_breaks") {
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
script_debugger->set_ignore_error_breaks(p_data[0]);
} else if (p_cmd == "break") { } else if (p_cmd == "break") {
script_debugger->debug(script_debugger->get_break_language()); script_debugger->debug(script_debugger->get_break_language());
} else { } else {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef REMOTE_DEBUGGER_H #pragma once
#define REMOTE_DEBUGGER_H
#include "core/debugger/debugger_marshalls.h" #include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
@ -122,5 +121,3 @@ public:
explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer); explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
~RemoteDebugger(); ~RemoteDebugger();
}; };
#endif // REMOTE_DEBUGGER_H

View file

@ -96,7 +96,7 @@ void RemoteDebuggerPeerTCP::_write_out() {
while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) { while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) {
uint8_t *buf = out_buf.ptrw(); uint8_t *buf = out_buf.ptrw();
if (out_left <= 0) { if (out_left <= 0) {
if (out_queue.size() == 0) { if (out_queue.is_empty()) {
break; // Nothing left to send break; // Nothing left to send
} }
mutex.lock(); mutex.lock();

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef REMOTE_DEBUGGER_PEER_H #pragma once
#define REMOTE_DEBUGGER_PEER_H
#include "core/io/stream_peer_tcp.h" #include "core/io/stream_peer_tcp.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -92,5 +91,3 @@ public:
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>()); RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
~RemoteDebuggerPeerTCP(); ~RemoteDebuggerPeerTCP();
}; };
#endif // REMOTE_DEBUGGER_PEER_H

View file

@ -58,7 +58,7 @@ void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
} }
breakpoints[p_line].erase(p_source); breakpoints[p_line].erase(p_source);
if (breakpoints[p_line].size() == 0) { if (breakpoints[p_line].is_empty()) {
breakpoints.erase(p_line); breakpoints.erase(p_line);
} }
} }
@ -79,6 +79,14 @@ bool ScriptDebugger::is_skipping_breakpoints() {
return skip_breakpoints; return skip_breakpoints;
} }
void ScriptDebugger::set_ignore_error_breaks(bool p_ignore) {
ignore_error_breaks = p_ignore;
}
bool ScriptDebugger::is_ignoring_error_breaks() {
return ignore_error_breaks;
}
void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) { void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
ScriptLanguage *prev = break_lang; ScriptLanguage *prev = break_lang;
break_lang = p_lang; break_lang = p_lang;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef SCRIPT_DEBUGGER_H #pragma once
#define SCRIPT_DEBUGGER_H
#include "core/object/script_language.h" #include "core/object/script_language.h"
#include "core/string/string_name.h" #include "core/string/string_name.h"
@ -40,6 +39,7 @@ class ScriptDebugger {
typedef ScriptLanguage::StackInfo StackInfo; typedef ScriptLanguage::StackInfo StackInfo;
bool skip_breakpoints = false; bool skip_breakpoints = false;
bool ignore_error_breaks = false;
HashMap<int, HashSet<StringName>> breakpoints; HashMap<int, HashSet<StringName>> breakpoints;
@ -64,6 +64,8 @@ public:
ScriptLanguage *get_break_language() { return break_lang; } ScriptLanguage *get_break_language() { return break_lang; }
void set_skip_breakpoints(bool p_skip_breakpoints); void set_skip_breakpoints(bool p_skip_breakpoints);
bool is_skipping_breakpoints(); bool is_skipping_breakpoints();
void set_ignore_error_breaks(bool p_ignore);
bool is_ignoring_error_breaks();
void insert_breakpoint(int p_line, const StringName &p_source); void insert_breakpoint(int p_line, const StringName &p_source);
void remove_breakpoint(int p_line, const StringName &p_source); void remove_breakpoint(int p_line, const StringName &p_source);
_ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const { _ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const {
@ -82,5 +84,3 @@ public:
Vector<StackInfo> get_error_stack_info() const; Vector<StackInfo> get_error_stack_info() const;
ScriptDebugger() {} ScriptDebugger() {}
}; };
#endif // SCRIPT_DEBUGGER_H

View file

@ -32,11 +32,11 @@
String DocData::get_default_value_string(const Variant &p_value) { String DocData::get_default_value_string(const Variant &p_value) {
if (p_value.get_type() == Variant::ARRAY) { if (p_value.get_type() == Variant::ARRAY) {
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " "); return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' ');
} else if (p_value.get_type() == Variant::DICTIONARY) { } else if (p_value.get_type() == Variant::DICTIONARY) {
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " "); return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' ');
} else { } else {
return p_value.get_construct_string().replace("\n", " "); return p_value.get_construct_string().replace_char('\n', ' ');
} }
} }
@ -51,7 +51,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper
} else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
p_method.return_enum = p_retinfo.class_name; p_method.return_enum = p_retinfo.class_name;
if (p_method.return_enum.begins_with("_")) { //proxy class if (p_method.return_enum.begins_with("_")) { //proxy class
p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); p_method.return_enum = p_method.return_enum.substr(1);
} }
p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_method.return_type = "int"; p_method.return_type = "int";
@ -85,7 +85,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const
} else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
p_argument.enumeration = p_arginfo.class_name; p_argument.enumeration = p_arginfo.class_name;
if (p_argument.enumeration.begins_with("_")) { //proxy class if (p_argument.enumeration.begins_with("_")) { //proxy class
p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); p_argument.enumeration = p_argument.enumeration.substr(1);
} }
p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_argument.type = "int"; p_argument.type = "int";
@ -136,11 +136,10 @@ void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const Met
return_doc_from_retinfo(p_method, p_methodinfo.return_val); return_doc_from_retinfo(p_method, p_methodinfo.return_val);
int i = 0; for (int64_t i = 0; i < p_methodinfo.arguments.size(); ++i) {
for (List<PropertyInfo>::ConstIterator itr = p_methodinfo.arguments.begin(); itr != p_methodinfo.arguments.end(); ++itr, ++i) {
DocData::ArgumentDoc argument; DocData::ArgumentDoc argument;
argument_doc_from_arginfo(argument, *itr); argument_doc_from_arginfo(argument, p_methodinfo.arguments[i]);
int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size()); int64_t default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
if (default_arg_index >= 0) { if (default_arg_index >= 0) {
Variant default_arg = p_methodinfo.default_arguments[default_arg_index]; Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
argument.default_value = get_default_value_string(default_arg); argument.default_value = get_default_value_string(default_arg);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef DOC_DATA_H #pragma once
#define DOC_DATA_H
#include "core/io/xml_parser.h" #include "core/io/xml_parser.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
@ -115,7 +114,7 @@ public:
// Must be an operator or a constructor since there is no other overloading // Must be an operator or a constructor since there is no other overloading
if (name.left(8) == "operator") { if (name.left(8) == "operator") {
if (arguments.size() == p_method.arguments.size()) { if (arguments.size() == p_method.arguments.size()) {
if (arguments.size() == 0) { if (arguments.is_empty()) {
return false; return false;
} }
return arguments[0].type < p_method.arguments[0].type; return arguments[0].type < p_method.arguments[0].type;
@ -127,7 +126,7 @@ public:
// - 1. Default constructor: Foo() // - 1. Default constructor: Foo()
// - 2. Copy constructor: Foo(Foo) // - 2. Copy constructor: Foo(Foo)
// - 3+. Other constructors Foo(Bar, ...) based on first argument's name // - 3+. Other constructors Foo(Bar, ...) based on first argument's name
if (arguments.size() == 0 || p_method.arguments.size() == 0) { // 1. if (arguments.is_empty() || p_method.arguments.is_empty()) { // 1.
return arguments.size() < p_method.arguments.size(); return arguments.size() < p_method.arguments.size();
} }
if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2. if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2.
@ -795,8 +794,8 @@ public:
if (p_dict.has("enums")) { if (p_dict.has("enums")) {
enums = p_dict["enums"]; enums = p_dict["enums"];
} }
for (int i = 0; i < enums.size(); i++) { for (const KeyValue<Variant, Variant> &kv : enums) {
doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i)); doc.enums[kv.key] = EnumDoc::from_dict(kv.value);
} }
Array properties; Array properties;
@ -980,5 +979,3 @@ public:
static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo); static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo);
static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc); static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc);
}; };
#endif // DOC_DATA_H

View file

@ -30,6 +30,8 @@
#include "error_list.h" #include "error_list.h"
#include <iterator>
const char *error_names[] = { const char *error_names[] = {
"OK", // OK "OK", // OK
"Failed", // FAILED "Failed", // FAILED
@ -82,4 +84,4 @@ const char *error_names[] = {
"Printer on fire", // ERR_PRINTER_ON_FIRE "Printer on fire", // ERR_PRINTER_ON_FIRE
}; };
static_assert(sizeof(error_names) / sizeof(*error_names) == ERR_MAX); static_assert(std::size(error_names) == ERR_MAX);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef ERROR_LIST_H #pragma once
#define ERROR_LIST_H
/** Error List. Please never compare an error against FAILED /** Error List. Please never compare an error against FAILED
* Either do result != OK , or !result. This way, Error fail * Either do result != OK , or !result. This way, Error fail
@ -98,5 +97,3 @@ enum Error {
}; };
extern const char *error_names[]; extern const char *error_names[];
#endif // ERROR_LIST_H

View file

@ -31,6 +31,7 @@
#include "error_macros.h" #include "error_macros.h"
#include "core/io/logger.h" #include "core/io/logger.h"
#include "core/object/object_id.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -187,7 +188,7 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
} else { } else {
String node_name; String node_name;
if (p_id.is_valid()) { if (p_id.is_valid()) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id)); Node *node = ObjectDB::get_instance<Node>(p_id);
if (node && node->is_inside_tree()) { if (node && node->is_inside_tree()) {
node_name = "\"" + String(node->get_path()) + "\""; node_name = "\"" + String(node->get_path()) + "\"";
} else { } else {

View file

@ -28,15 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef ERROR_MACROS_H #pragma once
#define ERROR_MACROS_H
#include "core/object/object_id.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes. #include <atomic> // IWYU pragma: keep // Used in macro. We'd normally use `safe_refcount.h`, but that would cause circular includes.
class String; class String;
class ObjectID;
enum ErrorHandlerType { enum ErrorHandlerType {
ERR_HANDLER_ERROR, ERR_HANDLER_ERROR,
@ -62,16 +61,16 @@ void add_error_handler(ErrorHandlerList *p_handler);
void remove_error_handler(const ErrorHandlerList *p_handler); void remove_error_handler(const ErrorHandlerList *p_handler);
// Functions used by the error macros. // Functions used by the error macros.
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
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 = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ 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 = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); _NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR); void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false); _NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false); _NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
void _err_flush_stdout(); _NO_INLINE_ void _err_flush_stdout();
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string); void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string);
@ -845,5 +844,3 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
#define PHYSICS_INTERPOLATION_WARNING(m_string) \ #define PHYSICS_INTERPOLATION_WARNING(m_string) \
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string) _physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string)
#endif // ERROR_MACROS_H

View file

@ -96,8 +96,7 @@ static String fix_doc_description(const String &p_bbcode) {
// Based on what EditorHelp does. // Based on what EditorHelp does.
return p_bbcode.dedent() return p_bbcode.dedent()
.replace("\t", "") .remove_chars("\t\r")
.replace("\r", "")
.strip_edges(); .strip_edges();
} }
@ -107,16 +106,22 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
{ {
//header //header
Dictionary header; Dictionary header;
header["version_major"] = VERSION_MAJOR; header["version_major"] = GODOT_VERSION_MAJOR;
header["version_minor"] = VERSION_MINOR; header["version_minor"] = GODOT_VERSION_MINOR;
#if VERSION_PATCH #if GODOT_VERSION_PATCH
header["version_patch"] = VERSION_PATCH; header["version_patch"] = GODOT_VERSION_PATCH;
#else #else
header["version_patch"] = 0; header["version_patch"] = 0;
#endif #endif
header["version_status"] = VERSION_STATUS; header["version_status"] = GODOT_VERSION_STATUS;
header["version_build"] = VERSION_BUILD; header["version_build"] = GODOT_VERSION_BUILD;
header["version_full_name"] = VERSION_FULL_NAME; header["version_full_name"] = GODOT_VERSION_FULL_NAME;
#if REAL_T_IS_DOUBLE
header["precision"] = "double";
#else
header["precision"] = "single";
#endif
api_dump["header"] = header; api_dump["header"] = header;
} }
@ -278,43 +283,43 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
#define REAL_MEMBER_OFFSET(type, member) \ #define REAL_MEMBER_OFFSET(type, member) \
{ \ { \
type, \ type, \
member, \ member, \
"float", \ "float", \
sizeof(float), \ sizeof(float), \
"float", \ "float", \
sizeof(float), \ sizeof(float), \
"double", \ "double", \
sizeof(double), \ sizeof(double), \
"double", \ "double", \
sizeof(double), \ sizeof(double), \
} }
#define INT32_MEMBER_OFFSET(type, member) \ #define INT32_MEMBER_OFFSET(type, member) \
{ \ { \
type, \ type, \
member, \ member, \
"int32", \ "int32", \
sizeof(int32_t), \ sizeof(int32_t), \
"int32", \ "int32", \
sizeof(int32_t), \ sizeof(int32_t), \
"int32", \ "int32", \
sizeof(int32_t), \ sizeof(int32_t), \
"int32", \ "int32", \
sizeof(int32_t), \ sizeof(int32_t), \
} }
#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ #define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
{ \ { \
type, \ type, \
member, \ member, \
member_type, \ member_type, \
sizeof(int32_t) * member_elems, \ sizeof(int32_t) * member_elems, \
member_type, \ member_type, \
sizeof(int32_t) * member_elems, \ sizeof(int32_t) * member_elems, \
member_type, \ member_type, \
sizeof(int32_t) * member_elems, \ sizeof(int32_t) * member_elems, \
member_type, \ member_type, \
sizeof(int32_t) * member_elems, \ sizeof(int32_t) * member_elems, \
} }
#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ #define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
@ -970,14 +975,14 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
Array values; Array values;
List<StringName> enum_constant_list; List<StringName> enum_constant_list;
ClassDB::get_enum_constants(class_name, F, &enum_constant_list, true); ClassDB::get_enum_constants(class_name, F, &enum_constant_list, true);
for (List<StringName>::Element *G = enum_constant_list.front(); G; G = G->next()) { for (const StringName &enum_constant : enum_constant_list) {
Dictionary d3; Dictionary d3;
d3["name"] = String(G->get()); d3["name"] = String(enum_constant);
d3["value"] = ClassDB::get_integer_constant(class_name, G->get()); d3["value"] = ClassDB::get_integer_constant(class_name, enum_constant);
if (p_include_docs) { if (p_include_docs) {
for (const DocData::ConstantDoc &constant_doc : class_doc->constants) { for (const DocData::ConstantDoc &constant_doc : class_doc->constants) {
if (constant_doc.name == G->get()) { if (constant_doc.name == enum_constant) {
d3["description"] = fix_doc_description(constant_doc.description); d3["description"] = fix_doc_description(constant_doc.description);
break; break;
} }
@ -1048,9 +1053,8 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
} }
Array arguments; Array arguments;
int i = 0; for (int64_t i = 0; i < mi.arguments.size(); ++i) {
for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++i) { const PropertyInfo &pinfo = mi.arguments[i];
const PropertyInfo &pinfo = *itr;
Dictionary d3; Dictionary d3;
d3["name"] = pinfo.name; d3["name"] = pinfo.name;
@ -1175,11 +1179,10 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
Array arguments; Array arguments;
int i = 0; for (int64_t i = 0; i < F.arguments.size(); ++i) {
for (List<PropertyInfo>::ConstIterator itr = F.arguments.begin(); itr != F.arguments.end(); ++itr, ++i) {
Dictionary d3; Dictionary d3;
d3["name"] = itr->name; d3["name"] = F.arguments[i].name;
d3["type"] = get_property_info_type_name(*itr); d3["type"] = get_property_info_type_name(F.arguments[i]);
if (F.get_argument_meta(i) > 0) { if (F.get_argument_meta(i) > 0) {
d3["meta"] = get_type_meta_name((GodotTypeInfo::Metadata)F.get_argument_meta(i)); d3["meta"] = get_type_meta_name((GodotTypeInfo::Metadata)F.get_argument_meta(i));
} }
@ -1340,16 +1343,16 @@ static bool compare_value(const String &p_path, const String &p_field, const Var
} else if (p_old_value.get_type() == Variant::DICTIONARY && p_new_value.get_type() == Variant::DICTIONARY) { } else if (p_old_value.get_type() == Variant::DICTIONARY && p_new_value.get_type() == Variant::DICTIONARY) {
Dictionary old_dict = p_old_value; Dictionary old_dict = p_old_value;
Dictionary new_dict = p_new_value; Dictionary new_dict = p_new_value;
for (const Variant &key : old_dict.keys()) { for (const KeyValue<Variant, Variant> &kv : old_dict) {
if (!new_dict.has(key)) { if (!new_dict.has(kv.key)) {
failed = true; failed = true;
print_error(vformat("Validate extension JSON: Error: Field '%s': %s was removed.", p_path, key)); print_error(vformat("Validate extension JSON: Error: Field '%s': %s was removed.", p_path, kv.key));
continue; continue;
} }
if (p_allow_name_change && key == "name") { if (p_allow_name_change && kv.key == "name") {
continue; continue;
} }
if (!compare_value(path, key, old_dict[key], new_dict[key], p_allow_name_change)) { if (!compare_value(path, kv.key, kv.value, new_dict[kv.key], p_allow_name_change)) {
failed = true; failed = true;
} }
} }
@ -1420,25 +1423,25 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
bool optional = field.begins_with("*"); bool optional = field.begins_with("*");
if (optional) { if (optional) {
// This is an optional field, but if exists it has to exist in both. // This is an optional field, but if exists it has to exist in both.
field = field.substr(1, field.length()); field = field.substr(1);
} }
bool added = field.begins_with("+"); bool added = field.begins_with("+");
if (added) { if (added) {
// Meaning this field must either exist or contents may not exist. // Meaning this field must either exist or contents may not exist.
field = field.substr(1, field.length()); field = field.substr(1);
} }
bool enum_values = field.begins_with("$"); bool enum_values = field.begins_with("$");
if (enum_values) { if (enum_values) {
// Meaning this field is a list of enum values. // Meaning this field is a list of enum values.
field = field.substr(1, field.length()); field = field.substr(1);
} }
bool allow_name_change = field.begins_with("@"); bool allow_name_change = field.begins_with("@");
if (allow_name_change) { if (allow_name_change) {
// Meaning that when structurally comparing the old and new value, the dictionary entry 'name' may change. // Meaning that when structurally comparing the old and new value, the dictionary entry 'name' may change.
field = field.substr(1, field.length()); field = field.substr(1);
} }
Variant old_value; Variant old_value;
@ -1598,8 +1601,8 @@ Error GDExtensionAPIDump::validate_extension_json_file(const String &p_path) {
int major = header["version_major"]; int major = header["version_major"];
int minor = header["version_minor"]; int minor = header["version_minor"];
ERR_FAIL_COND_V_MSG(major != VERSION_MAJOR, ERR_INVALID_DATA, vformat("JSON API dump is for a different engine version (%d) than this one (%d)", major, VERSION_MAJOR)); ERR_FAIL_COND_V_MSG(major != GODOT_VERSION_MAJOR, ERR_INVALID_DATA, vformat("JSON API dump is for a different engine version (%d) than this one (%d)", major, GODOT_VERSION_MAJOR));
ERR_FAIL_COND_V_MSG(minor > VERSION_MINOR, ERR_INVALID_DATA, vformat("JSON API dump is for a newer version of the engine: %d.%d", major, minor)); ERR_FAIL_COND_V_MSG(minor > GODOT_VERSION_MINOR, ERR_INVALID_DATA, vformat("JSON API dump is for a newer version of the engine: %d.%d", major, minor));
} }
bool failed = false; bool failed = false;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef EXTENSION_API_DUMP_H #pragma once
#define EXTENSION_API_DUMP_H
#include "core/extension/gdextension.h" #include "core/extension/gdextension.h"
@ -42,5 +41,3 @@ public:
static Error validate_extension_json_file(const String &p_path); static Error validate_extension_json_file(const String &p_path);
}; };
#endif #endif
#endif // EXTENSION_API_DUMP_H

View file

@ -679,6 +679,13 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte
memnew_placement(r_path, String(library_path)); memnew_placement(r_path, String(library_path));
} }
void GDExtension::_register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback) {
#ifdef TOOLS_ENABLED
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
self->get_classes_used_callback = p_callback;
#endif
}
HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions; HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions;
void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
@ -799,6 +806,7 @@ void GDExtension::initialize_gdextensions() {
register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal); register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal);
register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class); register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path); register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback);
} }
void GDExtension::finalize_gdextensions() { void GDExtension::finalize_gdextensions() {
@ -1034,6 +1042,14 @@ void GDExtension::_untrack_instance(void *p_user_data, void *p_instance) {
extension->instances.erase(obj->get_instance_id()); extension->instances.erase(obj->get_instance_id());
} }
PackedStringArray GDExtension::get_classes_used() const {
PackedStringArray ret;
if (get_classes_used_callback) {
get_classes_used_callback((GDExtensionTypePtr)&ret);
}
return ret;
}
Vector<StringName> GDExtensionEditorPlugins::extension_classes; Vector<StringName> GDExtensionEditorPlugins::extension_classes;
GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr;
GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_H #pragma once
#define GDEXTENSION_H
#include "core/extension/gdextension_interface.h" #include "core/extension/gdextension_interface.h"
#include "core/extension/gdextension_loader.h" #include "core/extension/gdextension_loader.h"
@ -94,6 +93,7 @@ class GDExtension : public Resource {
static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count); static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name); static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path); static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
GDExtensionInitialization initialization; GDExtensionInitialization initialization;
int32_t level_initialized = -1; int32_t level_initialized = -1;
@ -102,6 +102,7 @@ class GDExtension : public Resource {
bool is_reloading = false; bool is_reloading = false;
Vector<GDExtensionMethodBind *> invalid_methods; Vector<GDExtensionMethodBind *> invalid_methods;
Vector<ObjectID> instance_bindings; Vector<ObjectID> instance_bindings;
GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr;
static void _track_instance(void *p_user_data, void *p_instance); static void _track_instance(void *p_user_data, void *p_instance);
static void _untrack_instance(void *p_user_data, void *p_instance); static void _untrack_instance(void *p_user_data, void *p_instance);
@ -156,6 +157,8 @@ public:
void track_instance_binding(Object *p_object); void track_instance_binding(Object *p_object);
void untrack_instance_binding(Object *p_object); void untrack_instance_binding(Object *p_object);
PackedStringArray get_classes_used() const;
#endif #endif
InitializationLevel get_minimum_library_initialization_level() const; InitializationLevel get_minimum_library_initialization_level() const;
@ -226,5 +229,3 @@ public:
}; };
#endif // TOOLS_ENABLED #endif // TOOLS_ENABLED
#endif // GDEXTENSION_H

View file

@ -241,11 +241,25 @@ GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name)
return GDExtension::get_interface_function(p_name); return GDExtension::get_interface_function(p_name);
} }
#ifndef DISABLE_DEPRECATED
static void gdextension_get_godot_version(GDExtensionGodotVersion *r_godot_version) { static void gdextension_get_godot_version(GDExtensionGodotVersion *r_godot_version) {
r_godot_version->major = VERSION_MAJOR; r_godot_version->major = GODOT_VERSION_MAJOR;
r_godot_version->minor = VERSION_MINOR; r_godot_version->minor = GODOT_VERSION_MINOR;
r_godot_version->patch = VERSION_PATCH; r_godot_version->patch = GODOT_VERSION_PATCH;
r_godot_version->string = VERSION_FULL_NAME; r_godot_version->string = GODOT_VERSION_FULL_NAME;
}
#endif
static void gdextension_get_godot_version2(GDExtensionGodotVersion2 *r_godot_version) {
r_godot_version->major = GODOT_VERSION_MAJOR;
r_godot_version->minor = GODOT_VERSION_MINOR;
r_godot_version->patch = GODOT_VERSION_PATCH;
r_godot_version->hex = GODOT_VERSION_HEX;
r_godot_version->status = GODOT_VERSION_STATUS;
r_godot_version->build = GODOT_VERSION_BUILD;
r_godot_version->hash = GODOT_VERSION_HASH;
r_godot_version->timestamp = GODOT_VERSION_TIMESTAMP;
r_godot_version->string = GODOT_VERSION_FULL_NAME;
} }
// Memory Functions // Memory Functions
@ -858,84 +872,82 @@ static GDExtensionPtrUtilityFunction gdextension_variant_get_ptr_utility_functio
//string helpers //string helpers
static void gdextension_string_new_with_latin1_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) { static void gdextension_string_new_with_latin1_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) {
memnew_placement(r_dest, String(p_contents)); String *dest = memnew_placement(r_dest, String);
dest->append_latin1(Span<char>(p_contents, p_contents ? strlen(p_contents) : 0));
} }
static void gdextension_string_new_with_utf8_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) { static void gdextension_string_new_with_utf8_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf8(p_contents);
dest->parse_utf8(p_contents);
} }
static void gdextension_string_new_with_utf16_chars(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents) { static void gdextension_string_new_with_utf16_chars(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf16(p_contents);
dest->parse_utf16(p_contents);
} }
static void gdextension_string_new_with_utf32_chars(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents) { static void gdextension_string_new_with_utf32_chars(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents) {
memnew_placement(r_dest, String((const char32_t *)p_contents)); String *dest = memnew_placement(r_dest, String);
dest->append_utf32(Span(p_contents, p_contents ? strlen(p_contents) : 0));
} }
static void gdextension_string_new_with_wide_chars(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents) { static void gdextension_string_new_with_wide_chars(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents) {
if constexpr (sizeof(wchar_t) == 2) { if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse. // wchar_t is 16 bit (UTF-16).
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf16((const char16_t *)p_contents);
dest->parse_utf16((const char16_t *)p_contents);
} else { } else {
// wchar_t is 32 bit, copy. // wchar_t is 32 bit (UTF-32).
memnew_placement(r_dest, String((const char32_t *)p_contents)); String *string = memnew_placement(r_dest, String);
string->append_utf32(Span((const char32_t *)p_contents, p_contents ? strlen(p_contents) : 0));
} }
} }
static void gdextension_string_new_with_latin1_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { static void gdextension_string_new_with_latin1_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
memnew_placement(r_dest, String(p_contents, p_size)); String *dest = memnew_placement(r_dest, String);
dest->append_latin1(Span(p_contents, p_contents ? _strlen_clipped(p_contents, p_size) : 0));
} }
static void gdextension_string_new_with_utf8_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { static void gdextension_string_new_with_utf8_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf8(p_contents, p_size);
dest->parse_utf8(p_contents, p_size);
} }
static GDExtensionInt gdextension_string_new_with_utf8_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { static GDExtensionInt gdextension_string_new_with_utf8_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); return (GDExtensionInt)dest->append_utf8(p_contents, p_size);
return (GDExtensionInt)dest->parse_utf8(p_contents, p_size);
} }
static void gdextension_string_new_with_utf16_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count) { static void gdextension_string_new_with_utf16_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf16(p_contents, p_char_count);
dest->parse_utf16(p_contents, p_char_count);
} }
static GDExtensionInt gdextension_string_new_with_utf16_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count, GDExtensionBool p_default_little_endian) { static GDExtensionInt gdextension_string_new_with_utf16_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count, GDExtensionBool p_default_little_endian) {
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); return (GDExtensionInt)dest->append_utf16(p_contents, p_char_count, p_default_little_endian);
return (GDExtensionInt)dest->parse_utf16(p_contents, p_char_count, p_default_little_endian);
} }
static void gdextension_string_new_with_utf32_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_char_count) { static void gdextension_string_new_with_utf32_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_char_count) {
memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count)); String *string = memnew_placement(r_dest, String);
string->append_utf32(Span(p_contents, p_contents ? _strlen_clipped(p_contents, p_char_count) : 0));
} }
static void gdextension_string_new_with_wide_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_char_count) { static void gdextension_string_new_with_wide_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_char_count) {
if constexpr (sizeof(wchar_t) == 2) { if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse. // wchar_t is 16 bit (UTF-16).
memnew_placement(r_dest, String); String *dest = memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest); dest->append_utf16((const char16_t *)p_contents, p_char_count);
dest->parse_utf16((const char16_t *)p_contents, p_char_count);
} else { } else {
// wchar_t is 32 bit, copy. // wchar_t is 32 bit (UTF-32).
memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count)); String *string = memnew_placement(r_dest, String);
string->append_utf32(Span((const char32_t *)p_contents, p_contents ? _strlen_clipped((const char32_t *)p_contents, p_char_count) : 0));
} }
} }
static GDExtensionInt gdextension_string_to_latin1_chars(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) { static GDExtensionInt gdextension_string_to_latin1_chars(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) {
String *self = (String *)p_self; String *self = (String *)p_self;
CharString cs = self->ascii(true); CharString cs = self->latin1();
GDExtensionInt len = cs.length(); GDExtensionInt len = cs.length();
if (r_text) { if (r_text) {
const char *s_text = cs.ptr(); const char *s_text = cs.ptr();
@ -1040,16 +1052,12 @@ static void gdextension_string_name_new_with_latin1_chars(GDExtensionUninitializ
} }
static void gdextension_string_name_new_with_utf8_chars(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents) { static void gdextension_string_name_new_with_utf8_chars(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents) {
String tmp; String tmp = String::utf8(p_contents);
tmp.parse_utf8(p_contents);
memnew_placement(r_dest, StringName(tmp)); memnew_placement(r_dest, StringName(tmp));
} }
static void gdextension_string_name_new_with_utf8_chars_and_len(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionInt p_size) { static void gdextension_string_name_new_with_utf8_chars_and_len(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionInt p_size) {
String tmp; String tmp = String::utf8(p_contents, p_size);
tmp.parse_utf8(p_contents, p_size);
memnew_placement(r_dest, StringName(tmp)); memnew_placement(r_dest, StringName(tmp));
} }
@ -1543,11 +1551,8 @@ static void gdextension_placeholder_script_instance_update(GDExtensionScriptInst
properties_list.push_back(PropertyInfo::from_dict(d)); properties_list.push_back(PropertyInfo::from_dict(d));
} }
List<Variant> keys; for (const KeyValue<Variant, Variant> &kv : values) {
values.get_key_list(&keys); values_map.insert(kv.key, kv.value);
for (const Variant &E : keys) {
values_map.insert(E, values[E]);
} }
placeholder->update(properties_list, values_map); placeholder->update(properties_list, values_map);
@ -1572,6 +1577,15 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt
return script_instance_extension->instance; return script_instance_extension->instance;
} }
static void gdextension_object_set_script_instance(GDExtensionObjectPtr p_object, GDExtensionScriptInstancePtr p_script_instance) {
ERR_FAIL_NULL(p_object);
Object *o = (Object *)p_object;
ScriptInstance *script_instance = (ScriptInstanceExtension *)p_script_instance;
o->set_script_instance(script_instance);
}
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) { static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) {
memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info)))); memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
@ -1666,7 +1680,10 @@ static void gdextension_editor_help_load_xml_from_utf8_chars(const char *p_data)
#define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr) & gdextension_##m_name) #define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr) & gdextension_##m_name)
void gdextension_setup_interface() { void gdextension_setup_interface() {
#ifndef DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(get_godot_version); REGISTER_INTERFACE_FUNC(get_godot_version);
#endif // DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(get_godot_version2);
REGISTER_INTERFACE_FUNC(mem_alloc); REGISTER_INTERFACE_FUNC(mem_alloc);
REGISTER_INTERFACE_FUNC(mem_realloc); REGISTER_INTERFACE_FUNC(mem_realloc);
REGISTER_INTERFACE_FUNC(mem_free); REGISTER_INTERFACE_FUNC(mem_free);
@ -1809,6 +1826,7 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(placeholder_script_instance_create); REGISTER_INTERFACE_FUNC(placeholder_script_instance_create);
REGISTER_INTERFACE_FUNC(placeholder_script_instance_update); REGISTER_INTERFACE_FUNC(placeholder_script_instance_update);
REGISTER_INTERFACE_FUNC(object_get_script_instance); REGISTER_INTERFACE_FUNC(object_get_script_instance);
REGISTER_INTERFACE_FUNC(object_set_script_instance);
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(callable_custom_create); REGISTER_INTERFACE_FUNC(callable_custom_create);
#endif // DISABLE_DEPRECATED #endif // DISABLE_DEPRECATED

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_INTERFACE_H #pragma once
#define GDEXTENSION_INTERFACE_H
/* This is a C class header, you can copy it and use it directly in your own binders. /* This is a C class header, you can copy it and use it directly in your own binders.
* Together with the JSON file, you should be able to generate any binder. * Together with the JSON file, you should be able to generate any binder.
@ -401,6 +400,9 @@ typedef struct {
typedef void *GDExtensionClassLibraryPtr; typedef void *GDExtensionClassLibraryPtr;
/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */
typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array);
/* Method */ /* Method */
typedef enum { typedef enum {
@ -790,9 +792,22 @@ typedef struct {
const char *string; const char *string;
} GDExtensionGodotVersion; } GDExtensionGodotVersion;
typedef struct {
uint32_t major;
uint32_t minor;
uint32_t patch;
uint32_t hex; // Full version encoded as hexadecimal with one byte (2 hex digits) per number (e.g. for "3.1.12" it would be 0x03010C)
const char *status; // (e.g. "stable", "beta", "rc1", "rc2")
const char *build; // (e.g. "custom_build")
const char *hash; // Full Git commit hash.
uint64_t timestamp; // Git commit date UNIX timestamp in seconds, or 0 if unavailable.
const char *string; // (e.g. "Godot v3.1.4.stable.official.mono")
} GDExtensionGodotVersion2;
/** /**
* @name get_godot_version * @name get_godot_version
* @since 4.1 * @since 4.1
* @deprecated in Godot 4.5. Use `get_godot_version2` instead.
* *
* Gets the Godot version that the GDExtension was loaded into. * Gets the Godot version that the GDExtension was loaded into.
* *
@ -800,6 +815,16 @@ typedef struct {
*/ */
typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version); typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version);
/**
* @name get_godot_version2
* @since 4.5
*
* Gets the Godot version that the GDExtension was loaded into.
*
* @param r_godot_version A pointer to the structure to write the version information into.
*/
typedef void (*GDExtensionInterfaceGetGodotVersion2)(GDExtensionGodotVersion2 *r_godot_version);
/* INTERFACE: Memory */ /* INTERFACE: Memory */
/** /**
@ -2721,6 +2746,17 @@ typedef void (*GDExtensionInterfacePlaceHolderScriptInstanceUpdate)(GDExtensionS
*/ */
typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language); typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language);
/**
* @name object_set_script_instance
* @since 4.5
*
* Set the script instance data attached to this object.
*
* @param p_object A pointer to the Object.
* @param p_script_instance A pointer to the script instance data to attach to this object.
*/
typedef void (*GDExtensionInterfaceObjectSetScriptInstance)(GDExtensionObjectPtr p_object, GDExtensionScriptInstanceDataPtr p_script_instance);
/* INTERFACE: Callable */ /* INTERFACE: Callable */
/** /**
@ -3078,8 +3114,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *
*/ */
typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size);
/**
* @name editor_register_get_classes_used_callback
* @since 4.5
*
* Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension.
*
* This is used by the editor to generate a build profile (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"),
* in order to recompile Godot with only the classes used.
* In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter.
* If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_callback The callback to retrieve the list of classes used.
*/
typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif // GDEXTENSION_INTERFACE_H

View file

@ -307,12 +307,12 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
bool compatible = true; bool compatible = true;
// Check version lexicographically. // Check version lexicographically.
if (VERSION_MAJOR != compatibility_minimum[0]) { if (GODOT_VERSION_MAJOR != compatibility_minimum[0]) {
compatible = VERSION_MAJOR > compatibility_minimum[0]; compatible = GODOT_VERSION_MAJOR > compatibility_minimum[0];
} else if (VERSION_MINOR != compatibility_minimum[1]) { } else if (GODOT_VERSION_MINOR != compatibility_minimum[1]) {
compatible = VERSION_MINOR > compatibility_minimum[1]; compatible = GODOT_VERSION_MINOR > compatibility_minimum[1];
} else { } else {
compatible = VERSION_PATCH >= compatibility_minimum[2]; compatible = GODOT_VERSION_PATCH >= compatibility_minimum[2];
} }
if (!compatible) { if (!compatible) {
ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path)); ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
@ -334,15 +334,15 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
} }
compatible = true; compatible = true;
if (VERSION_MAJOR != compatibility_maximum[0]) { if (GODOT_VERSION_MAJOR != compatibility_maximum[0]) {
compatible = VERSION_MAJOR < compatibility_maximum[0]; compatible = GODOT_VERSION_MAJOR < compatibility_maximum[0];
} else if (VERSION_MINOR != compatibility_maximum[1]) { } else if (GODOT_VERSION_MINOR != compatibility_maximum[1]) {
compatible = VERSION_MINOR < compatibility_maximum[1]; compatible = GODOT_VERSION_MINOR < compatibility_maximum[1];
} }
#if VERSION_PATCH #if GODOT_VERSION_PATCH
// #if check to avoid -Wtype-limits warning when 0. // #if check to avoid -Wtype-limits warning when 0.
else { else {
compatible = VERSION_PATCH <= compatibility_maximum[2]; compatible = GODOT_VERSION_PATCH <= compatibility_maximum[2];
} }
#endif #endif

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_LIBRARY_LOADER_H #pragma once
#define GDEXTENSION_LIBRARY_LOADER_H
#include <functional> #include <functional>
@ -38,6 +37,8 @@
#include "core/os/shared_object.h" #include "core/os/shared_object.h"
class GDExtensionLibraryLoader : public GDExtensionLoader { class GDExtensionLibraryLoader : public GDExtensionLoader {
GDSOFTCLASS(GDExtensionLibraryLoader, GDExtensionLoader);
friend class GDExtensionManager; friend class GDExtensionManager;
friend class GDExtension; friend class GDExtension;
@ -81,5 +82,3 @@ public:
Error parse_gdextension_file(const String &p_path); Error parse_gdextension_file(const String &p_path);
}; };
#endif // GDEXTENSION_LIBRARY_LOADER_H

View file

@ -28,14 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_LOADER_H #pragma once
#define GDEXTENSION_LOADER_H
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
class GDExtension; class GDExtension;
class GDExtensionLoader : public RefCounted { class GDExtensionLoader : public RefCounted {
GDSOFTCLASS(GDExtensionLoader, GDExtensionLoader);
public: public:
virtual Error open_library(const String &p_path) = 0; virtual Error open_library(const String &p_path) = 0;
virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) = 0; virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) = 0;
@ -44,5 +45,3 @@ public:
virtual bool has_library_changed() const = 0; virtual bool has_library_changed() const = 0;
virtual bool library_exists() const = 0; virtual bool library_exists() const = 0;
}; };
#endif // GDEXTENSION_LOADER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_MANAGER_H #pragma once
#define GDEXTENSION_MANAGER_H
#include "core/extension/gdextension.h" #include "core/extension/gdextension.h"
@ -92,5 +91,3 @@ public:
}; };
VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus) VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus)
#endif // GDEXTENSION_MANAGER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H #pragma once
#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
@ -58,5 +57,3 @@ public:
}; };
#endif // DISABLE_DEPRECATED #endif // DISABLE_DEPRECATED
#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H

View file

@ -1,55 +1,37 @@
import zlib import methods
def run(target, source, env): def run(target, source, env):
src = str(source[0]) buffer = methods.get_buffer(str(source[0]))
dst = str(target[0]) decomp_size = len(buffer)
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: buffer = methods.compress_buffer(buffer)
buf = f.read()
decomp_size = len(buf)
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
g.write(
"""/* THIS FILE IS GENERATED DO NOT EDIT */
#ifndef GDEXTENSION_INTERFACE_DUMP_H
#define GDEXTENSION_INTERFACE_DUMP_H
with methods.generated_wrapper(str(target[0])) as file:
file.write(f"""\
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
#include "core/io/compression.h" #include "core/io/compression.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
""" 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)}
}};
g.write("static const int _gdextension_interface_data_compressed_size = " + str(len(buf)) + ";\n") class GDExtensionInterfaceDump {{
g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n") public:
g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n") static void generate_gdextension_interface_file(const String &p_path) {{
for i in range(len(buf)): Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
g.write("\t" + str(buf[i]) + ",\n") ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
g.write("};\n") Vector<uint8_t> data;
data.resize(_gdextension_interface_data_uncompressed_size);
g.write( int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
""" ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
class GDExtensionInterfaceDump { fa->store_buffer(data.ptr(), data.size());
public: }};
static void generate_gdextension_interface_file(const String &p_path) { }};
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
Vector<uint8_t> data;
data.resize(_gdextension_interface_data_uncompressed_size);
int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
fa->store_buffer(data.ptr(), data.size());
};
};
#endif // TOOLS_ENABLED #endif // TOOLS_ENABLED
""")
#endif // GDEXTENSION_INTERFACE_DUMP_H
"""
)

View file

@ -119,10 +119,7 @@ def generate_ex_version(argcount, const=False, returns=False):
def run(target, source, env): def run(target, source, env):
max_versions = 12 max_versions = 12
txt = """ txt = "#pragma once"
#ifndef GDEXTENSION_WRAPPERS_GEN_H
#define GDEXTENSION_WRAPPERS_GEN_H
"""
for i in range(max_versions + 1): for i in range(max_versions + 1):
txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n" txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n"
@ -138,7 +135,5 @@ def run(target, source, env):
txt += generate_mod_version(i, True, False) txt += generate_mod_version(i, True, False)
txt += generate_mod_version(i, True, True) txt += generate_mod_version(i, True, True)
txt += "\n#endif\n"
with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f: with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
f.write(txt) f.write(txt)

View file

@ -28,12 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef DEFAULT_CONTROLLER_MAPPINGS_H #pragma once
#define DEFAULT_CONTROLLER_MAPPINGS_H
class DefaultControllerMappings { class DefaultControllerMappings {
public: public:
static const char *mappings[]; static const char *mappings[];
}; };
#endif // DEFAULT_CONTROLLER_MAPPINGS_H

View file

@ -219,7 +219,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
continue; continue;
} }
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length()); String name = pi.name.substr(pi.name.find_char('/') + 1);
r_options->push_back(name.quote()); r_options->push_back(name.quote());
} }
} }
@ -1594,8 +1594,8 @@ void Input::parse_mapping(const String &p_mapping) {
continue; continue;
} }
String output = entry[idx].get_slice(":", 0).replace(" ", ""); String output = entry[idx].get_slicec(':', 0).remove_char(' ');
String input = entry[idx].get_slice(":", 1).replace(" ", ""); String input = entry[idx].get_slicec(':', 1).remove_char(' ');
if (output.length() < 1 || input.length() < 2) { if (output.length() < 1 || input.length() < 2) {
continue; continue;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef INPUT_H #pragma once
#define INPUT_H
#include "core/input/input_event.h" #include "core/input/input_event.h"
#include "core/object/object.h" #include "core/object/object.h"
@ -86,7 +85,7 @@ public:
typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event); typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
private: private:
BitField<MouseButtonMask> mouse_button_mask; BitField<MouseButtonMask> mouse_button_mask = MouseButtonMask::NONE;
RBSet<Key> key_label_pressed; RBSet<Key> key_label_pressed;
RBSet<Key> physical_keys_pressed; RBSet<Key> physical_keys_pressed;
@ -403,5 +402,3 @@ public:
VARIANT_ENUM_CAST(Input::MouseMode); VARIANT_ENUM_CAST(Input::MouseMode);
VARIANT_ENUM_CAST(Input::CursorShape); VARIANT_ENUM_CAST(Input::CursorShape);
#endif // INPUT_H

View file

@ -2,18 +2,22 @@
from collections import OrderedDict from collections import OrderedDict
import methods
def make_default_controller_mappings(target, source, env): def make_default_controller_mappings(target, source, env):
dst = str(target[0]) with methods.generated_wrapper(str(target[0])) as file:
with open(dst, "w", encoding="utf-8", newline="\n") as g: file.write("""\
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") #include "core/input/default_controller_mappings.h"
g.write('#include "core/typedefs.h"\n')
g.write('#include "core/input/default_controller_mappings.h"\n') #include "core/typedefs.h"
""")
# ensure mappings have a consistent order # ensure mappings have a consistent order
platform_mappings: dict = OrderedDict() platform_mappings = OrderedDict()
for src_path in source: for src_path in map(str, source):
with open(str(src_path), "r", encoding="utf-8") as f: with open(src_path, "r", encoding="utf-8") as f:
# read mapping file and skip header # read mapping file and skip header
mapping_file_lines = f.readlines()[2:] mapping_file_lines = f.readlines()[2:]
@ -32,28 +36,28 @@ def make_default_controller_mappings(target, source, env):
line_parts = line.split(",") line_parts = line.split(",")
guid = line_parts[0] guid = line_parts[0]
if guid in platform_mappings[current_platform]: if guid in platform_mappings[current_platform]:
g.write( file.write(
"// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format( "// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
src_path, current_platform, platform_mappings[current_platform][guid] src_path, current_platform, platform_mappings[current_platform][guid]
) )
) )
platform_mappings[current_platform][guid] = line platform_mappings[current_platform][guid] = line
platform_variables = { PLATFORM_VARIABLES = {
"Linux": "#ifdef LINUXBSD_ENABLED", "Linux": "LINUXBSD",
"Windows": "#ifdef WINDOWS_ENABLED", "Windows": "WINDOWS",
"Mac OS X": "#ifdef MACOS_ENABLED", "Mac OS X": "MACOS",
"Android": "#ifdef ANDROID_ENABLED", "Android": "ANDROID",
"iOS": "#ifdef IOS_ENABLED", "iOS": "IOS",
"Web": "#ifdef WEB_ENABLED", "Web": "WEB",
} }
g.write("const char* DefaultControllerMappings::mappings[] = {\n") file.write("const char *DefaultControllerMappings::mappings[] = {\n")
for platform, mappings in platform_mappings.items(): for platform, mappings in platform_mappings.items():
variable = platform_variables[platform] variable = PLATFORM_VARIABLES[platform]
g.write("{}\n".format(variable)) file.write(f"#ifdef {variable}_ENABLED\n")
for mapping in mappings.values(): for mapping in mappings.values():
g.write('\t"{}",\n'.format(mapping)) file.write(f'\t"{mapping}",\n')
g.write("#endif\n") file.write(f"#endif // {variable}_ENABLED\n")
g.write("\tnullptr\n};\n") file.write("\tnullptr\n};\n")

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef INPUT_ENUMS_H #pragma once
#define INPUT_ENUMS_H
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
@ -138,4 +137,10 @@ inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
return MouseButtonMask(1 << ((int)button - 1)); return MouseButtonMask(1 << ((int)button - 1));
} }
#endif // INPUT_ENUMS_H constexpr MouseButtonMask operator|(MouseButtonMask p_a, MouseButtonMask p_b) {
return static_cast<MouseButtonMask>(static_cast<int>(p_a) | static_cast<int>(p_b));
}
constexpr MouseButtonMask &operator|=(MouseButtonMask &p_a, MouseButtonMask p_b) {
return p_a = p_a | p_b;
}

View file

@ -230,7 +230,7 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif
} }
BitField<KeyModifierMask> InputEventWithModifiers::get_modifiers_mask() const { BitField<KeyModifierMask> InputEventWithModifiers::get_modifiers_mask() const {
BitField<KeyModifierMask> mask; BitField<KeyModifierMask> mask = {};
if (is_ctrl_pressed()) { if (is_ctrl_pressed()) {
mask.set_flag(KeyModifierMask::CTRL); mask.set_flag(KeyModifierMask::CTRL);
} }
@ -385,11 +385,11 @@ bool InputEventKey::is_echo() const {
} }
Key InputEventKey::get_keycode_with_modifiers() const { Key InputEventKey::get_keycode_with_modifiers() const {
return keycode | (int64_t)get_modifiers_mask(); return keycode | get_modifiers_mask();
} }
Key InputEventKey::get_physical_keycode_with_modifiers() const { Key InputEventKey::get_physical_keycode_with_modifiers() const {
return physical_keycode | (int64_t)get_modifiers_mask(); return physical_keycode | get_modifiers_mask();
} }
Key InputEventKey::get_key_label_with_modifiers() const { Key InputEventKey::get_key_label_with_modifiers() const {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef INPUT_EVENT_H #pragma once
#define INPUT_EVENT_H
#include "core/input/input_enums.h" #include "core/input/input_enums.h"
#include "core/io/resource.h" #include "core/io/resource.h"
@ -209,7 +208,7 @@ public:
class InputEventMouse : public InputEventWithModifiers { class InputEventMouse : public InputEventWithModifiers {
GDCLASS(InputEventMouse, InputEventWithModifiers); GDCLASS(InputEventMouse, InputEventWithModifiers);
BitField<MouseButtonMask> button_mask; BitField<MouseButtonMask> button_mask = MouseButtonMask::NONE;
Vector2 pos; Vector2 pos;
Vector2 global_pos; Vector2 global_pos;
@ -595,5 +594,3 @@ public:
InputEventShortcut(); InputEventShortcut();
}; };
#endif // INPUT_EVENT_H

View file

@ -47,6 +47,8 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE)); ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE));
ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
ClassDB::bind_method(D_METHOD("get_action_description", "action"), &InputMap::get_action_description);
ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone); ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone); ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone);
ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
@ -106,7 +108,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis
continue; continue;
} }
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length()); String name = pi.name.substr(pi.name.find_char('/') + 1);
r_options->push_back(name.quote()); r_options->push_back(name.quote());
} }
} }
@ -181,6 +183,25 @@ bool InputMap::has_action(const StringName &p_action) const {
return input_map.has(p_action); return input_map.has(p_action);
} }
String InputMap::get_action_description(const StringName &p_action) const {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), String(), suggest_actions(p_action));
String ret;
const List<Ref<InputEvent>> &inputs = input_map[p_action].inputs;
for (Ref<InputEventKey> iek : inputs) {
if (iek.is_valid()) {
if (!ret.is_empty()) {
ret += RTR(" or ");
}
ret += iek->as_text();
}
}
if (ret.is_empty()) {
ret = RTR("Action has no bound inputs");
}
return ret;
}
float InputMap::action_get_deadzone(const StringName &p_action) { float InputMap::action_get_deadzone(const StringName &p_action) {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action)); ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action));
@ -304,7 +325,7 @@ void InputMap::load_from_project_settings() {
continue; continue;
} }
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length()); String name = pi.name.substr(pi.name.find_char('/') + 1);
Dictionary action = GLOBAL_GET(pi.name); Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE; float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
@ -344,6 +365,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_cut", TTRC("Cut") }, { "ui_cut", TTRC("Cut") },
{ "ui_copy", TTRC("Copy") }, { "ui_copy", TTRC("Copy") },
{ "ui_paste", TTRC("Paste") }, { "ui_paste", TTRC("Paste") },
{ "ui_focus_mode", TTRC("Toggle Tab Focus Mode") },
{ "ui_undo", TTRC("Undo") }, { "ui_undo", TTRC("Undo") },
{ "ui_redo", TTRC("Redo") }, { "ui_redo", TTRC("Redo") },
{ "ui_text_completion_query", TTRC("Completion Query") }, { "ui_text_completion_query", TTRC("Completion Query") },
@ -397,17 +419,21 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_submit", TTRC("Submit Text") }, { "ui_text_submit", TTRC("Submit Text") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") }, { "ui_graph_duplicate", TTRC("Duplicate Nodes") },
{ "ui_graph_delete", TTRC("Delete Nodes") }, { "ui_graph_delete", TTRC("Delete Nodes") },
{ "ui_graph_follow_left", TTRC("Follow Input Port Connection") },
{ "ui_graph_follow_right", TTRC("Follow Output Port Connection") },
{ "ui_filedialog_up_one_level", TTRC("Go Up One Level") }, { "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
{ "ui_filedialog_refresh", TTRC("Refresh") }, { "ui_filedialog_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") }, { "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") }, { "ui_swap_input_direction ", TTRC("Swap Input Direction") },
{ "ui_unicode_start", TTRC("Start Unicode Character Input") }, { "ui_unicode_start", TTRC("Start Unicode Character Input") },
{ "ui_colorpicker_delete_preset", TTRC("Toggle License Notices") },
{ "ui_accessibility_drag_and_drop", TTRC("Accessibility: Keyboard Drag and Drop") },
{ "", ""} { "", ""}
/* clang-format on */ /* clang-format on */
}; };
String InputMap::get_builtin_display_name(const String &p_name) const { String InputMap::get_builtin_display_name(const String &p_name) const {
int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName); constexpr int len = std::size(_builtin_action_display_names);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if (_builtin_action_display_names[i].name == p_name) { if (_builtin_action_display_names[i].name == p_name) {
@ -487,6 +513,9 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::END)); inputs.push_back(InputEventKey::create_reference(Key::END));
default_builtin_cache.insert("ui_end", inputs); default_builtin_cache.insert("ui_end", inputs);
inputs = List<Ref<InputEvent>>();
default_builtin_cache.insert("ui_accessibility_drag_and_drop", inputs);
// ///// UI basic Shortcuts ///// // ///// UI basic Shortcuts /////
inputs = List<Ref<InputEvent>>(); inputs = List<Ref<InputEvent>>();
@ -499,6 +528,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL)); inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_copy", inputs); default_builtin_cache.insert("ui_copy", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::M | KeyModifierMask::CTRL));
default_builtin_cache.insert("ui_focus_mode", inputs);
inputs = List<Ref<InputEvent>>(); inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL)); inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT)); inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
@ -772,6 +805,22 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE)); inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
default_builtin_cache.insert("ui_graph_delete", inputs); default_builtin_cache.insert("ui_graph_delete", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_graph_follow_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_graph_follow_left.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_graph_follow_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_graph_follow_right.macos", inputs);
// ///// UI File Dialog Shortcuts ///// // ///// UI File Dialog Shortcuts /////
inputs = List<Ref<InputEvent>>(); inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE)); inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
@ -789,6 +838,12 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL)); inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_swap_input_direction", inputs); default_builtin_cache.insert("ui_swap_input_direction", inputs);
// ///// UI ColorPicker Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::X));
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
default_builtin_cache.insert("ui_colorpicker_delete_preset", inputs);
return default_builtin_cache; return default_builtin_cache;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef INPUT_MAP_H #pragma once
#define INPUT_MAP_H
#include "core/input/input_event.h" #include "core/input/input_event.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
@ -86,6 +85,8 @@ public:
void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE); void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE);
void erase_action(const StringName &p_action); void erase_action(const StringName &p_action);
String get_action_description(const StringName &p_action) const;
float action_get_deadzone(const StringName &p_action); float action_get_deadzone(const StringName &p_action);
void action_set_deadzone(const StringName &p_action, float p_deadzone); void action_set_deadzone(const StringName &p_action, float p_deadzone);
void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event); void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
@ -116,5 +117,3 @@ public:
InputMap(); InputMap();
~InputMap(); ~InputMap();
}; };
#endif // INPUT_MAP_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef SHORTCUT_H #pragma once
#define SHORTCUT_H
#include "core/input/input_event.h" #include "core/input/input_event.h"
#include "core/io/resource.h" #include "core/io/resource.h"
@ -55,5 +54,3 @@ public:
static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2); static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2);
}; };
#endif // SHORTCUT_H

View file

@ -42,6 +42,12 @@
#include <brotli/decode.h> #include <brotli/decode.h>
#endif #endif
// 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;
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) { int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {
switch (p_mode) { switch (p_mode) {
case MODE_BROTLI: { case MODE_BROTLI: {
@ -187,12 +193,22 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
return total; return total;
} break; } break;
case MODE_ZSTD: { case MODE_ZSTD: {
ZSTD_DCtx *dctx = ZSTD_createDCtx(); MutexLock lock(mutex);
if (zstd_long_distance_matching) {
ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_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;
} }
int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
ZSTD_freeDCtx(dctx); int ret = ZSTD_decompressDCtx(current_zstd_d_ctx, p_dst, p_dst_max_size, p_src, p_src_size);
return ret; return ret;
} break; } break;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef COMPRESSION_H #pragma once
#define COMPRESSION_H
#include "core/templates/vector.h" #include "core/templates/vector.h"
#include "core/typedefs.h" #include "core/typedefs.h"
@ -56,5 +55,3 @@ public:
static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD); static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode); static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode);
}; };
#endif // COMPRESSION_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef CONFIG_FILE_H #pragma once
#define CONFIG_FILE_H
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -78,5 +77,3 @@ public:
Error save_encrypted(const String &p_path, const Vector<uint8_t> &p_key); Error save_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
Error save_encrypted_pass(const String &p_path, const String &p_pass); Error save_encrypted_pass(const String &p_path, const String &p_pass);
}; };
#endif // CONFIG_FILE_H

View file

@ -146,7 +146,7 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
full_dir = p_dir; full_dir = p_dir;
} }
full_dir = full_dir.replace("\\", "/"); full_dir = full_dir.replace_char('\\', '/');
String base; String base;
@ -336,7 +336,7 @@ Ref<DirAccess> DirAccess::create_temp(const String &p_prefix, bool p_keep, Error
uint32_t suffix_i = 0; uint32_t suffix_i = 0;
String path; String path;
while (true) { while (true) {
String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", ""); String datetime = Time::get_singleton()->get_datetime_string_from_system().remove_chars("-T:");
datetime += itos(Time::get_singleton()->get_ticks_usec()); datetime += itos(Time::get_singleton()->get_ticks_usec());
String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : ""); String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
path = (p_prefix.is_empty() ? "" : p_prefix + "-") + suffix; path = (p_prefix.is_empty() ? "" : p_prefix + "-") + suffix;
@ -626,6 +626,10 @@ bool DirAccess::is_case_sensitive(const String &p_path) const {
return true; return true;
} }
bool DirAccess::is_equivalent(const String &p_path_a, const String &p_path_b) const {
return p_path_a == p_path_b;
}
void DirAccess::_bind_methods() { void DirAccess::_bind_methods() {
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open); ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error); ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
@ -671,6 +675,7 @@ void DirAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden); ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive); ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive);
ClassDB::bind_method(D_METHOD("is_equivalent", "path_a", "path_b"), &DirAccess::is_equivalent);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef DIR_ACCESS_H #pragma once
#define DIR_ACCESS_H
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -169,10 +168,9 @@ public:
virtual bool is_case_sensitive(const String &p_path) const; virtual bool is_case_sensitive(const String &p_path) const;
virtual bool is_bundle(const String &p_file) const { return false; } virtual bool is_bundle(const String &p_file) const { return false; }
virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const;
public: public:
DirAccess() {} DirAccess() {}
virtual ~DirAccess(); virtual ~DirAccess();
}; };
#endif // DIR_ACCESS_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef DTLS_SERVER_H #pragma once
#define DTLS_SERVER_H
#include "core/io/net_socket.h" #include "core/io/net_socket.h"
#include "core/io/packet_peer_dtls.h" #include "core/io/packet_peer_dtls.h"
@ -53,5 +52,3 @@ public:
DTLSServer() {} DTLSServer() {}
}; };
#endif // DTLS_SERVER_H

View file

@ -104,7 +104,7 @@ Ref<FileAccess> FileAccess::create_temp(int p_mode_flags, const String &p_prefix
uint32_t suffix_i = 0; uint32_t suffix_i = 0;
String path; String path;
while (true) { while (true) {
String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", ""); String datetime = Time::get_singleton()->get_datetime_string_from_system().remove_chars("-T:");
datetime += itos(Time::get_singleton()->get_ticks_usec()); datetime += itos(Time::get_singleton()->get_ticks_usec());
String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : ""); String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
path = TEMP_DIR.path_join((p_prefix.is_empty() ? "" : p_prefix + "-") + suffix + (extension.is_empty() ? "" : "." + extension)); path = TEMP_DIR.path_join((p_prefix.is_empty() ? "" : p_prefix + "-") + suffix + (extension.is_empty() ? "" : "." + extension));
@ -259,7 +259,7 @@ FileAccess::AccessType FileAccess::get_access_type() const {
String FileAccess::fix_path(const String &p_path) const { String FileAccess::fix_path(const String &p_path) const {
// Helper used by file accesses that use a single filesystem. // Helper used by file accesses that use a single filesystem.
String r_path = p_path.replace("\\", "/"); String r_path = p_path.replace_char('\\', '/');
switch (_access_type) { switch (_access_type) {
case ACCESS_RESOURCES: { case ACCESS_RESOURCES: {
@ -313,9 +313,15 @@ uint16_t FileAccess::get_16() const {
uint16_t data = 0; uint16_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint16_t)); get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint16_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP16(data);
}
#else
if (big_endian) { if (big_endian) {
data = BSWAP16(data); data = BSWAP16(data);
} }
#endif
return data; return data;
} }
@ -324,9 +330,15 @@ uint32_t FileAccess::get_32() const {
uint32_t data = 0; uint32_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint32_t)); get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint32_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP32(data);
}
#else
if (big_endian) { if (big_endian) {
data = BSWAP32(data); data = BSWAP32(data);
} }
#endif
return data; return data;
} }
@ -335,9 +347,15 @@ uint64_t FileAccess::get_64() const {
uint64_t data = 0; uint64_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint64_t)); get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint64_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP64(data);
}
#else
if (big_endian) { if (big_endian) {
data = BSWAP64(data); data = BSWAP64(data);
} }
#endif
return data; return data;
} }
@ -429,7 +447,7 @@ class CharBuffer {
public: public:
_FORCE_INLINE_ CharBuffer() : _FORCE_INLINE_ CharBuffer() :
buffer(stack_buffer), buffer(stack_buffer),
capacity(sizeof(stack_buffer) / sizeof(char)) { capacity(std::size(stack_buffer)) {
} }
_FORCE_INLINE_ void push_back(char c) { _FORCE_INLINE_ void push_back(char c) {
@ -565,7 +583,7 @@ String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
w[len] = 0; w[len] = 0;
String s; String s;
s.parse_utf8((const char *)w, len, p_skip_cr); s.append_utf8((const char *)w, len, p_skip_cr);
return s; return s;
} }
@ -574,25 +592,43 @@ bool FileAccess::store_8(uint8_t p_dest) {
} }
bool FileAccess::store_16(uint16_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) { if (big_endian) {
p_dest = BSWAP16(p_dest); p_dest = BSWAP16(p_dest);
} }
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint16_t)); return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint16_t));
} }
bool FileAccess::store_32(uint32_t p_dest) { bool FileAccess::store_32(uint32_t p_dest) {
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
p_dest = BSWAP32(p_dest);
}
#else
if (big_endian) { if (big_endian) {
p_dest = BSWAP32(p_dest); p_dest = BSWAP32(p_dest);
} }
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint32_t)); return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint32_t));
} }
bool FileAccess::store_64(uint64_t p_dest) { bool FileAccess::store_64(uint64_t p_dest) {
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
p_dest = BSWAP64(p_dest);
}
#else
if (big_endian) { if (big_endian) {
p_dest = BSWAP64(p_dest); p_dest = BSWAP64(p_dest);
} }
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint64_t)); return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint64_t));
} }
@ -629,8 +665,29 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
Ref<FileAccess> fa = create_for_path(p_file); Ref<FileAccess> fa = create_for_path(p_file);
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file)); ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file));
uint64_t mt = fa->_get_modified_time(p_file); return fa->_get_modified_time(p_file);
return mt; }
uint64_t FileAccess::get_access_time(const String &p_file) {
if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return 0;
}
Ref<FileAccess> fa = create_for_path(p_file);
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
return fa->_get_access_time(p_file);
}
int64_t FileAccess::get_size(const String &p_file) {
if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return PackedData::get_singleton()->get_size(p_file);
}
Ref<FileAccess> fa = create_for_path(p_file);
ERR_FAIL_COND_V_MSG(fa.is_null(), -1, "Cannot create FileAccess for path '" + p_file + "'.");
return fa->_get_size(p_file);
} }
BitField<FileAccess::UnixPermissionFlags> FileAccess::get_unix_permissions(const String &p_file) { BitField<FileAccess::UnixPermissionFlags> FileAccess::get_unix_permissions(const String &p_file) {
@ -723,9 +780,7 @@ String FileAccess::get_pascal_string() {
get_buffer((uint8_t *)cs.ptr(), sl); get_buffer((uint8_t *)cs.ptr(), sl);
cs[sl] = 0; cs[sl] = 0;
String ret; return String::utf8(cs.ptr(), sl);
ret.parse_utf8(cs.ptr(), sl);
return ret;
} }
bool FileAccess::store_line(const String &p_line) { bool FileAccess::store_line(const String &p_line) {
@ -817,7 +872,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
} }
String ret; String ret;
ret.parse_utf8((const char *)array.ptr(), array.size()); ret.append_utf8((const char *)array.ptr(), array.size());
return ret; return ret;
} }
@ -931,7 +986,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float); ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double); ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real); ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t>(FileAccess::*)(int64_t) const) & FileAccess::get_buffer); ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t> (FileAccess::*)(int64_t) const) & FileAccess::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line); ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
@ -950,7 +1005,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float); ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double); ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real); ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer); ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool (FileAccess::*)(const Vector<uint8_t> &))&FileAccess::store_buffer);
ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line); ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string); ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
@ -963,6 +1018,8 @@ void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists); ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time); ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_access_time", "file"), &FileAccess::get_access_time);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_size", "file"), &FileAccess::get_size);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_unix_permissions", "file"), &FileAccess::get_unix_permissions); ClassDB::bind_static_method("FileAccess", D_METHOD("get_unix_permissions", "file"), &FileAccess::get_unix_permissions);
ClassDB::bind_static_method("FileAccess", D_METHOD("set_unix_permissions", "file", "permissions"), &FileAccess::set_unix_permissions); ClassDB::bind_static_method("FileAccess", D_METHOD("set_unix_permissions", "file", "permissions"), &FileAccess::set_unix_permissions);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_H #pragma once
#define FILE_ACCESS_H
#include "core/io/compression.h" #include "core/io/compression.h"
#include "core/math/math_defs.h" #include "core/math/math_defs.h"
@ -87,7 +86,11 @@ public:
typedef void (*FileCloseFailNotify)(const String &); typedef void (*FileCloseFailNotify)(const String &);
typedef Ref<FileAccess> (*CreateFunc)(); typedef Ref<FileAccess> (*CreateFunc)();
#ifdef BIG_ENDIAN_ENABLED
bool big_endian = true;
#else
bool big_endian = false; bool big_endian = false;
#endif
bool real_is_double = false; bool real_is_double = false;
virtual BitField<UnixPermissionFlags> _get_unix_permissions(const String &p_file) = 0; virtual BitField<UnixPermissionFlags> _get_unix_permissions(const String &p_file) = 0;
@ -105,6 +108,8 @@ protected:
virtual String fix_path(const String &p_path) 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 virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0; virtual uint64_t _get_modified_time(const String &p_file) = 0;
virtual uint64_t _get_access_time(const String &p_file) = 0;
virtual int64_t _get_size(const String &p_file) = 0;
virtual void _set_access_type(AccessType p_access); virtual void _set_access_type(AccessType p_access);
static FileCloseFailNotify close_fail_notify; static FileCloseFailNotify close_fail_notify;
@ -239,6 +244,8 @@ public:
static CreateFunc get_create_func(AccessType p_access); static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file); static uint64_t get_modified_time(const String &p_file);
static uint64_t get_access_time(const String &p_file);
static int64_t get_size(const String &p_file);
static BitField<FileAccess::UnixPermissionFlags> get_unix_permissions(const String &p_file); static BitField<FileAccess::UnixPermissionFlags> get_unix_permissions(const String &p_file);
static Error set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions); static Error set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions);
@ -273,5 +280,3 @@ public:
VARIANT_ENUM_CAST(FileAccess::CompressionMode); VARIANT_ENUM_CAST(FileAccess::CompressionMode);
VARIANT_ENUM_CAST(FileAccess::ModeFlags); VARIANT_ENUM_CAST(FileAccess::ModeFlags);
VARIANT_BITFIELD_CAST(FileAccess::UnixPermissionFlags); VARIANT_BITFIELD_CAST(FileAccess::UnixPermissionFlags);
#endif // FILE_ACCESS_H

View file

@ -247,7 +247,11 @@ bool FileAccessCompressed::eof_reached() const {
} }
uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const { uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); if (p_length == 0) {
return 0;
}
ERR_FAIL_NULL_V(p_dst, -1);
ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use."); ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode."); ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
@ -256,29 +260,38 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con
return 0; return 0;
} }
for (uint64_t i = 0; i < p_length; i++) { uint64_t dst_idx = 0;
p_dst[i] = read_ptr[read_pos]; while (true) {
read_pos++; // Copy over as much of our current block as possible.
if (read_pos >= read_block_size) { const uint32_t copied_bytes_count = MIN(p_length - dst_idx, read_block_size - read_pos);
read_block++; memcpy(p_dst + dst_idx, read_ptr + read_pos, copied_bytes_count);
dst_idx += copied_bytes_count;
read_pos += copied_bytes_count;
if (read_block < read_block_count) { if (dst_idx == p_length) {
//read another block of compressed data // We're done! We read back all that was requested.
f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); return p_length;
int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt.");
read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
read_pos = 0;
} else {
read_block--;
at_end = true;
if (i + 1 < p_length) {
read_eof = true;
}
return i + 1;
}
} }
// We're not done yet; try reading the next block.
read_block++;
if (read_block >= read_block_count) {
// We're done! We read back the whole file.
read_block--;
at_end = true;
if (dst_idx + 1 < p_length) {
read_eof = true;
}
return dst_idx;
}
// Read the next block of compressed data.
f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize);
int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt.");
read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
read_pos = 0;
} }
return p_length; return p_length;
@ -332,6 +345,22 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
} }
} }
uint64_t FileAccessCompressed::_get_access_time(const String &p_file) {
if (f.is_valid()) {
return f->get_access_time(p_file);
} else {
return 0;
}
}
int64_t FileAccessCompressed::_get_size(const String &p_file) {
if (f.is_valid()) {
return f->get_size(p_file);
} else {
return -1;
}
}
BitField<FileAccess::UnixPermissionFlags> FileAccessCompressed::_get_unix_permissions(const String &p_file) { BitField<FileAccess::UnixPermissionFlags> FileAccessCompressed::_get_unix_permissions(const String &p_file) {
if (f.is_valid()) { if (f.is_valid()) {
return f->_get_unix_permissions(p_file); return f->_get_unix_permissions(p_file);

View file

@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_COMPRESSED_H #pragma once
#define FILE_ACCESS_COMPRESSED_H
#include "core/io/compression.h" #include "core/io/compression.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
class FileAccessCompressed : public FileAccess { class FileAccessCompressed : public FileAccess {
GDSOFTCLASS(FileAccessCompressed, FileAccess);
Compression::Mode cmode = Compression::MODE_ZSTD; Compression::Mode cmode = Compression::MODE_ZSTD;
bool writing = false; bool writing = false;
uint64_t write_pos = 0; uint64_t write_pos = 0;
@ -94,6 +94,8 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override; virtual uint64_t _get_modified_time(const String &p_file) override;
virtual uint64_t _get_access_time(const String &p_file) override;
virtual int64_t _get_size(const String &p_file) override;
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override; virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override;
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override; virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
@ -107,5 +109,3 @@ public:
FileAccessCompressed() {} FileAccessCompressed() {}
virtual ~FileAccessCompressed(); virtual ~FileAccessCompressed();
}; };
#endif // FILE_ACCESS_COMPRESSED_H

View file

@ -30,9 +30,17 @@
#include "file_access_encrypted.h" #include "file_access_encrypted.h"
#include "core/crypto/crypto_core.h"
#include "core/variant/variant.h" #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) { 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_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); ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
@ -48,9 +56,15 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
key = p_key; key = p_key;
if (p_iv.is_empty()) { if (p_iv.is_empty()) {
iv.resize(16); iv.resize(16);
CryptoCore::RandomGenerator rng; if (unlikely(!_fae_static_rng)) {
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator."); _fae_static_rng = memnew(CryptoCore::RandomGenerator);
Error err = rng.get_random_bytes(iv.ptrw(), 16); 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); ERR_FAIL_COND_V(err != OK, err);
} else { } else {
ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
@ -265,7 +279,27 @@ bool FileAccessEncrypted::file_exists(const String &p_name) {
} }
uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) { uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) {
return 0; if (file.is_valid()) {
return file->get_modified_time(p_file);
} else {
return 0;
}
}
uint64_t FileAccessEncrypted::_get_access_time(const String &p_file) {
if (file.is_valid()) {
return file->get_access_time(p_file);
} else {
return 0;
}
}
int64_t FileAccessEncrypted::_get_size(const String &p_file) {
if (file.is_valid()) {
return file->get_size(p_file);
} else {
return -1;
}
} }
BitField<FileAccess::UnixPermissionFlags> FileAccessEncrypted::_get_unix_permissions(const String &p_file) { BitField<FileAccess::UnixPermissionFlags> FileAccessEncrypted::_get_unix_permissions(const String &p_file) {

View file

@ -28,14 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_ENCRYPTED_H #pragma once
#define FILE_ACCESS_ENCRYPTED_H
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#define ENCRYPTED_HEADER_MAGIC 0x43454447 #define ENCRYPTED_HEADER_MAGIC 0x43454447
class FileAccessEncrypted : public FileAccess { class FileAccessEncrypted : public FileAccess {
GDSOFTCLASS(FileAccessEncrypted, FileAccess);
public: public:
enum Mode : int32_t { enum Mode : int32_t {
MODE_READ, MODE_READ,
@ -57,6 +59,8 @@ private:
void _close(); void _close();
static CryptoCore::RandomGenerator *_fae_static_rng;
public: 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(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); Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
@ -87,6 +91,8 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override; virtual uint64_t _get_modified_time(const String &p_file) override;
virtual uint64_t _get_access_time(const String &p_file) override;
virtual int64_t _get_size(const String &p_file) override;
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override; virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override;
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override; virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
@ -97,8 +103,8 @@ public:
virtual void close() override; virtual void close() override;
static void deinitialize();
FileAccessEncrypted() {} FileAccessEncrypted() {}
~FileAccessEncrypted(); ~FileAccessEncrypted();
}; };
#endif // FILE_ACCESS_ENCRYPTED_H

View file

@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_MEMORY_H #pragma once
#define FILE_ACCESS_MEMORY_H
#include "core/io/file_access.h" #include "core/io/file_access.h"
class FileAccessMemory : public FileAccess { class FileAccessMemory : public FileAccess {
GDSOFTCLASS(FileAccessMemory, FileAccess);
uint8_t *data = nullptr; uint8_t *data = nullptr;
uint64_t length = 0; uint64_t length = 0;
mutable uint64_t pos = 0; mutable uint64_t pos = 0;
@ -66,6 +66,9 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint64_t _get_access_time(const String &p_file) override { return 0; }
virtual int64_t _get_size(const String &p_file) override { return -1; }
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; } virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; } virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
@ -78,5 +81,3 @@ public:
FileAccessMemory() {} FileAccessMemory() {}
}; };
#endif // FILE_ACCESS_MEMORY_H

View file

@ -264,7 +264,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
f->get_32(); // patch number, not used for validation. f->get_32(); // patch number, not used for validation.
ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, vformat("Pack version unsupported: %d.", version)); ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, vformat("Pack version unsupported: %d.", version));
ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor)); ERR_FAIL_COND_V_MSG(ver_major > GODOT_VERSION_MAJOR || (ver_major == GODOT_VERSION_MAJOR && ver_minor > GODOT_VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor));
uint32_t pack_flags = f->get_32(); uint32_t pack_flags = f->get_32();
uint64_t file_base = f->get_64(); uint64_t file_base = f->get_64();
@ -306,9 +306,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
f->get_buffer((uint8_t *)cs.ptr(), sl); f->get_buffer((uint8_t *)cs.ptr(), sl);
cs[sl] = 0; cs[sl] = 0;
String path; String path = String::utf8(cs.ptr(), sl);
path.parse_utf8(cs.ptr(), sl);
uint64_t ofs = f->get_64(); uint64_t ofs = f->get_64();
uint64_t size = f->get_64(); uint64_t size = f->get_64();
uint8_t md5[16]; uint8_t md5[16];
@ -550,7 +548,7 @@ String DirAccessPack::get_drive(int p_drive) {
} }
PackedData::PackedDir *DirAccessPack::_find_dir(const String &p_dir) { PackedData::PackedDir *DirAccessPack::_find_dir(const String &p_dir) {
String nd = p_dir.replace("\\", "/"); String nd = p_dir.replace_char('\\', '/');
// Special handling since simplify_path() will forbid it // Special handling since simplify_path() will forbid it
if (p_dir == "..") { if (p_dir == "..") {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_PACK_H #pragma once
#define FILE_ACCESS_PACK_H
#include "core/io/dir_access.h" #include "core/io/dir_access.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
@ -127,6 +126,8 @@ public:
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path); _FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
_FORCE_INLINE_ bool has_path(const String &p_path); _FORCE_INLINE_ bool has_path(const String &p_path);
_FORCE_INLINE_ int64_t get_size(const String &p_path);
_FORCE_INLINE_ Ref<DirAccess> try_open_directory(const String &p_path); _FORCE_INLINE_ Ref<DirAccess> try_open_directory(const String &p_path);
_FORCE_INLINE_ bool has_directory(const String &p_path); _FORCE_INLINE_ bool has_directory(const String &p_path);
@ -156,6 +157,7 @@ public:
}; };
class FileAccessPack : public FileAccess { class FileAccessPack : public FileAccess {
GDSOFTCLASS(FileAccessPack, FileAccess);
PackedData::PackedFile pf; PackedData::PackedFile pf;
mutable uint64_t pos; mutable uint64_t pos;
@ -165,6 +167,8 @@ class FileAccessPack : public FileAccess {
Ref<FileAccess> f; Ref<FileAccess> f;
virtual Error open_internal(const String &p_path, int p_mode_flags) override; virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint64_t _get_access_time(const String &p_file) override { return 0; }
virtual int64_t _get_size(const String &p_file) override { return -1; }
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; } virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; } virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
@ -200,6 +204,19 @@ public:
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file); FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
}; };
int64_t PackedData::get_size(const String &p_path) {
String simplified_path = p_path.simplify_path();
PathMD5 pmd5(simplified_path.md5_buffer());
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
if (!E) {
return -1; // File not found.
}
if (E->value.offset == 0) {
return -1; // File was erased.
}
return E->value.size;
}
Ref<FileAccess> PackedData::try_open_path(const String &p_path) { Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
String simplified_path = p_path.simplify_path().trim_prefix("res://"); String simplified_path = p_path.simplify_path().trim_prefix("res://");
PathMD5 pmd5(simplified_path.md5_buffer()); PathMD5 pmd5(simplified_path.md5_buffer());
@ -225,6 +242,7 @@ bool PackedData::has_directory(const String &p_path) {
} }
class DirAccessPack : public DirAccess { class DirAccessPack : public DirAccess {
GDSOFTCLASS(DirAccessPack, DirAccess);
PackedData::PackedDir *current; PackedData::PackedDir *current;
List<String> list_dirs; List<String> list_dirs;
@ -272,5 +290,3 @@ Ref<DirAccess> PackedData::try_open_directory(const String &p_path) {
} }
return da; return da;
} }
#endif // FILE_ACCESS_PACK_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef FILE_ACCESS_ZIP_H #pragma once
#define FILE_ACCESS_ZIP_H
#ifdef MINIZIP_ENABLED #ifdef MINIZIP_ENABLED
@ -74,6 +73,7 @@ public:
}; };
class FileAccessZip : public FileAccess { class FileAccessZip : public FileAccess {
GDSOFTCLASS(FileAccessZip, FileAccess);
unzFile zfile = nullptr; unzFile zfile = nullptr;
unz_file_info64 file_info; unz_file_info64 file_info;
@ -102,7 +102,9 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } // todo virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint64_t _get_access_time(const String &p_file) override { return 0; }
virtual int64_t _get_size(const String &p_file) override { return -1; }
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; } virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; } virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
@ -118,5 +120,3 @@ public:
}; };
#endif // MINIZIP_ENABLED #endif // MINIZIP_ENABLED
#endif // FILE_ACCESS_ZIP_H

View file

@ -70,10 +70,9 @@ Error HTTPClient::_request(Method p_method, const String &p_url, const Vector<St
String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
String query = ""; String query = "";
Array keys = p_dict.keys(); for (const KeyValue<Variant, Variant> &kv : p_dict) {
for (int i = 0; i < keys.size(); ++i) { String encoded_key = String(kv.key).uri_encode();
String encoded_key = String(keys[i]).uri_encode(); const Variant &value = kv.value;
const Variant &value = p_dict[keys[i]];
switch (value.get_type()) { switch (value.get_type()) {
case Variant::ARRAY: { case Variant::ARRAY: {
// Repeat the key with every values // Repeat the key with every values
@ -118,7 +117,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() {
continue; continue;
} }
String key = s.substr(0, sp).strip_edges(); String key = s.substr(0, sp).strip_edges();
String value = s.substr(sp + 1, s.length()).strip_edges(); String value = s.substr(sp + 1).strip_edges();
ret[key] = value; ret[key] = value;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef HTTP_CLIENT_H #pragma once
#define HTTP_CLIENT_H
#include "core/crypto/crypto.h" #include "core/crypto/crypto.h"
#include "core/io/ip.h" #include "core/io/ip.h"
@ -205,5 +204,3 @@ public:
VARIANT_ENUM_CAST(HTTPClient::ResponseCode) VARIANT_ENUM_CAST(HTTPClient::ResponseCode)
VARIANT_ENUM_CAST(HTTPClient::Method); VARIANT_ENUM_CAST(HTTPClient::Method);
VARIANT_ENUM_CAST(HTTPClient::Status); VARIANT_ENUM_CAST(HTTPClient::Status);
#endif // HTTP_CLIENT_H

View file

@ -50,13 +50,13 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, Ref<TLSOp
String host_lower = conn_host.to_lower(); String host_lower = conn_host.to_lower();
if (host_lower.begins_with("http://")) { if (host_lower.begins_with("http://")) {
conn_host = conn_host.substr(7, conn_host.length() - 7); conn_host = conn_host.substr(7);
tls_options.unref(); tls_options.unref();
} else if (host_lower.begins_with("https://")) { } else if (host_lower.begins_with("https://")) {
if (tls_options.is_null()) { if (tls_options.is_null()) {
tls_options = TLSOptions::client(); tls_options = TLSOptions::client();
} }
conn_host = conn_host.substr(8, conn_host.length() - 8); conn_host = conn_host.substr(8);
} }
ERR_FAIL_COND_V(tls_options.is_valid() && tls_options->is_server(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(tls_options.is_valid() && tls_options->is_server(), ERR_INVALID_PARAMETER);
@ -196,7 +196,7 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<
// Should it add utf8 encoding? // Should it add utf8 encoding?
} }
if (add_uagent) { if (add_uagent) {
request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; request += "User-Agent: GodotEngine/" + String(GODOT_VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n";
} }
if (add_accept) { if (add_accept) {
request += "Accept: */*\r\n"; request += "Accept: */*\r\n";
@ -483,8 +483,7 @@ Error HTTPClientTCP::poll() {
(rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) {
// End of response, parse. // End of response, parse.
response_str.push_back(0); response_str.push_back(0);
String response; String response = String::utf8((const char *)response_str.ptr(), response_str.size());
response.parse_utf8((const char *)response_str.ptr(), response_str.size());
Vector<String> responses = response.split("\n"); Vector<String> responses = response.split("\n");
body_size = -1; body_size = -1;
chunked = false; chunked = false;
@ -508,11 +507,11 @@ Error HTTPClientTCP::poll() {
continue; continue;
} }
if (s.begins_with("content-length:")) { if (s.begins_with("content-length:")) {
body_size = s.substr(s.find_char(':') + 1, s.length()).strip_edges().to_int(); body_size = s.substr(s.find_char(':') + 1).strip_edges().to_int();
body_left = body_size; body_left = body_size;
} else if (s.begins_with("transfer-encoding:")) { } else if (s.begins_with("transfer-encoding:")) {
String encoding = header.substr(header.find_char(':') + 1, header.length()).strip_edges(); String encoding = header.substr(header.find_char(':') + 1).strip_edges();
if (encoding == "chunked") { if (encoding == "chunked") {
chunked = true; chunked = true;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef HTTP_CLIENT_TCP_H #pragma once
#define HTTP_CLIENT_TCP_H
#include "http_client.h" #include "http_client.h"
@ -100,5 +99,3 @@ public:
void set_https_proxy(const String &p_host, int p_port) override; void set_https_proxy(const String &p_host, int p_port) override;
HTTPClientTCP(); HTTPClientTCP();
}; };
#endif // HTTP_CLIENT_TCP_H

View file

@ -31,7 +31,6 @@
#include "image.h" #include "image.h"
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/error/error_list.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/io/image_loader.h" #include "core/io/image_loader.h"
#include "core/io/resource_loader.h" #include "core/io/resource_loader.h"
@ -89,11 +88,13 @@ SavePNGFunc Image::save_png_func = nullptr;
SaveJPGFunc Image::save_jpg_func = nullptr; SaveJPGFunc Image::save_jpg_func = nullptr;
SaveEXRFunc Image::save_exr_func = nullptr; SaveEXRFunc Image::save_exr_func = nullptr;
SaveWebPFunc Image::save_webp_func = nullptr; SaveWebPFunc Image::save_webp_func = nullptr;
SaveDDSFunc Image::save_dds_func = nullptr;
SavePNGBufferFunc Image::save_png_buffer_func = nullptr; SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr; SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr; SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr; SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr;
SaveDDSBufferFunc Image::save_dds_buffer_func = nullptr;
// External loader function pointers. // External loader function pointers.
@ -105,6 +106,7 @@ ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr; ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr; ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr; ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_dds_mem_loader_func = nullptr;
// External VRAM compression function pointers. // External VRAM compression function pointers.
@ -571,7 +573,7 @@ static bool _are_formats_compatible(Image::Format p_format0, Image::Format p_for
void Image::convert(Format p_new_format) { void Image::convert(Format p_new_format) {
ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_new_format)); ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_new_format));
if (data.size() == 0 || p_new_format == format) { if (data.is_empty() || p_new_format == format) {
return; return;
} }
@ -796,7 +798,7 @@ Image::Format Image::get_format() const {
} }
static double _bicubic_interp_kernel(double x) { static double _bicubic_interp_kernel(double x) {
x = ABS(x); x = Math::abs(x);
double bc = 0; double bc = 0;
@ -1139,7 +1141,7 @@ bool Image::is_size_po2() const {
} }
void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) { void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats.");
int w = next_power_of_2(width); int w = next_power_of_2(width);
int h = next_power_of_2(height); int h = next_power_of_2(height);
@ -1158,7 +1160,7 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(data.is_empty(), "Cannot resize image before creating it, use set_data() first."); ERR_FAIL_COND_MSG(data.is_empty(), "Cannot resize image before creating it, use set_data() first.");
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */; bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
@ -1461,8 +1463,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
} }
void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot crop in compressed image formats.");
ERR_FAIL_COND_MSG(p_x < 0, "Start x position cannot be smaller than 0."); ERR_FAIL_COND_MSG(p_x < 0, "Start x position cannot be smaller than 0.");
ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0."); ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0.");
ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0."); ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0.");
@ -1515,7 +1516,7 @@ void Image::crop(int p_width, int p_height) {
} }
void Image::rotate_90(ClockDirection p_direction) { void Image::rotate_90(ClockDirection p_direction) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot rotate in compressed image formats.");
ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width));
ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height));
@ -1633,7 +1634,7 @@ void Image::rotate_90(ClockDirection p_direction) {
} }
void Image::rotate_180() { void Image::rotate_180() {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot rotate in compressed image formats.");
ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width));
ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height));
@ -1667,7 +1668,7 @@ void Image::rotate_180() {
} }
void Image::flip_y() { void Image::flip_y() {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot flip_y in compressed image formats.");
bool used_mipmaps = has_mipmaps(); bool used_mipmaps = has_mipmaps();
if (used_mipmaps) { if (used_mipmaps) {
@ -1697,7 +1698,7 @@ void Image::flip_y() {
} }
void Image::flip_x() { void Image::flip_x() {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot flip_x in compressed image formats.");
bool used_mipmaps = has_mipmaps(); bool used_mipmaps = has_mipmaps();
if (used_mipmaps) { if (used_mipmaps) {
@ -1789,10 +1790,6 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i
return size; return size;
} }
bool Image::_can_modify(Format p_format) const {
return !Image::is_format_compressed(p_format);
}
template <typename Component, int CC, bool renormalize, template <typename Component, int CC, bool renormalize,
void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &), void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
void (*renormalize_func)(Component *)> void (*renormalize_func)(Component *)>
@ -1926,7 +1923,7 @@ void Image::shrink_x2() {
memcpy(new_data.ptrw(), data.ptr() + ofs, new_size); memcpy(new_data.ptrw(), data.ptr() + ofs, new_size);
} else { } else {
// Generate a mipmap and replace the original. // Generate a mipmap and replace the original.
ERR_FAIL_COND(!_can_modify(format)); ERR_FAIL_COND(is_compressed());
new_data.resize((width / 2) * (height / 2) * get_format_pixel_size(format)); new_data.resize((width / 2) * (height / 2) * get_format_pixel_size(format));
ERR_FAIL_COND(data.is_empty() || new_data.is_empty()); ERR_FAIL_COND(data.is_empty() || new_data.is_empty());
@ -1963,7 +1960,7 @@ void Image::normalize() {
} }
Error Image::generate_mipmaps(bool p_renormalize) { Error Image::generate_mipmaps(bool p_renormalize) {
ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in compressed or custom image formats."); ERR_FAIL_COND_V_MSG(is_compressed(), ERR_UNAVAILABLE, "Cannot generate mipmaps from compressed image formats.");
ERR_FAIL_COND_V_MSG(format == FORMAT_RGBA4444, ERR_UNAVAILABLE, "Cannot generate mipmaps from RGBA4444 format."); ERR_FAIL_COND_V_MSG(format == FORMAT_RGBA4444, ERR_UNAVAILABLE, "Cannot generate mipmaps from RGBA4444 format.");
ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0."); ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0.");
@ -2180,7 +2177,7 @@ void Image::clear_mipmaps() {
} }
bool Image::is_empty() const { bool Image::is_empty() const {
return (data.size() == 0); return (data.is_empty());
} }
Vector<uint8_t> Image::get_data() const { Vector<uint8_t> Image::get_data() const {
@ -2297,7 +2294,7 @@ void Image::initialize_data(const char **p_xpm) {
switch (status) { switch (status) {
case READING_HEADER: { case READING_HEADER: {
String line_str = line_ptr; String line_str = line_ptr;
line_str.replace("\t", " "); line_str.replace_char('\t', ' ');
size_width = line_str.get_slicec(' ', 0).to_int(); size_width = line_str.get_slicec(' ', 0).to_int();
size_height = line_str.get_slicec(' ', 1).to_int(); size_height = line_str.get_slicec(' ', 1).to_int();
@ -2441,47 +2438,75 @@ void Image::initialize_data(const char **p_xpm) {
} }
bool Image::is_invisible() const { bool Image::is_invisible() const {
if (format == FORMAT_L8 || format == FORMAT_RGB8 || format == FORMAT_RG8) { int w, h;
return false; int64_t len;
} _get_mipmap_offset_and_size(1, len, w, h);
int64_t len = data.size();
if (len == 0) { if (len == 0) {
return true; return true;
} }
int w, h;
_get_mipmap_offset_and_size(1, len, w, h);
const uint8_t *r = data.ptr();
const unsigned char *data_ptr = r;
bool detected = false;
switch (format) { switch (format) {
case FORMAT_LA8: { case FORMAT_LA8: {
for (int i = 0; i < (len >> 1); i++) { const int pixel_count = len / 2;
DETECT_NON_ALPHA(data_ptr[(i << 1) + 1]); const uint16_t *pixeldata = reinterpret_cast<const uint16_t *>(data.ptr());
}
for (int i = 0; i < pixel_count; i++) {
if ((pixeldata[i] & 0xFF00) != 0) {
return false;
}
}
} break; } break;
case FORMAT_RGBA8: { case FORMAT_RGBA8: {
for (int i = 0; i < (len >> 2); i++) { const int pixel_count = len / 4;
DETECT_NON_ALPHA(data_ptr[(i << 2) + 3]) const uint32_t *pixeldata = reinterpret_cast<const uint32_t *>(data.ptr());
for (int i = 0; i < pixel_count; i++) {
if ((pixeldata[i] & 0xFF000000) != 0) {
return false;
}
} }
} break; } break;
case FORMAT_RGBA4444: {
const int pixel_count = len / 2;
const uint16_t *pixeldata = reinterpret_cast<const uint16_t *>(data.ptr());
case FORMAT_DXT3: for (int i = 0; i < pixel_count; i++) {
case FORMAT_DXT5: { if ((pixeldata[i] & 0x000F) != 0) {
detected = true; return false;
}
}
} break;
case FORMAT_RGBAH: {
// The alpha mask accounts for the sign bit.
const int pixel_count = len / 4;
const uint16_t *pixeldata = reinterpret_cast<const uint16_t *>(data.ptr());
for (int i = 0; i < pixel_count; i += 4) {
if ((pixeldata[i + 3] & 0x7FFF) != 0) {
return false;
}
}
} break;
case FORMAT_RGBAF: {
// The alpha mask accounts for the sign bit.
const int pixel_count = len / 4;
const uint32_t *pixeldata = reinterpret_cast<const uint32_t *>(data.ptr());
for (int i = 0; i < pixel_count; i += 4) {
if ((pixeldata[i + 3] & 0x7FFFFFFF) != 0) {
return false;
}
}
} break; } break;
default: { default: {
// Formats that are compressed or don't support alpha channels are presumed to be visible.
return false;
} }
} }
return !detected; // Every pixel has been checked, the image is invisible.
return true;
} }
Image::AlphaMode Image::detect_alpha() const { Image::AlphaMode Image::detect_alpha() const {
@ -2603,6 +2628,21 @@ Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const {
return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale); return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale);
} }
Error Image::save_dds(const String &p_path) const {
if (save_dds_func == nullptr) {
return ERR_UNAVAILABLE;
}
return save_dds_func(p_path, Ref<Image>((Image *)this));
}
Vector<uint8_t> Image::save_dds_to_buffer() const {
if (save_dds_buffer_func == nullptr) {
return Vector<uint8_t>();
}
return save_dds_buffer_func(Ref<Image>((Image *)this));
}
Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const { Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const {
if (save_webp_func == nullptr) { if (save_webp_func == nullptr) {
return ERR_UNAVAILABLE; return ERR_UNAVAILABLE;
@ -2682,6 +2722,19 @@ Error Image::decompress() {
return OK; return OK;
} }
bool Image::can_decompress(const String &p_format_tag) {
if (p_format_tag == "astc") {
return _image_decompress_astc != nullptr;
} else if (p_format_tag == "bptc") {
return _image_decompress_bptc != nullptr;
} else if (p_format_tag == "etc2") {
return _image_decompress_etc2 != nullptr;
} else if (p_format_tag == "s3tc") {
return _image_decompress_bc != nullptr;
}
return false;
}
Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p_astc_format) { 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_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."); ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source.");
@ -2863,7 +2916,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const P
ERR_FAIL_COND(dsize == 0); ERR_FAIL_COND(dsize == 0);
ERR_FAIL_COND(srcdsize == 0); ERR_FAIL_COND(srcdsize == 0);
ERR_FAIL_COND(format != p_src->format); ERR_FAIL_COND(format != p_src->format);
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot blit_rect in compressed image formats.");
Rect2i src_rect; Rect2i src_rect;
Rect2i dest_rect; Rect2i dest_rect;
@ -3043,10 +3096,10 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s
} }
void Image::fill(const Color &p_color) { void Image::fill(const Color &p_color) {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot fill in compressed image formats.");
uint8_t *dst_data_ptr = data.ptrw(); uint8_t *dst_data_ptr = data.ptrw();
@ -3059,10 +3112,10 @@ void Image::fill(const Color &p_color) {
} }
void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) { void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot fill rect in compressed image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs()); Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
if (!r.has_area()) { if (!r.has_area()) {
@ -3278,7 +3331,7 @@ void Image::_set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color)
uint16_t rgba = 0; uint16_t rgba = 0;
rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31)); rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31));
rgba |= uint16_t(CLAMP(p_color.g * 63.0, 0, 33)) << 5; rgba |= uint16_t(CLAMP(p_color.g * 63.0, 0, 63)) << 5;
rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 11; rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 11;
((uint16_t *)ptr)[ofs] = rgba; ((uint16_t *)ptr)[ofs] = rgba;
@ -3366,7 +3419,7 @@ int64_t Image::get_data_size() const {
} }
void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats."); ERR_FAIL_COND_MSG(is_compressed(), "Cannot adjust_bcs in compressed image formats.");
uint8_t *w = data.ptrw(); uint8_t *w = data.ptrw();
uint32_t pixel_size = get_format_pixel_size(format); uint32_t pixel_size = get_format_pixel_size(format);
@ -3524,6 +3577,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, 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"), &Image::save_exr, DEFVAL(false)); 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_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);
ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f));
ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f));
@ -3577,6 +3633,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer); ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer); ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer); ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer);
ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer);
ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
@ -3677,7 +3734,7 @@ void Image::normal_map_to_xy() {
} }
Ref<Image> Image::rgbe_to_srgb() { Ref<Image> Image::rgbe_to_srgb() {
if (data.size() == 0) { if (data.is_empty()) {
return Ref<Image>(); return Ref<Image>();
} }
@ -3724,7 +3781,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipmap) const {
} }
void Image::bump_map_to_normal_map(float bump_scale) { void Image::bump_map_to_normal_map(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format)); ERR_FAIL_COND(is_compressed());
clear_mipmaps(); clear_mipmaps();
convert(Image::FORMAT_RF); convert(Image::FORMAT_RF);
@ -3799,7 +3856,7 @@ bool Image::detect_signed(bool p_include_mips) const {
} }
void Image::srgb_to_linear() { void Image::srgb_to_linear() {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
@ -3830,7 +3887,7 @@ void Image::srgb_to_linear() {
} }
void Image::linear_to_srgb() { void Image::linear_to_srgb() {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
@ -3861,7 +3918,7 @@ void Image::linear_to_srgb() {
} }
void Image::premultiply_alpha() { void Image::premultiply_alpha() {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
@ -3883,7 +3940,7 @@ void Image::premultiply_alpha() {
} }
void Image::fix_alpha_edges() { void Image::fix_alpha_edges() {
if (data.size() == 0) { if (data.is_empty()) {
return; return;
} }
@ -4072,6 +4129,14 @@ Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _bmp_mem_loader_func); return _load_from_buffer(p_array, _bmp_mem_loader_func);
} }
Error Image::load_dds_from_buffer(const Vector<uint8_t> &p_array) {
ERR_FAIL_NULL_V_MSG(
_dds_mem_loader_func,
ERR_UNAVAILABLE,
"The DDS module isn't enabled. Recompile the Godot editor or export template binary with the `module_dds_enabled=yes` SCons option.");
return _load_from_buffer(p_array, _dds_mem_loader_func);
}
Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) { Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) {
ERR_FAIL_NULL_V_MSG( ERR_FAIL_NULL_V_MSG(
_svg_scalable_mem_loader_func, _svg_scalable_mem_loader_func,
@ -4266,10 +4331,10 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Dictionary result; Dictionary result;
result["max"] = INFINITY; result["max"] = Math::INF;
result["mean"] = INFINITY; result["mean"] = Math::INF;
result["mean_squared"] = INFINITY; result["mean_squared"] = Math::INF;
result["root_mean_squared"] = INFINITY; result["root_mean_squared"] = Math::INF;
result["peak_snr"] = 0.0f; result["peak_snr"] = 0.0f;
ERR_FAIL_COND_V(p_compared_image.is_null(), result); ERR_FAIL_COND_V(p_compared_image.is_null(), result);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef IMAGE_H #pragma once
#define IMAGE_H
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/math/color.h" #include "core/math/color.h"
@ -59,6 +58,9 @@ typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const boo
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); 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 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);
class Image : public Resource { class Image : public Resource {
GDCLASS(Image, Resource); GDCLASS(Image, Resource);
@ -186,10 +188,12 @@ public:
static SaveJPGFunc save_jpg_func; static SaveJPGFunc save_jpg_func;
static SaveEXRFunc save_exr_func; static SaveEXRFunc save_exr_func;
static SaveWebPFunc save_webp_func; static SaveWebPFunc save_webp_func;
static SaveDDSFunc save_dds_func;
static SavePNGBufferFunc save_png_buffer_func; static SavePNGBufferFunc save_png_buffer_func;
static SaveEXRBufferFunc save_exr_buffer_func; static SaveEXRBufferFunc save_exr_buffer_func;
static SaveJPGBufferFunc save_jpg_buffer_func; static SaveJPGBufferFunc save_jpg_buffer_func;
static SaveWebPBufferFunc save_webp_buffer_func; static SaveWebPBufferFunc save_webp_buffer_func;
static SaveDDSBufferFunc save_dds_buffer_func;
// External loader function pointers. // External loader function pointers.
@ -201,6 +205,7 @@ public:
static ImageMemLoadFunc _bmp_mem_loader_func; static ImageMemLoadFunc _bmp_mem_loader_func;
static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func; static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
static ImageMemLoadFunc _ktx_mem_loader_func; static ImageMemLoadFunc _ktx_mem_loader_func;
static ImageMemLoadFunc _dds_mem_loader_func;
// External VRAM compression function pointers. // External VRAM compression function pointers.
@ -251,7 +256,6 @@ private:
_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; // Get where the mipmap begins in data. _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; // Get where the mipmap begins in data.
static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr); static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
bool _can_modify(Format p_format) const;
_FORCE_INLINE_ void _get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const; _FORCE_INLINE_ void _get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const;
@ -334,9 +338,11 @@ public:
static Ref<Image> load_from_file(const String &p_path); static Ref<Image> load_from_file(const String &p_path);
Error save_png(const String &p_path) const; Error save_png(const String &p_path) const;
Error save_jpg(const String &p_path, float p_quality = 0.75) const; Error save_jpg(const String &p_path, float p_quality = 0.75) const;
Error save_dds(const String &p_path) const;
Vector<uint8_t> save_png_to_buffer() 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_jpg_to_buffer(float p_quality = 0.75) const;
Vector<uint8_t> save_exr_to_buffer(bool p_grayscale = false) 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) 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; 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; Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
@ -373,6 +379,8 @@ public:
bool is_compressed() const; bool is_compressed() const;
static bool is_format_compressed(Format p_format); static bool is_format_compressed(Format p_format);
static bool can_decompress(const String &p_format_tag);
void fix_alpha_edges(); void fix_alpha_edges();
void premultiply_alpha(); void premultiply_alpha();
void srgb_to_linear(); void srgb_to_linear();
@ -403,6 +411,7 @@ public:
Error load_tga_from_buffer(const Vector<uint8_t> &p_array); Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array); Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
Error load_ktx_from_buffer(const Vector<uint8_t> &p_array); Error load_ktx_from_buffer(const Vector<uint8_t> &p_array);
Error load_dds_from_buffer(const Vector<uint8_t> &p_array);
Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0); Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
Error load_svg_from_string(const String &p_svg_str, float scale = 1.0); Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);
@ -442,5 +451,3 @@ VARIANT_ENUM_CAST(Image::UsedChannels)
VARIANT_ENUM_CAST(Image::AlphaMode) VARIANT_ENUM_CAST(Image::AlphaMode)
VARIANT_ENUM_CAST(Image::RoughnessChannel) VARIANT_ENUM_CAST(Image::RoughnessChannel)
VARIANT_ENUM_CAST(Image::ASTCFormat) VARIANT_ENUM_CAST(Image::ASTCFormat)
#endif // IMAGE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef IMAGE_LOADER_H #pragma once
#define IMAGE_LOADER_H
#include "core/core_bind.h" #include "core/core_bind.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
@ -108,5 +107,3 @@ public:
virtual bool handles_type(const String &p_type) const override; virtual bool handles_type(const String &p_type) const override;
virtual String get_resource_type(const String &p_path) const override; virtual String get_resource_type(const String &p_path) const override;
}; };
#endif // IMAGE_LOADER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef IP_H #pragma once
#define IP_H
#include "core/io/ip_address.h" #include "core/io/ip_address.h"
#include "core/os/os.h" #include "core/os/os.h"
@ -110,5 +109,3 @@ public:
VARIANT_ENUM_CAST(IP::Type); VARIANT_ENUM_CAST(IP::Type);
VARIANT_ENUM_CAST(IP::ResolverStatus); VARIANT_ENUM_CAST(IP::ResolverStatus);
#endif // IP_H

View file

@ -148,7 +148,7 @@ void IPAddress::_parse_ipv6(const String &p_string) {
void IPAddress::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) { void IPAddress::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) {
String ip; String ip;
if (p_start != 0) { if (p_start != 0) {
ip = p_string.substr(p_start, p_string.length() - p_start); ip = p_string.substr(p_start);
} else { } else {
ip = p_string; ip = p_string;
} }

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef IP_ADDRESS_H #pragma once
#define IP_ADDRESS_H
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -96,4 +95,6 @@ public:
IPAddress() { clear(); } IPAddress() { clear(); }
}; };
#endif // IP_ADDRESS_H // Zero-constructing IPAddress initializes field, valid, and wildcard to 0 (and thus empty).
template <>
struct is_zero_constructible<IPAddress> : std::true_type {};

View file

@ -122,8 +122,7 @@ String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_
ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON."); ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON.");
p_markers.insert(d.id()); p_markers.insert(d.id());
List<Variant> keys; LocalVector<Variant> keys = d.get_key_list();
d.get_key_list(&keys);
if (p_sort_keys) { if (p_sort_keys) {
keys.sort_custom<StringLikeVariantOrder>(); keys.sort_custom<StringLikeVariantOrder>();
@ -664,201 +663,96 @@ Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_
case Variant::VECTOR2: { case Variant::VECTOR2: {
const Vector2 v = p_variant; const Vector2 v = p_variant;
Array args = { v.x, v.y };
Array args;
args.push_back(v.x);
args.push_back(v.y);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::VECTOR2I: { case Variant::VECTOR2I: {
const Vector2i v = p_variant; const Vector2i v = p_variant;
Array args = { v.x, v.y };
Array args;
args.push_back(v.x);
args.push_back(v.y);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::RECT2: { case Variant::RECT2: {
const Rect2 r = p_variant; const Rect2 r = p_variant;
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
Array args;
args.push_back(r.position.x);
args.push_back(r.position.y);
args.push_back(r.size.width);
args.push_back(r.size.height);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::RECT2I: { case Variant::RECT2I: {
const Rect2i r = p_variant; const Rect2i r = p_variant;
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
Array args;
args.push_back(r.position.x);
args.push_back(r.position.y);
args.push_back(r.size.width);
args.push_back(r.size.height);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::VECTOR3: { case Variant::VECTOR3: {
const Vector3 v = p_variant; const Vector3 v = p_variant;
Array args = { v.x, v.y, v.z };
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::VECTOR3I: { case Variant::VECTOR3I: {
const Vector3i v = p_variant; const Vector3i v = p_variant;
Array args = { v.x, v.y, v.z };
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::TRANSFORM2D: { case Variant::TRANSFORM2D: {
const Transform2D t = p_variant; const Transform2D t = p_variant;
Array args = { t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y };
Array args;
args.push_back(t[0].x);
args.push_back(t[0].y);
args.push_back(t[1].x);
args.push_back(t[1].y);
args.push_back(t[2].x);
args.push_back(t[2].y);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::VECTOR4: { case Variant::VECTOR4: {
const Vector4 v = p_variant; const Vector4 v = p_variant;
Array args = { v.x, v.y, v.z, v.w };
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
args.push_back(v.w);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::VECTOR4I: { case Variant::VECTOR4I: {
const Vector4i v = p_variant; const Vector4i v = p_variant;
Array args = { v.x, v.y, v.z, v.w };
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
args.push_back(v.w);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::PLANE: { case Variant::PLANE: {
const Plane p = p_variant; const Plane p = p_variant;
Array args = { p.normal.x, p.normal.y, p.normal.z, p.d };
Array args;
args.push_back(p.normal.x);
args.push_back(p.normal.y);
args.push_back(p.normal.z);
args.push_back(p.d);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::QUATERNION: { case Variant::QUATERNION: {
const Quaternion q = p_variant; const Quaternion q = p_variant;
Array args = { q.x, q.y, q.z, q.w };
Array args;
args.push_back(q.x);
args.push_back(q.y);
args.push_back(q.z);
args.push_back(q.w);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::AABB: { case Variant::AABB: {
const AABB aabb = p_variant; const AABB aabb = p_variant;
Array args = { aabb.position.x, aabb.position.y, aabb.position.z, aabb.size.x, aabb.size.y, aabb.size.z };
Array args;
args.push_back(aabb.position.x);
args.push_back(aabb.position.y);
args.push_back(aabb.position.z);
args.push_back(aabb.size.x);
args.push_back(aabb.size.y);
args.push_back(aabb.size.z);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::BASIS: { case Variant::BASIS: {
const Basis b = p_variant; const Basis b = p_variant;
Array args; Array args = { b.get_column(0).x, b.get_column(0).y, b.get_column(0).z,
args.push_back(b.get_column(0).x); b.get_column(1).x, b.get_column(1).y, b.get_column(1).z,
args.push_back(b.get_column(0).y); b.get_column(2).x, b.get_column(2).y, b.get_column(2).z };
args.push_back(b.get_column(0).z);
args.push_back(b.get_column(1).x);
args.push_back(b.get_column(1).y);
args.push_back(b.get_column(1).z);
args.push_back(b.get_column(2).x);
args.push_back(b.get_column(2).y);
args.push_back(b.get_column(2).z);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::TRANSFORM3D: { case Variant::TRANSFORM3D: {
const Transform3D t = p_variant; const Transform3D t = p_variant;
Array args; Array args = { t.basis.get_column(0).x, t.basis.get_column(0).y, t.basis.get_column(0).z,
args.push_back(t.basis.get_column(0).x); t.basis.get_column(1).x, t.basis.get_column(1).y, t.basis.get_column(1).z,
args.push_back(t.basis.get_column(0).y); t.basis.get_column(2).x, t.basis.get_column(2).y, t.basis.get_column(2).z,
args.push_back(t.basis.get_column(0).z); t.origin.x, t.origin.y, t.origin.z };
args.push_back(t.basis.get_column(1).x);
args.push_back(t.basis.get_column(1).y);
args.push_back(t.basis.get_column(1).z);
args.push_back(t.basis.get_column(2).x);
args.push_back(t.basis.get_column(2).y);
args.push_back(t.basis.get_column(2).z);
args.push_back(t.origin.x);
args.push_back(t.origin.y);
args.push_back(t.origin.z);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::PROJECTION: { case Variant::PROJECTION: {
const Projection p = p_variant; const Projection p = p_variant;
Array args; Array args = { p[0].x, p[0].y, p[0].z, p[0].w,
args.push_back(p[0].x); p[1].x, p[1].y, p[1].z, p[1].w,
args.push_back(p[0].y); p[2].x, p[2].y, p[2].z, p[2].w,
args.push_back(p[0].z); p[3].x, p[3].y, p[3].z, p[3].w };
args.push_back(p[0].w);
args.push_back(p[1].x);
args.push_back(p[1].y);
args.push_back(p[1].z);
args.push_back(p[1].w);
args.push_back(p[2].x);
args.push_back(p[2].y);
args.push_back(p[2].z);
args.push_back(p[2].w);
args.push_back(p[3].x);
args.push_back(p[3].y);
args.push_back(p[3].z);
args.push_back(p[3].w);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
case Variant::COLOR: { case Variant::COLOR: {
const Color c = p_variant; const Color c = p_variant;
Array args = { c.r, c.g, c.b, c.a };
Array args;
args.push_back(c.r);
args.push_back(c.g);
args.push_back(c.b);
args.push_back(c.a);
RETURN_ARGS; RETURN_ARGS;
} break; } break;
@ -922,12 +816,9 @@ Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing."); ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
List<Variant> keys; for (const KeyValue<Variant, Variant> &kv : dict) {
dict.get_key_list(&keys); args.push_back(_from_native(kv.key, p_full_objects, p_depth + 1));
args.push_back(_from_native(kv.value, p_full_objects, p_depth + 1));
for (const Variant &key : keys) {
args.push_back(_from_native(key, p_full_objects, p_depth + 1));
args.push_back(_from_native(dict[key], p_full_objects, p_depth + 1));
} }
return ret; return ret;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef JSON_H #pragma once
#define JSON_H
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/io/resource_loader.h" #include "core/io/resource_loader.h"
@ -125,5 +124,3 @@ public:
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const 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; virtual bool recognize(const Ref<Resource> &p_resource) const override;
}; };
#endif // JSON_H

View file

@ -36,10 +36,9 @@
#include "core/templates/rb_set.h" #include "core/templates/rb_set.h"
#include "modules/modules_enabled.gen.h" // For regex. #include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED #ifdef MODULE_REGEX_ENABLED
#include "modules/regex/regex.h" #include "modules/regex/regex.h"
#else
class RegEx : public RefCounted {};
#endif // MODULE_REGEX_ENABLED #endif // MODULE_REGEX_ENABLED
#if defined(MINGW_ENABLED) || defined(_MSC_VER) #if defined(MINGW_ENABLED) || defined(_MSC_VER)
@ -156,7 +155,7 @@ void RotatedFileLogger::rotate_file() {
if (FileAccess::exists(base_path)) { if (FileAccess::exists(base_path)) {
if (max_files > 1) { if (max_files > 1) {
String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace_char(':', '.');
String backup_name = base_path.get_basename() + timestamp; String backup_name = base_path.get_basename() + timestamp;
if (!base_path.get_extension().is_empty()) { if (!base_path.get_extension().is_empty()) {
backup_name += "." + base_path.get_extension(); backup_name += "." + base_path.get_extension();

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef LOGGER_H #pragma once
#define LOGGER_H
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
@ -109,5 +108,3 @@ public:
virtual ~CompositeLogger(); virtual ~CompositeLogger();
}; };
#endif // LOGGER_H

View file

@ -107,7 +107,7 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r
ERR_FAIL_COND_V(strlen < 0 || strlen + pad > len, ERR_FILE_EOF); ERR_FAIL_COND_V(strlen < 0 || strlen + pad > len, ERR_FILE_EOF);
String str; String str;
ERR_FAIL_COND_V(str.parse_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA); ERR_FAIL_COND_V(str.append_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA);
r_string = str; r_string = str;
// Add padding. // Add padding.
@ -1345,7 +1345,7 @@ static Error _encode_container_type(const ContainerType &p_type, uint8_t *&buf,
_encode_string(EncodedObjectAsID::get_class_static(), buf, r_len); _encode_string(EncodedObjectAsID::get_class_static(), buf, r_len);
} }
} else if (p_type.class_name != StringName()) { } else if (p_type.class_name != StringName()) {
_encode_string(p_full_objects ? p_type.class_name.operator String() : EncodedObjectAsID::get_class_static(), buf, r_len); _encode_string(p_full_objects ? p_type.class_name : EncodedObjectAsID::get_class_static(), buf, r_len);
} else { } else {
// No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`. // No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`.
if (buf) { if (buf) {
@ -1849,19 +1849,16 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} }
r_len += 4; r_len += 4;
List<Variant> keys; for (const KeyValue<Variant, Variant> &kv : dict) {
dict.get_key_list(&keys);
for (const Variant &key : keys) {
int len; int len;
Error err = encode_variant(key, buf, len, p_full_objects, p_depth + 1); Error err = encode_variant(kv.key, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG); ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len; r_len += len;
if (buf) { if (buf) {
buf += len; buf += len;
} }
const Variant *value = dict.getptr(key); const Variant *value = dict.getptr(kv.key);
ERR_FAIL_NULL_V(value, ERR_BUG); ERR_FAIL_NULL_V(value, ERR_BUG);
err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1); err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err, err);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/ /**************************************************************************/
#ifndef MARSHALLS_H #pragma once
#define MARSHALLS_H
#include "core/math/math_defs.h" #include "core/math/math_defs.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
@ -226,5 +225,3 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0); Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0);
Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count); Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count);
#endif // MARSHALLS_H

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