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:
Includes:
IgnoreHeader:
- core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere.
- \.compat\.inc
---
# Header-specific conditions.

View file

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

View file

@ -66,3 +66,9 @@ bb5f390fb9b466be35a5df7651323d7e66afca31
# Style: Enforce `AllowShortFunctionsOnASingleLine`
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/**/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
.vs/

View file

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

View file

@ -163,6 +163,11 @@ Comment: Temporal Anti-Aliasing resolve implementation
Copyright: 2016, Panos Karabelas
License: Expat
Files: thirdparty/accesskit/*
Comment: AccessKit
Copyright: 2023, The AccessKit Authors.
License: Expat
Files: thirdparty/amd-fsr/*
Comment: AMD FidelityFX Super Resolution
Copyright: 2021, Advanced Micro Devices, Inc.
@ -200,7 +205,7 @@ License: MPL-2.0
Files: thirdparty/clipper2/*
Comment: Clipper2
Copyright: 2010-2024, Angus Johnson
Copyright: 2010-2025, Angus Johnson
License: BSL-1.0
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 SCons import __version__ as scons_raw_version
from SCons.Builder import ListEmitter
# 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
@ -57,7 +58,7 @@ import gles3_builders
import glsl_builders
import methods
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
if ARGUMENTS.get("target", "editor") == "editor":
@ -166,7 +167,7 @@ opts.Add(
"optimize",
"Optimization level (by default inferred from 'target' and 'dev_build')",
"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))
@ -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("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("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("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(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
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(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_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(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))
@ -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("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(
BoolVariable(
"redirect_build_objects",
"Enable redirecting built objects/libraries to `bin/obj/` to declutter the repository.",
True,
)
)
# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
@ -433,10 +447,19 @@ for tool in custom_tools:
env.Tool(tool)
# add default include paths
# Add default include paths.
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
env.platform_exporters = platform_exporters
env.platform_apis = platform_apis
@ -696,83 +719,84 @@ if env["arch"] == "x86_32":
# Explicitly specify colored output.
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):
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":
env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
# Set optimize and debug_symbols flags.
# "custom" means do nothing and let users set their own optimization flags.
# Needs to happen after configure to have `env.msvc` defined.
env.AppendUnique(CCFLAGS=["$OPTIMIZELEVEL"])
if env.msvc:
if env["debug_symbols"]:
env.Append(CCFLAGS=["/Zi", "/FS"])
env.Append(LINKFLAGS=["/DEBUG:FULL"])
env.AppendUnique(CCFLAGS=["/Zi", "/FS"])
env.AppendUnique(LINKFLAGS=["/DEBUG:FULL"])
else:
env.Append(LINKFLAGS=["/DEBUG:NONE"])
env.AppendUnique(LINKFLAGS=["/DEBUG:NONE"])
if env["optimize"].startswith("speed"):
env.Append(CCFLAGS=["/O2"])
env.Append(LINKFLAGS=["/OPT:REF"])
env["OPTIMIZELEVEL"] = "/O2"
env.AppendUnique(LINKFLAGS=["/OPT:REF"])
if env["optimize"] == "speed_trace":
env.Append(LINKFLAGS=["/OPT:NOICF"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["/O1"])
env.Append(LINKFLAGS=["/OPT:REF"])
env.AppendUnique(LINKFLAGS=["/OPT:NOICF"])
elif env["optimize"].startswith("size"):
env["OPTIMIZELEVEL"] = "/O1"
env.AppendUnique(LINKFLAGS=["/OPT:REF"])
if env["optimize"] == "size_extra":
env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"])
elif env["optimize"] == "debug" or env["optimize"] == "none":
env.Append(CCFLAGS=["/Od"])
env["OPTIMIZELEVEL"] = "/Od"
else:
if env["debug_symbols"]:
if env["platform"] == "windows":
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:
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:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them
env.Append(CCFLAGS=["-gdwarf-4"])
env.AppendUnique(CCFLAGS=["-gdwarf-4"])
if methods.using_emcc(env):
# Emscripten only produces dwarf symbols when using "-g3".
env.Append(CCFLAGS=["-g3"])
env.AppendUnique(CCFLAGS=["-g3"])
# Emscripten linker needs debug symbols options too.
env.Append(LINKFLAGS=["-gdwarf-4"])
env.Append(LINKFLAGS=["-g3"])
env.AppendUnique(LINKFLAGS=["-gdwarf-4"])
env.AppendUnique(LINKFLAGS=["-g3"])
elif env.dev_build:
env.Append(CCFLAGS=["-g3"])
env.AppendUnique(CCFLAGS=["-g3"])
else:
env.Append(CCFLAGS=["-g2"])
env.AppendUnique(CCFLAGS=["-g2"])
if env["debug_paths_relative"]:
# Remap absolute paths to relative paths for debug symbols.
project_path = Dir("#").abspath
env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
env.AppendUnique(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
else:
if methods.is_apple_clang(env):
# 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:
env.Append(LINKFLAGS=["-s"])
env.AppendUnique(LINKFLAGS=["-s"])
# Linker needs optimization flags too, at least for Emscripten.
# For other toolchains, this _may_ be useful for LTO too to disambiguate.
env.AppendUnique(LINKFLAGS=["$OPTIMIZELEVEL"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["-O3"])
env.Append(LINKFLAGS=["-O3"])
env["OPTIMIZELEVEL"] = "-O3"
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["-O2"])
env.Append(LINKFLAGS=["-O2"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
env["OPTIMIZELEVEL"] = "-O2"
elif env["optimize"].startswith("size"):
env["OPTIMIZELEVEL"] = "-Os"
if env["optimize"] == "size_extra":
env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"])
elif env["optimize"] == "debug":
env.Append(CCFLAGS=["-Og"])
env.Append(LINKFLAGS=["-Og"])
env["OPTIMIZELEVEL"] = "-Og"
elif env["optimize"] == "none":
env.Append(CCFLAGS=["-O0"])
env.Append(LINKFLAGS=["-O0"])
env["OPTIMIZELEVEL"] = "-O0"
# Needs to happen after configure to handle "auto".
if env["lto"] != "none":
@ -813,6 +837,7 @@ elif env.msvc:
env.Append(CXXFLAGS=["/EHsc"])
# Configure compiler warnings
env.AppendUnique(CCFLAGS=["$WARNLEVEL"])
if env.msvc and not methods.using_clang(env): # MSVC
# Disable warnings which we don't plan to fix.
disabled_warnings = [
@ -830,19 +855,23 @@ if env.msvc and not methods.using_clang(env): # MSVC
]
if env["warnings"] == "extra":
env.Append(CCFLAGS=["/W4"] + disabled_warnings)
env["WARNLEVEL"] = "/W4"
env.AppendUnique(CCFLAGS=disabled_warnings)
elif env["warnings"] == "all":
env["WARNLEVEL"] = "/W3"
# 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":
env.Append(CCFLAGS=["/W2"] + disabled_warnings)
env["WARNLEVEL"] = "/W2"
env.AppendUnique(CCFLAGS=disabled_warnings)
else: # 'no'
env["WARNLEVEL"] = "/w"
# C4267 is particularly finicky & needs to be explicitly disabled.
env.Append(CCFLAGS=["/w", "/wd4267"])
env.AppendUnique(CCFLAGS=["/wd4267"])
if env["werror"]:
env.Append(CCFLAGS=["/WX"])
env.Append(LINKFLAGS=["/WX"])
env.AppendUnique(CCFLAGS=["/WX"])
env.AppendUnique(LINKFLAGS=["/WX"])
else: # GCC, Clang
common_warnings = []
@ -861,14 +890,14 @@ else: # GCC, Clang
# for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
common_warnings += ["-Wno-ordered-compare-function-pointers"]
# clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast
W_ALL = "-Wall" if not env.msvc else "-W3"
# clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast.
env["WARNLEVEL"] = "-Wall" if not env.msvc else "-W3"
if env["warnings"] == "extra":
env.Append(CCFLAGS=[W_ALL, "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
env.AppendUnique(CCFLAGS=["-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
env.AppendUnique(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
if methods.using_gcc(env):
env.Append(
env.AppendUnique(
CCFLAGS=[
"-Walloc-zero",
"-Wduplicated-branches",
@ -876,25 +905,38 @@ else: # GCC, Clang
"-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.
# if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
# env.Append(CXXFLAGS=["-Wnoexcept"])
if cc_version_major >= 9:
env.Append(CCFLAGS=["-Wattribute-alias=2"])
env.AppendUnique(CCFLAGS=["-Wattribute-alias=2"])
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):
env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
env.AppendUnique(CCFLAGS=["-Wimplicit-fallthrough"])
elif env["warnings"] == "all":
env.Append(CCFLAGS=[W_ALL] + common_warnings)
env.AppendUnique(CCFLAGS=common_warnings)
elif env["warnings"] == "moderate":
env.Append(CCFLAGS=[W_ALL, "-Wno-unused"] + common_warnings)
env.AppendUnique(CCFLAGS=["-Wno-unused"] + common_warnings)
else: # 'no'
env.Append(CCFLAGS=["-w"])
env["WARNLEVEL"] = "-w"
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"):
suffix = "." + detect.get_program_suffix()
@ -918,6 +960,51 @@ suffix += env.extra_suffix
sys.path.remove(tmppath)
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()
env.module_dependencies = {}
env.module_icons_paths = []
@ -968,8 +1055,6 @@ if env.editor_build:
print_error("Not all modules required by editor builds are enabled.")
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"] = suffix + env.module_version_string + env["PROGSUFFIX"]
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
@ -989,28 +1074,6 @@ env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
env["OBJPREFIX"] = 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 = {
"RD_GLSL": env.Builder(
action=env.Run(glsl_builders.build_rd_headers),
@ -1051,6 +1114,14 @@ if env["ninja"]:
if env["threads"]:
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.
Export("env")
@ -1082,11 +1153,11 @@ if "check_c_headers" in env:
for header in headers:
if conf.CheckCHeader(header):
env.AppendUnique(CPPDEFINES=[headers[header]])
conf.Finish()
methods.show_progress(env)
# TODO: replace this with `env.Dump(format="json")`
# once we start requiring SCons 4.0 as min version.
methods.dump(env)
methods.prepare_purge(env)
methods.prepare_timer()
# Miscellaneous & post-build methods.
if not env.GetOption("clean") and not env.GetOption("help"):
methods.dump(env)
methods.show_progress(env)
methods.prepare_purge(env)
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]
env_thirdparty.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
env.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
env_thirdparty.Prepend(CPPEXTPATH=[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"):
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]
env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"])
env.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"])
env_thirdparty.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]
env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too
env.Prepend(CPPPATH=[thirdparty_zlib_dir])
env.Prepend(CPPEXTPATH=[thirdparty_zlib_dir])
if env.dev_build:
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
# 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 = [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.Prepend(CPPPATH=thirdparty_zstd_dir)
env.Prepend(CPPEXTPATH=thirdparty_zstd_dir)
# Also needed in main env includes will trigger warnings
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
@ -167,10 +167,9 @@ env.add_source_files(env.core_sources, "*.cpp")
# Generate disabled classes
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():
cs = c.strip()
if cs != "":
if cs := c.strip():
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
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(
"""\
#define VERSION_SHORT_NAME "{short_name}"
#define VERSION_NAME "{name}"
#define VERSION_MAJOR {major}
#define VERSION_MINOR {minor}
#define VERSION_PATCH {patch}
#define VERSION_STATUS "{status}"
#define VERSION_BUILD "{build}"
#define VERSION_MODULE_CONFIG "{module_config}"
#define VERSION_WEBSITE "{website}"
#define VERSION_DOCS_BRANCH "{docs_branch}"
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
""".format(**env.version_info)
#define GODOT_VERSION_SHORT_NAME "{short_name}"
#define GODOT_VERSION_NAME "{name}"
#define GODOT_VERSION_MAJOR {major}
#define GODOT_VERSION_MINOR {minor}
#define GODOT_VERSION_PATCH {patch}
#define GODOT_VERSION_STATUS "{status}"
#define GODOT_VERSION_BUILD "{build}"
#define GODOT_VERSION_MODULE_CONFIG "{module_config}"
#define GODOT_VERSION_WEBSITE "{website}"
#define GODOT_VERSION_DOCS_BRANCH "{docs_branch}"
#define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH
""".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
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(
"""\
#include "core/version.h"
const char *const VERSION_HASH = "{git_hash}";
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
""".format(**env.version_info)
const char *const GODOT_VERSION_HASH = "{git_hash}";
const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
""".format(**source[0].read())
)
gen_hash = env.CommandNoCache(
"version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
)
gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder))
env.add_source_files(env.core_sources, gen_hash)
# Generate AES256 script encryption key
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(
f"""\
#include "core/config/project_settings.h"
@ -251,30 +252,21 @@ env.add_source_files(env.core_sources, gen_encrypt)
# 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(
"#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),
)
# 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
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
env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
env.CommandNoCache(
"#core/license.gen.h",
["../COPYRIGHT.txt", "../LICENSE.txt"],
env.Run(core_builders.make_license_header),
"#core/license.gen.h", ["#COPYRIGHT.txt", "#LICENSE.txt"], env.Run(core_builders.make_license_header)
)
# Chain load SCsubs

View file

@ -125,17 +125,17 @@ double Engine::get_unfrozen_time_scale() const {
Dictionary Engine::get_version_info() const {
Dictionary dict;
dict["major"] = VERSION_MAJOR;
dict["minor"] = VERSION_MINOR;
dict["patch"] = VERSION_PATCH;
dict["hex"] = VERSION_HEX;
dict["status"] = VERSION_STATUS;
dict["build"] = VERSION_BUILD;
dict["major"] = GODOT_VERSION_MAJOR;
dict["minor"] = GODOT_VERSION_MINOR;
dict["patch"] = GODOT_VERSION_PATCH;
dict["hex"] = GODOT_VERSION_HEX;
dict["status"] = GODOT_VERSION_STATUS;
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["timestamp"] = VERSION_TIMESTAMP;
dict["timestamp"] = GODOT_VERSION_TIMESTAMP;
String stringver = String(dict["major"]) + "." + String(dict["minor"]);
if ((int)dict["patch"] != 0) {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_H
#define ENGINE_H
#pragma once
#include "core/os/main_loop.h"
#include "core/string/ustring.h"
@ -214,5 +213,3 @@ public:
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.
const PackedStringArray ProjectSettings::get_required_features() {
PackedStringArray features;
features.append(VERSION_BRANCH);
features.append(GODOT_VERSION_BRANCH);
#ifdef REAL_T_IS_DOUBLE
features.append("Double Precision");
#endif
@ -92,9 +92,9 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
#endif
// 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.
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);
features.append(GODOT_VERSION_BRANCH "." _MKSTR(GODOT_VERSION_PATCH));
features.append(GODOT_VERSION_FULL_CONFIG);
features.append(GODOT_VERSION_FULL_BUILD);
#ifdef RD_ENABLED
features.append("Forward Plus");
@ -173,7 +173,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
if (dir->change_dir(path) == OK) {
String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/");
cwd = cwd.replace_char('\\', '/');
// Ensure that we end with a '/'.
// 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] == '/') {
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);
}
} 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)) {
remove_global_group(group_name);
}
@ -340,7 +340,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
}
add_autoload(autoload);
} 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);
}
}
@ -359,14 +359,14 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
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_
StringName name = p_name;
if (feature_overrides.has(name)) {
const LocalVector<Pair<StringName, StringName>> &overrides = feature_overrides[name];
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)) {
name = overrides[i].second;
break;
@ -376,12 +376,39 @@ Variant ProjectSettings::get_setting_with_override(const StringName &p_name) con
}
if (!props.has(name)) {
WARN_PRINT(vformat("Property not found: '%s'.", String(name)));
WARN_PRINT("Property not found: " + String(name));
return 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 {
String name;
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()) {
// 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.
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] == '/') {
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) {
// Set the resource path early so things can be resolved when loading.
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"));
if (err == OK && !p_ignore_override) {
// 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[slen] = 0;
f->get_buffer((uint8_t *)cs.ptr(), slen);
String key;
key.parse_utf8(cs.ptr(), slen);
String key = String::utf8(cs.ptr(), slen);
uint32_t vlen = f->get_32();
Vector<uint8_t> d;
@ -1129,7 +1155,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
category = "";
} else {
category = category.substr(0, div);
name = name.substr(div + 1, name.size());
name = name.substr(div + 1);
}
save_props[category].push_back(name);
}
@ -1141,7 +1167,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
save_features += ",";
}
String f = p_custom_features[i].strip_edges().replace("\"", "");
String f = p_custom_features[i].strip_edges().remove_char('\"');
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_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_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("get_order", "name"), &ProjectSettings::get_order);
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;
// Convert list of input events into array
for (List<Ref<InputEvent>>::Element *I = E.value.front(); I; I = I->next()) {
events.push_back(I->get());
for (const Ref<InputEvent> &event : E.value) {
events.push_back(event);
}
Dictionary action;
@ -1488,6 +1515,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/auto_accept_quit", 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:
// - Have a 16:9 aspect ratio,
// - 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);
// Keep the enum values in sync with the `DisplayServer::SCREEN_` 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);
// 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: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());
// 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("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/no_focus", 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_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
@ -1543,8 +1576,13 @@ ProjectSettings::ProjectSettings() {
#else
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate");
#endif
#ifndef PHYSICS_2D_DISABLED
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);
#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/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_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("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().
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/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/");
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PROJECT_SETTINGS_H
#define PROJECT_SETTINGS_H
#pragma once
#include "core/object/class_db.h"
@ -194,6 +193,7 @@ public:
List<String> get_input_presets() const { return input_presets; }
Variant get_setting_with_override(const StringName &p_name) const;
Variant get_setting_with_override_and_custom_features(const StringName &p_name, const Vector<String> &p_features) const;
bool is_using_datapack() 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_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
namespace core_bind {
namespace CoreBind {
// Semaphore
@ -53,10 +53,12 @@ Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const
}
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("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
}
} // namespace core_bind
} // namespace CoreBind
#endif // DISABLE_DEPRECATED

View file

@ -42,7 +42,7 @@
#include "core/os/thread_safe.h"
#include "core/variant/typed_array.h"
namespace core_bind {
namespace CoreBind {
////// ResourceLoader //////
@ -466,8 +466,8 @@ bool OS::is_restart_on_exit_set() const {
Vector<String> OS::get_restart_on_exit_arguments() const {
List<String> args = ::OS::get_singleton()->get_restart_on_exit_arguments();
Vector<String> args_vector;
for (List<String>::Element *E = args.front(); E; E = E->next()) {
args_vector.push_back(E->get());
for (const String &arg : args) {
args_vector.push_back(arg);
}
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_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_buffer_from_stdin", "buffer_size"), &OS::read_buffer_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, DEFVAL(1024));
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_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 s[2] = { p_a, p_b };
return ::Geometry2D::get_closest_point_to_segment(p_point, s);
return ::Geometry2D::get_closest_point_to_segment(p_point, p_a, 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, s);
return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
}
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 s[2] = { p_a, p_b };
return ::Geometry3D::get_closest_point_to_segment(p_point, s);
return ::Geometry3D::get_closest_point_to_segment(p_point, p_a, 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, s);
return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
}
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) {
if (p_str.is_empty()) {
return String();
}
CharString cstr = p_str.utf8();
String ret = CryptoCore::b64_encode_str((unsigned char *)cstr.get_data(), cstr.length());
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.
ObjectID th_instance_id = t->get_instance_id();
Callable target_callable = t->target_callable;
String id = t->get_id();
t = Ref<Thread>();
Callable::CallError ce;
@ -1347,7 +1347,7 @@ void Thread::_start_func(void *ud) {
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
// (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()) {
t->ret = ret;
t->running.clear();
@ -1357,7 +1357,7 @@ void Thread::_start_func(void *ud) {
}
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);
}
namespace special {
namespace Special {
////// ClassDB //////
@ -1438,8 +1438,8 @@ PackedStringArray ClassDB::get_class_list() const {
}
PackedStringArray ClassDB::get_inheriters_from_class(const StringName &p_class) const {
List<StringName> classes;
::ClassDB::get_inheriters_from_class(p_class, &classes);
LocalVector<StringName> classes;
::ClassDB::get_inheriters_from_class(p_class, classes);
PackedStringArray ret;
ret.resize(classes.size());
@ -1746,7 +1746,7 @@ void ClassDB::_bind_methods() {
BIND_ENUM_CONSTANT(API_NONE);
}
} // namespace special
} // namespace Special
////// Engine //////
@ -1876,8 +1876,8 @@ Vector<String> Engine::get_singleton_list() const {
List<::Engine::Singleton> singletons;
::Engine::get_singleton()->get_singletons(&singletons);
Vector<String> ret;
for (List<::Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
ret.push_back(E->get().name);
for (const ::Engine::Singleton &E : singletons) {
ret.push_back(E.name);
}
return ret;
}
@ -2190,4 +2190,4 @@ void EngineDebugger::_bind_methods() {
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. */
/**************************************************************************/
#ifndef CORE_BIND_H
#define CORE_BIND_H
#pragma once
#include "core/debugger/engine_profiler.h"
#include "core/io/resource_loader.h"
@ -42,7 +41,7 @@ class MainLoop;
template <typename T>
class TypedArray;
namespace core_bind {
namespace CoreBind {
class ResourceLoader : public Object {
GDCLASS(ResourceLoader, Object);
@ -458,7 +457,7 @@ public:
static void set_thread_safety_checks_enabled(bool p_enabled);
};
namespace special {
namespace Special {
class ClassDB : public Object {
GDCLASS(ClassDB, Object);
@ -524,7 +523,7 @@ public:
~ClassDB() {}
};
} // namespace special
} // namespace Special
class Engine : public Object {
GDCLASS(Engine, Object);
@ -652,23 +651,21 @@ public:
~EngineDebugger();
};
} // namespace core_bind
} // namespace CoreBind
VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus);
VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
VARIANT_ENUM_CAST(CoreBind::ResourceLoader::ThreadLoadStatus);
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(core_bind::OS::SystemDir);
VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);
VARIANT_ENUM_CAST(CoreBind::OS::RenderingDriver);
VARIANT_ENUM_CAST(CoreBind::OS::SystemDir);
VARIANT_ENUM_CAST(CoreBind::OS::StdHandleType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyJoinType);
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);
#endif // CORE_BIND_H
VARIANT_ENUM_CAST(CoreBind::Special::ClassDB::APIType);

View file

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

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_CONSTANTS_H
#define CORE_CONSTANTS_H
#pragma once
#include "core/string/string_name.h"
#include "core/templates/hash_map.h"
@ -47,5 +46,3 @@ public:
static bool is_global_enum(const StringName &p_enum);
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. */
/**************************************************************************/
#ifndef CORE_GLOBALS_H
#define CORE_GLOBALS_H
#pragma once
// Home for state needed from global functions
// 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_error_enabled;
};
#endif // CORE_GLOBALS_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_STRING_NAMES_H
#define CORE_STRING_NAMES_H
#pragma once
#include "core/string/string_name.h"
@ -87,5 +86,3 @@ public:
};
#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.
# We decided not to depend on system mbedtls just for these few files that can
# be easily extracted.
env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
env_crypto.Prepend(CPPEXTPATH=["#thirdparty/mbedtls/include"])
# MbedTLS core functions (for CryptoCore).
# If the mbedtls module is compiled we don't need to add the .c files with our

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef AES_CONTEXT_H
#define AES_CONTEXT_H
#pragma once
#include "core/crypto/crypto_core.h"
#include "core/object/ref_counted.h"
@ -64,5 +63,3 @@ public:
};
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. */
/**************************************************************************/
#ifndef CRYPTO_H
#define CRYPTO_H
#pragma once
#include "core/crypto/hashing_context.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 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
String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
int b64len = p_src_len / 3 * 4 + 4 + 1;
String CryptoCore::b64_encode_str(const uint8_t *p_src, size_t p_src_len) {
size_t b64len = p_src_len / 3 * 4 + 4 + 1;
Vector<uint8_t> b64buff;
b64buff.resize(b64len);
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];
}
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);
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);
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);
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);
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);
return ret ? FAILED : OK;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CRYPTO_CORE_H
#define CRYPTO_CORE_H
#pragma once
#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);
};
static String b64_encode_str(const uint8_t *p_src, int 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_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, 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, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
static Error b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
static Error md5(const uint8_t *p_src, int 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 sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]);
static Error md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]);
static Error sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]);
static Error sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]);
};
#endif // CRYPTO_CORE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef HASHING_CONTEXT_H
#define HASHING_CONTEXT_H
#pragma once
#include "core/object/ref_counted.h"
@ -62,5 +61,3 @@ public:
};
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()))
Array DebuggerMarshalls::ScriptStackDump::serialize() {
Array arr;
arr.push_back(frames.size() * 3);
Array arr = { frames.size() * 3 };
for (const ScriptLanguage::StackInfo &frame : frames) {
arr.push_back(frame.file);
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 arr;
arr.push_back(name);
arr.push_back(type);
arr.push_back(value.get_type());
Array arr = { name, type, value.get_type() };
Variant var = value;
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 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();
Array arr = {
hr,
min,
sec, msec,
source_file,
source_func,
source_line,
error,
error_descr,
warning,
size * 3
};
const ScriptLanguage::StackInfo *r = callstack.ptr();
arr.push_back(size * 3);
for (int i = 0; i < callstack.size(); i++) {
arr.push_back(r[i].file);
arr.push_back(r[i].func);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DEBUGGER_MARSHALLS_H
#define DEBUGGER_MARSHALLS_H
#pragma once
#include "core/input/shortcut.h"
#include "core/object/script_language.h"
@ -73,5 +72,3 @@ struct DebuggerMarshalls {
static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut);
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);
}
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.
if (p_uri.is_empty()) {
return;
@ -149,8 +149,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
script_debugger = memnew(ScriptDebugger);
// Notify editor of our pid (to allow focus stealing).
Array msg;
msg.push_back(OS::get_singleton()->get_process_id());
Array msg = { OS::get_singleton()->get_process_id() };
singleton->send_message("set_pid", msg);
}
if (!singleton) {
@ -160,13 +159,14 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
// There is a debugger, parse breakpoints.
ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger();
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++) {
const String &bp = p_breakpoints[i];
int sp = bp.rfind_char(':');
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;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_DEBUGGER_H
#define ENGINE_DEBUGGER_H
#pragma once
#include "core/string/string_name.h"
#include "core/string/ustring.h"
@ -107,7 +106,7 @@ public:
_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 register_profiler(const StringName &p_name, const Profiler &p_profiler);
static void unregister_profiler(const StringName &p_name);
@ -140,5 +139,3 @@ public:
virtual ~EngineDebugger();
};
#endif // ENGINE_DEBUGGER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_PROFILER_H
#define ENGINE_PROFILER_H
#pragma once
#include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h"
@ -59,5 +58,3 @@ public:
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")) {
if (line.get_slice_count(" ") <= 1) {
const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
if (breakpoints.size() == 0) {
if (breakpoints.is_empty()) {
print_line("No Breakpoints.");
continue;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef LOCAL_DEBUGGER_H
#define LOCAL_DEBUGGER_H
#pragma once
#include "core/debugger/engine_debugger.h"
#include "core/object/script_language.h"
@ -55,5 +54,3 @@ public:
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) {
Array msg;
msg.push_back(p_message);
msg.push_back(Thread::get_caller_id());
msg.push_back(p_data);
Array msg = { p_message, Thread::get_caller_id(), p_data };
Error err = peer->put_message(msg);
if (err != OK) {
n_messages_dropped++;
@ -235,9 +232,7 @@ void RemoteDebugger::flush_output() {
types.push_back(MESSAGE_TYPE_LOG);
}
Array arr;
arr.push_back(strings);
arr.push_back(types);
Array arr = { strings, types };
_put_msg("output", arr);
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();
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);
msg.push_back(script_lang->debug_get_stack_level_count() > 0);
msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id()));
if (allow_focus_steal_fn) {
allow_focus_steal_fn();
const bool can_break = !(p_is_error_breakpoint && script_debugger->is_ignoring_error_breaks());
const String error_str = script_lang ? script_lang->debug_get_error() : "";
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;
@ -507,8 +510,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
script_lang->debug_get_globals(&globals, &globals_vals);
ERR_FAIL_COND(globals.size() != globals_vals.size());
Array var_size;
var_size.push_back(local_vals.size() + member_vals.size() + globals_vals.size());
Array var_size = { local_vals.size() + member_vals.size() + globals_vals.size() };
send_message("stack_frame_vars", var_size);
_send_stack_vars(locals, local_vals, 0);
_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") {
ERR_FAIL_COND(data.is_empty());
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") {
String expression_str = data[0];
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") {
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
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") {
script_debugger->debug(script_debugger->get_break_language());
} else {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef REMOTE_DEBUGGER_H
#define REMOTE_DEBUGGER_H
#pragma once
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
@ -122,5 +121,3 @@ public:
explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
~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) {
uint8_t *buf = out_buf.ptrw();
if (out_left <= 0) {
if (out_queue.size() == 0) {
if (out_queue.is_empty()) {
break; // Nothing left to send
}
mutex.lock();

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef REMOTE_DEBUGGER_PEER_H
#define REMOTE_DEBUGGER_PEER_H
#pragma once
#include "core/io/stream_peer_tcp.h"
#include "core/object/ref_counted.h"
@ -92,5 +91,3 @@ public:
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
~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);
if (breakpoints[p_line].size() == 0) {
if (breakpoints[p_line].is_empty()) {
breakpoints.erase(p_line);
}
}
@ -79,6 +79,14 @@ bool ScriptDebugger::is_skipping_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) {
ScriptLanguage *prev = break_lang;
break_lang = p_lang;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCRIPT_DEBUGGER_H
#define SCRIPT_DEBUGGER_H
#pragma once
#include "core/object/script_language.h"
#include "core/string/string_name.h"
@ -40,6 +39,7 @@ class ScriptDebugger {
typedef ScriptLanguage::StackInfo StackInfo;
bool skip_breakpoints = false;
bool ignore_error_breaks = false;
HashMap<int, HashSet<StringName>> breakpoints;
@ -64,6 +64,8 @@ public:
ScriptLanguage *get_break_language() { return break_lang; }
void set_skip_breakpoints(bool p_skip_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 remove_breakpoint(int p_line, const StringName &p_source);
_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;
ScriptDebugger() {}
};
#endif // SCRIPT_DEBUGGER_H

View file

@ -32,11 +32,11 @@
String DocData::get_default_value_string(const Variant &p_value) {
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) {
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 {
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)) {
p_method.return_enum = p_retinfo.class_name;
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_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)) {
p_argument.enumeration = p_arginfo.class_name;
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.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);
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = p_methodinfo.arguments.begin(); itr != p_methodinfo.arguments.end(); ++itr, ++i) {
for (int64_t i = 0; i < p_methodinfo.arguments.size(); ++i) {
DocData::ArgumentDoc argument;
argument_doc_from_arginfo(argument, *itr);
int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
argument_doc_from_arginfo(argument, p_methodinfo.arguments[i]);
int64_t default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
if (default_arg_index >= 0) {
Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
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. */
/**************************************************************************/
#ifndef DOC_DATA_H
#define DOC_DATA_H
#pragma once
#include "core/io/xml_parser.h"
#include "core/variant/variant.h"
@ -115,7 +114,7 @@ public:
// Must be an operator or a constructor since there is no other overloading
if (name.left(8) == "operator") {
if (arguments.size() == p_method.arguments.size()) {
if (arguments.size() == 0) {
if (arguments.is_empty()) {
return false;
}
return arguments[0].type < p_method.arguments[0].type;
@ -127,7 +126,7 @@ public:
// - 1. Default constructor: Foo()
// - 2. Copy constructor: Foo(Foo)
// - 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();
}
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")) {
enums = p_dict["enums"];
}
for (int i = 0; i < enums.size(); i++) {
doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i));
for (const KeyValue<Variant, Variant> &kv : enums) {
doc.enums[kv.key] = EnumDoc::from_dict(kv.value);
}
Array properties;
@ -980,5 +979,3 @@ public:
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);
};
#endif // DOC_DATA_H

View file

@ -30,6 +30,8 @@
#include "error_list.h"
#include <iterator>
const char *error_names[] = {
"OK", // OK
"Failed", // FAILED
@ -82,4 +84,4 @@ const char *error_names[] = {
"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. */
/**************************************************************************/
#ifndef ERROR_LIST_H
#define ERROR_LIST_H
#pragma once
/** Error List. Please never compare an error against FAILED
* Either do result != OK , or !result. This way, Error fail
@ -98,5 +97,3 @@ enum Error {
};
extern const char *error_names[];
#endif // ERROR_LIST_H

View file

@ -31,6 +31,7 @@
#include "error_macros.h"
#include "core/io/logger.h"
#include "core/object/object_id.h"
#include "core/os/os.h"
#include "core/string/ustring.h"
@ -187,7 +188,7 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
} else {
String node_name;
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()) {
node_name = "\"" + String(node->get_path()) + "\"";
} else {

View file

@ -28,15 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ERROR_MACROS_H
#define ERROR_MACROS_H
#pragma once
#include "core/object/object_id.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 ObjectID;
enum ErrorHandlerType {
ERR_HANDLER_ERROR,
@ -62,16 +61,16 @@ void add_error_handler(ErrorHandlerList *p_handler);
void remove_error_handler(const ErrorHandlerList *p_handler);
// 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);
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);
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);
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 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 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 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 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 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 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_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);
void _err_flush_stdout();
_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);
_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);
_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);
@ -845,5 +844,3 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file,
#define PHYSICS_INTERPOLATION_WARNING(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.
return p_bbcode.dedent()
.replace("\t", "")
.replace("\r", "")
.remove_chars("\t\r")
.strip_edges();
}
@ -107,16 +106,22 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
{
//header
Dictionary header;
header["version_major"] = VERSION_MAJOR;
header["version_minor"] = VERSION_MINOR;
#if VERSION_PATCH
header["version_patch"] = VERSION_PATCH;
header["version_major"] = GODOT_VERSION_MAJOR;
header["version_minor"] = GODOT_VERSION_MINOR;
#if GODOT_VERSION_PATCH
header["version_patch"] = GODOT_VERSION_PATCH;
#else
header["version_patch"] = 0;
#endif
header["version_status"] = VERSION_STATUS;
header["version_build"] = VERSION_BUILD;
header["version_full_name"] = VERSION_FULL_NAME;
header["version_status"] = GODOT_VERSION_STATUS;
header["version_build"] = GODOT_VERSION_BUILD;
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;
}
@ -278,43 +283,43 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
#define REAL_MEMBER_OFFSET(type, member) \
{ \
type, \
member, \
"float", \
sizeof(float), \
"float", \
sizeof(float), \
"double", \
sizeof(double), \
"double", \
sizeof(double), \
member, \
"float", \
sizeof(float), \
"float", \
sizeof(float), \
"double", \
sizeof(double), \
"double", \
sizeof(double), \
}
#define INT32_MEMBER_OFFSET(type, member) \
{ \
type, \
member, \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
member, \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
"int32", \
sizeof(int32_t), \
}
#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
{ \
type, \
member, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
member_type, \
sizeof(int32_t) * member_elems, \
}
#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
@ -970,14 +975,14 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
Array values;
List<StringName> enum_constant_list;
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;
d3["name"] = String(G->get());
d3["value"] = ClassDB::get_integer_constant(class_name, G->get());
d3["name"] = String(enum_constant);
d3["value"] = ClassDB::get_integer_constant(class_name, enum_constant);
if (p_include_docs) {
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);
break;
}
@ -1048,9 +1053,8 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
}
Array arguments;
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++i) {
const PropertyInfo &pinfo = *itr;
for (int64_t i = 0; i < mi.arguments.size(); ++i) {
const PropertyInfo &pinfo = mi.arguments[i];
Dictionary d3;
d3["name"] = pinfo.name;
@ -1175,11 +1179,10 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
Array arguments;
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = F.arguments.begin(); itr != F.arguments.end(); ++itr, ++i) {
for (int64_t i = 0; i < F.arguments.size(); ++i) {
Dictionary d3;
d3["name"] = itr->name;
d3["type"] = get_property_info_type_name(*itr);
d3["name"] = F.arguments[i].name;
d3["type"] = get_property_info_type_name(F.arguments[i]);
if (F.get_argument_meta(i) > 0) {
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) {
Dictionary old_dict = p_old_value;
Dictionary new_dict = p_new_value;
for (const Variant &key : old_dict.keys()) {
if (!new_dict.has(key)) {
for (const KeyValue<Variant, Variant> &kv : old_dict) {
if (!new_dict.has(kv.key)) {
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;
}
if (p_allow_name_change && key == "name") {
if (p_allow_name_change && kv.key == "name") {
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;
}
}
@ -1420,25 +1423,25 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
bool optional = field.begins_with("*");
if (optional) {
// 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("+");
if (added) {
// 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("$");
if (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("@");
if (allow_name_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;
@ -1598,8 +1601,8 @@ Error GDExtensionAPIDump::validate_extension_json_file(const String &p_path) {
int major = header["version_major"];
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(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(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 > 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;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef EXTENSION_API_DUMP_H
#define EXTENSION_API_DUMP_H
#pragma once
#include "core/extension/gdextension.h"
@ -42,5 +41,3 @@ public:
static Error validate_extension_json_file(const String &p_path);
};
#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));
}
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;
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_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
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() {
@ -1034,6 +1042,14 @@ void GDExtension::_untrack_instance(void *p_user_data, void *p_instance) {
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;
GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_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. */
/**************************************************************************/
#ifndef GDEXTENSION_H
#define GDEXTENSION_H
#pragma once
#include "core/extension/gdextension_interface.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 _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
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;
int32_t level_initialized = -1;
@ -102,6 +102,7 @@ class GDExtension : public Resource {
bool is_reloading = false;
Vector<GDExtensionMethodBind *> invalid_methods;
Vector<ObjectID> instance_bindings;
GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr;
static void _track_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 untrack_instance_binding(Object *p_object);
PackedStringArray get_classes_used() const;
#endif
InitializationLevel get_minimum_library_initialization_level() const;
@ -226,5 +229,3 @@ public:
};
#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);
}
#ifndef DISABLE_DEPRECATED
static void gdextension_get_godot_version(GDExtensionGodotVersion *r_godot_version) {
r_godot_version->major = VERSION_MAJOR;
r_godot_version->minor = VERSION_MINOR;
r_godot_version->patch = VERSION_PATCH;
r_godot_version->string = VERSION_FULL_NAME;
r_godot_version->major = GODOT_VERSION_MAJOR;
r_godot_version->minor = GODOT_VERSION_MINOR;
r_godot_version->patch = GODOT_VERSION_PATCH;
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
@ -858,84 +872,82 @@ static GDExtensionPtrUtilityFunction gdextension_variant_get_ptr_utility_functio
//string helpers
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) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf8(p_contents);
String *dest = memnew_placement(r_dest, String);
dest->append_utf8(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 = reinterpret_cast<String *>(r_dest);
dest->parse_utf16(p_contents);
String *dest = memnew_placement(r_dest, String);
dest->append_utf16(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) {
if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf16((const char16_t *)p_contents);
// wchar_t is 16 bit (UTF-16).
String *dest = memnew_placement(r_dest, String);
dest->append_utf16((const char16_t *)p_contents);
} else {
// wchar_t is 32 bit, copy.
memnew_placement(r_dest, String((const char32_t *)p_contents));
// wchar_t is 32 bit (UTF-32).
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) {
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) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf8(p_contents, p_size);
String *dest = memnew_placement(r_dest, String);
dest->append_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) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
return (GDExtensionInt)dest->parse_utf8(p_contents, p_size);
String *dest = memnew_placement(r_dest, String);
return (GDExtensionInt)dest->append_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) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf16(p_contents, p_char_count);
String *dest = memnew_placement(r_dest, String);
dest->append_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) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
return (GDExtensionInt)dest->parse_utf16(p_contents, p_char_count, p_default_little_endian);
String *dest = memnew_placement(r_dest, String);
return (GDExtensionInt)dest->append_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) {
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) {
if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf16((const char16_t *)p_contents, p_char_count);
// wchar_t is 16 bit (UTF-16).
String *dest = memnew_placement(r_dest, String);
dest->append_utf16((const char16_t *)p_contents, p_char_count);
} else {
// wchar_t is 32 bit, copy.
memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count));
// wchar_t is 32 bit (UTF-32).
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) {
String *self = (String *)p_self;
CharString cs = self->ascii(true);
CharString cs = self->latin1();
GDExtensionInt len = cs.length();
if (r_text) {
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) {
String tmp;
tmp.parse_utf8(p_contents);
String tmp = String::utf8(p_contents);
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) {
String tmp;
tmp.parse_utf8(p_contents, p_size);
String tmp = String::utf8(p_contents, p_size);
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));
}
List<Variant> keys;
values.get_key_list(&keys);
for (const Variant &E : keys) {
values_map.insert(E, values[E]);
for (const KeyValue<Variant, Variant> &kv : values) {
values_map.insert(kv.key, kv.value);
}
placeholder->update(properties_list, values_map);
@ -1572,6 +1577,15 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt
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
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))));
@ -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)
void gdextension_setup_interface() {
#ifndef DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(get_godot_version);
#endif // DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(get_godot_version2);
REGISTER_INTERFACE_FUNC(mem_alloc);
REGISTER_INTERFACE_FUNC(mem_realloc);
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_update);
REGISTER_INTERFACE_FUNC(object_get_script_instance);
REGISTER_INTERFACE_FUNC(object_set_script_instance);
#ifndef DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(callable_custom_create);
#endif // DISABLE_DEPRECATED

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_INTERFACE_H
#define GDEXTENSION_INTERFACE_H
#pragma once
/* 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.
@ -401,6 +400,9 @@ typedef struct {
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 */
typedef enum {
@ -790,9 +792,22 @@ typedef struct {
const char *string;
} 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
* @since 4.1
* @deprecated in Godot 4.5. Use `get_godot_version2` instead.
*
* Gets the Godot version that the GDExtension was loaded into.
*
@ -800,6 +815,16 @@ typedef struct {
*/
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 */
/**
@ -2721,6 +2746,17 @@ typedef void (*GDExtensionInterfacePlaceHolderScriptInstanceUpdate)(GDExtensionS
*/
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 */
/**
@ -3078,8 +3114,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *
*/
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
}
#endif
#endif // GDEXTENSION_INTERFACE_H

View file

@ -307,12 +307,12 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
bool compatible = true;
// Check version lexicographically.
if (VERSION_MAJOR != compatibility_minimum[0]) {
compatible = VERSION_MAJOR > compatibility_minimum[0];
} else if (VERSION_MINOR != compatibility_minimum[1]) {
compatible = VERSION_MINOR > compatibility_minimum[1];
if (GODOT_VERSION_MAJOR != compatibility_minimum[0]) {
compatible = GODOT_VERSION_MAJOR > compatibility_minimum[0];
} else if (GODOT_VERSION_MINOR != compatibility_minimum[1]) {
compatible = GODOT_VERSION_MINOR > compatibility_minimum[1];
} else {
compatible = VERSION_PATCH >= compatibility_minimum[2];
compatible = GODOT_VERSION_PATCH >= compatibility_minimum[2];
}
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));
@ -334,15 +334,15 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
}
compatible = true;
if (VERSION_MAJOR != compatibility_maximum[0]) {
compatible = VERSION_MAJOR < compatibility_maximum[0];
} else if (VERSION_MINOR != compatibility_maximum[1]) {
compatible = VERSION_MINOR < compatibility_maximum[1];
if (GODOT_VERSION_MAJOR != compatibility_maximum[0]) {
compatible = GODOT_VERSION_MAJOR < compatibility_maximum[0];
} else if (GODOT_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.
else {
compatible = VERSION_PATCH <= compatibility_maximum[2];
compatible = GODOT_VERSION_PATCH <= compatibility_maximum[2];
}
#endif

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_LIBRARY_LOADER_H
#define GDEXTENSION_LIBRARY_LOADER_H
#pragma once
#include <functional>
@ -38,6 +37,8 @@
#include "core/os/shared_object.h"
class GDExtensionLibraryLoader : public GDExtensionLoader {
GDSOFTCLASS(GDExtensionLibraryLoader, GDExtensionLoader);
friend class GDExtensionManager;
friend class GDExtension;
@ -81,5 +82,3 @@ public:
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. */
/**************************************************************************/
#ifndef GDEXTENSION_LOADER_H
#define GDEXTENSION_LOADER_H
#pragma once
#include "core/object/ref_counted.h"
class GDExtension;
class GDExtensionLoader : public RefCounted {
GDSOFTCLASS(GDExtensionLoader, GDExtensionLoader);
public:
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;
@ -44,5 +45,3 @@ public:
virtual bool has_library_changed() 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. */
/**************************************************************************/
#ifndef GDEXTENSION_MANAGER_H
#define GDEXTENSION_MANAGER_H
#pragma once
#include "core/extension/gdextension.h"
@ -92,5 +91,3 @@ public:
};
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. */
/**************************************************************************/
#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H
#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H
#pragma once
#ifndef DISABLE_DEPRECATED
@ -58,5 +57,3 @@ public:
};
#endif // DISABLE_DEPRECATED
#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H

View file

@ -1,55 +1,37 @@
import zlib
import methods
def run(target, source, env):
src = str(source[0])
dst = str(target[0])
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
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
buffer = methods.get_buffer(str(source[0]))
decomp_size = len(buffer)
buffer = methods.compress_buffer(buffer)
with methods.generated_wrapper(str(target[0])) as file:
file.write(f"""\
#ifdef TOOLS_ENABLED
#include "core/io/compression.h"
#include "core/io/file_access.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")
g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n")
for i in range(len(buf)):
g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
g.write(
"""
class GDExtensionInterfaceDump {
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());
};
};
class GDExtensionInterfaceDump {{
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 // GDEXTENSION_INTERFACE_DUMP_H
"""
)
""")

View file

@ -119,10 +119,7 @@ def generate_ex_version(argcount, const=False, returns=False):
def run(target, source, env):
max_versions = 12
txt = """
#ifndef GDEXTENSION_WRAPPERS_GEN_H
#define GDEXTENSION_WRAPPERS_GEN_H
"""
txt = "#pragma once"
for i in range(max_versions + 1):
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, True)
txt += "\n#endif\n"
with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
f.write(txt)

View file

@ -28,12 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DEFAULT_CONTROLLER_MAPPINGS_H
#define DEFAULT_CONTROLLER_MAPPINGS_H
#pragma once
class DefaultControllerMappings {
public:
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;
}
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());
}
}
@ -1594,8 +1594,8 @@ void Input::parse_mapping(const String &p_mapping) {
continue;
}
String output = entry[idx].get_slice(":", 0).replace(" ", "");
String input = entry[idx].get_slice(":", 1).replace(" ", "");
String output = entry[idx].get_slicec(':', 0).remove_char(' ');
String input = entry[idx].get_slicec(':', 1).remove_char(' ');
if (output.length() < 1 || input.length() < 2) {
continue;
}

View file

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

View file

@ -2,18 +2,22 @@
from collections import OrderedDict
import methods
def make_default_controller_mappings(target, source, env):
dst = str(target[0])
with open(dst, "w", encoding="utf-8", newline="\n") as g:
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write('#include "core/typedefs.h"\n')
g.write('#include "core/input/default_controller_mappings.h"\n')
with methods.generated_wrapper(str(target[0])) as file:
file.write("""\
#include "core/input/default_controller_mappings.h"
#include "core/typedefs.h"
""")
# ensure mappings have a consistent order
platform_mappings: dict = OrderedDict()
for src_path in source:
with open(str(src_path), "r", encoding="utf-8") as f:
platform_mappings = OrderedDict()
for src_path in map(str, source):
with open(src_path, "r", encoding="utf-8") as f:
# read mapping file and skip header
mapping_file_lines = f.readlines()[2:]
@ -32,28 +36,28 @@ def make_default_controller_mappings(target, source, env):
line_parts = line.split(",")
guid = line_parts[0]
if guid in platform_mappings[current_platform]:
g.write(
file.write(
"// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
src_path, current_platform, platform_mappings[current_platform][guid]
)
)
platform_mappings[current_platform][guid] = line
platform_variables = {
"Linux": "#ifdef LINUXBSD_ENABLED",
"Windows": "#ifdef WINDOWS_ENABLED",
"Mac OS X": "#ifdef MACOS_ENABLED",
"Android": "#ifdef ANDROID_ENABLED",
"iOS": "#ifdef IOS_ENABLED",
"Web": "#ifdef WEB_ENABLED",
PLATFORM_VARIABLES = {
"Linux": "LINUXBSD",
"Windows": "WINDOWS",
"Mac OS X": "MACOS",
"Android": "ANDROID",
"iOS": "IOS",
"Web": "WEB",
}
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
file.write("const char *DefaultControllerMappings::mappings[] = {\n")
for platform, mappings in platform_mappings.items():
variable = platform_variables[platform]
g.write("{}\n".format(variable))
variable = PLATFORM_VARIABLES[platform]
file.write(f"#ifdef {variable}_ENABLED\n")
for mapping in mappings.values():
g.write('\t"{}",\n'.format(mapping))
g.write("#endif\n")
file.write(f'\t"{mapping}",\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. */
/**************************************************************************/
#ifndef INPUT_ENUMS_H
#define INPUT_ENUMS_H
#pragma once
#include "core/error/error_macros.h"
@ -138,4 +137,10 @@ inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
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> mask;
BitField<KeyModifierMask> mask = {};
if (is_ctrl_pressed()) {
mask.set_flag(KeyModifierMask::CTRL);
}
@ -385,11 +385,11 @@ bool InputEventKey::is_echo() 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 {
return physical_keycode | (int64_t)get_modifiers_mask();
return physical_keycode | get_modifiers_mask();
}
Key InputEventKey::get_key_label_with_modifiers() const {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INPUT_EVENT_H
#define INPUT_EVENT_H
#pragma once
#include "core/input/input_enums.h"
#include "core/io/resource.h"
@ -209,7 +208,7 @@ public:
class InputEventMouse : public InputEventWithModifiers {
GDCLASS(InputEventMouse, InputEventWithModifiers);
BitField<MouseButtonMask> button_mask;
BitField<MouseButtonMask> button_mask = MouseButtonMask::NONE;
Vector2 pos;
Vector2 global_pos;
@ -595,5 +594,3 @@ public:
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("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_get_deadzone", "action"), &InputMap::action_get_deadzone);
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;
}
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());
}
}
@ -181,6 +183,25 @@ bool InputMap::has_action(const StringName &p_action) const {
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) {
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;
}
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);
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_copy", TTRC("Copy") },
{ "ui_paste", TTRC("Paste") },
{ "ui_focus_mode", TTRC("Toggle Tab Focus Mode") },
{ "ui_undo", TTRC("Undo") },
{ "ui_redo", TTRC("Redo") },
{ "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_graph_duplicate", TTRC("Duplicate 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_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
{ "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 */
};
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++) {
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));
default_builtin_cache.insert("ui_end", inputs);
inputs = List<Ref<InputEvent>>();
default_builtin_cache.insert("ui_accessibility_drag_and_drop", inputs);
// ///// UI basic Shortcuts /////
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));
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.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
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));
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 /////
inputs = List<Ref<InputEvent>>();
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));
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;
}

View file

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

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SHORTCUT_H
#define SHORTCUT_H
#pragma once
#include "core/input/input_event.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);
};
#endif // SHORTCUT_H

View file

@ -42,6 +42,12 @@
#include <brotli/decode.h>
#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) {
switch (p_mode) {
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;
} break;
case MODE_ZSTD: {
ZSTD_DCtx *dctx = ZSTD_createDCtx();
if (zstd_long_distance_matching) {
ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size);
MutexLock lock(mutex);
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;
} break;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef COMPRESSION_H
#define COMPRESSION_H
#pragma once
#include "core/templates/vector.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_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. */
/**************************************************************************/
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
#pragma once
#include "core/io/file_access.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_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 = full_dir.replace("\\", "/");
full_dir = full_dir.replace_char('\\', '/');
String base;
@ -336,7 +336,7 @@ Ref<DirAccess> DirAccess::create_temp(const String &p_prefix, bool p_keep, Error
uint32_t suffix_i = 0;
String path;
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());
String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
path = (p_prefix.is_empty() ? "" : p_prefix + "-") + suffix;
@ -626,6 +626,10 @@ bool DirAccess::is_case_sensitive(const String &p_path) const {
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() {
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);
@ -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("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_hidden"), "set_include_hidden", "get_include_hidden");

View file

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

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DTLS_SERVER_H
#define DTLS_SERVER_H
#pragma once
#include "core/io/net_socket.h"
#include "core/io/packet_peer_dtls.h"
@ -53,5 +52,3 @@ public:
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;
String path;
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());
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));
@ -259,7 +259,7 @@ FileAccess::AccessType FileAccess::get_access_type() const {
String FileAccess::fix_path(const String &p_path) const {
// 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) {
case ACCESS_RESOURCES: {
@ -313,9 +313,15 @@ uint16_t FileAccess::get_16() const {
uint16_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint16_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP16(data);
}
#else
if (big_endian) {
data = BSWAP16(data);
}
#endif
return data;
}
@ -324,9 +330,15 @@ uint32_t FileAccess::get_32() const {
uint32_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint32_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP32(data);
}
#else
if (big_endian) {
data = BSWAP32(data);
}
#endif
return data;
}
@ -335,9 +347,15 @@ uint64_t FileAccess::get_64() const {
uint64_t data = 0;
get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint64_t));
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
data = BSWAP64(data);
}
#else
if (big_endian) {
data = BSWAP64(data);
}
#endif
return data;
}
@ -429,7 +447,7 @@ class CharBuffer {
public:
_FORCE_INLINE_ CharBuffer() :
buffer(stack_buffer),
capacity(sizeof(stack_buffer) / sizeof(char)) {
capacity(std::size(stack_buffer)) {
}
_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;
String s;
s.parse_utf8((const char *)w, len, p_skip_cr);
s.append_utf8((const char *)w, len, p_skip_cr);
return s;
}
@ -574,25 +592,43 @@ bool FileAccess::store_8(uint8_t p_dest) {
}
bool FileAccess::store_16(uint16_t p_dest) {
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
p_dest = BSWAP16(p_dest);
}
#else
if (big_endian) {
p_dest = BSWAP16(p_dest);
}
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint16_t));
}
bool FileAccess::store_32(uint32_t p_dest) {
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
p_dest = BSWAP32(p_dest);
}
#else
if (big_endian) {
p_dest = BSWAP32(p_dest);
}
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint32_t));
}
bool FileAccess::store_64(uint64_t p_dest) {
#ifdef BIG_ENDIAN_ENABLED
if (!big_endian) {
p_dest = BSWAP64(p_dest);
}
#else
if (big_endian) {
p_dest = BSWAP64(p_dest);
}
#endif
return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint64_t));
}
@ -629,8 +665,29 @@ uint64_t FileAccess::get_modified_time(const String &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));
uint64_t mt = fa->_get_modified_time(p_file);
return mt;
return fa->_get_modified_time(p_file);
}
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) {
@ -723,9 +780,7 @@ String FileAccess::get_pascal_string() {
get_buffer((uint8_t *)cs.ptr(), sl);
cs[sl] = 0;
String ret;
ret.parse_utf8(cs.ptr(), sl);
return ret;
return String::utf8(cs.ptr(), sl);
}
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;
ret.parse_utf8((const char *)array.ptr(), array.size());
ret.append_utf8((const char *)array.ptr(), array.size());
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_double"), &FileAccess::get_double);
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_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
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_double", "value"), &FileAccess::store_double);
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_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
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("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("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. */
/**************************************************************************/
#ifndef FILE_ACCESS_H
#define FILE_ACCESS_H
#pragma once
#include "core/io/compression.h"
#include "core/math/math_defs.h"
@ -87,7 +86,11 @@ public:
typedef void (*FileCloseFailNotify)(const String &);
typedef Ref<FileAccess> (*CreateFunc)();
#ifdef BIG_ENDIAN_ENABLED
bool big_endian = true;
#else
bool big_endian = false;
#endif
bool real_is_double = false;
virtual BitField<UnixPermissionFlags> _get_unix_permissions(const String &p_file) = 0;
@ -105,6 +108,8 @@ protected:
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 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);
static FileCloseFailNotify close_fail_notify;
@ -239,6 +244,8 @@ public:
static CreateFunc get_create_func(AccessType p_access);
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_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 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::ModeFlags);
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 {
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(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;
}
for (uint64_t i = 0; i < p_length; i++) {
p_dst[i] = read_ptr[read_pos];
read_pos++;
if (read_pos >= read_block_size) {
read_block++;
uint64_t dst_idx = 0;
while (true) {
// Copy over as much of our current block as possible.
const uint32_t copied_bytes_count = MIN(p_length - dst_idx, read_block_size - read_pos);
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) {
//read another 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;
} else {
read_block--;
at_end = true;
if (i + 1 < p_length) {
read_eof = true;
}
return i + 1;
}
if (dst_idx == p_length) {
// We're done! We read back all that was requested.
return p_length;
}
// 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;
@ -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) {
if (f.is_valid()) {
return f->_get_unix_permissions(p_file);

View file

@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef FILE_ACCESS_COMPRESSED_H
#define FILE_ACCESS_COMPRESSED_H
#pragma once
#include "core/io/compression.h"
#include "core/io/file_access.h"
class FileAccessCompressed : public FileAccess {
GDSOFTCLASS(FileAccessCompressed, FileAccess);
Compression::Mode cmode = Compression::MODE_ZSTD;
bool writing = false;
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 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 Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
@ -107,5 +109,3 @@ public:
FileAccessCompressed() {}
virtual ~FileAccessCompressed();
};
#endif // FILE_ACCESS_COMPRESSED_H

View file

@ -30,9 +30,17 @@
#include "file_access_encrypted.h"
#include "core/crypto/crypto_core.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) {
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);
@ -48,9 +56,15 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
key = p_key;
if (p_iv.is_empty()) {
iv.resize(16);
CryptoCore::RandomGenerator rng;
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
Error err = rng.get_random_bytes(iv.ptrw(), 16);
if (unlikely(!_fae_static_rng)) {
_fae_static_rng = memnew(CryptoCore::RandomGenerator);
if (_fae_static_rng->init() != OK) {
memdelete(_fae_static_rng);
_fae_static_rng = nullptr;
ERR_FAIL_V_MSG(FAILED, "Failed to initialize random number generator.");
}
}
Error err = _fae_static_rng->get_random_bytes(iv.ptrw(), 16);
ERR_FAIL_COND_V(err != OK, err);
} else {
ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
@ -265,7 +279,27 @@ bool FileAccessEncrypted::file_exists(const String &p_name) {
}
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) {

View file

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

View file

@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef FILE_ACCESS_MEMORY_H
#define FILE_ACCESS_MEMORY_H
#pragma once
#include "core/io/file_access.h"
class FileAccessMemory : public FileAccess {
GDSOFTCLASS(FileAccessMemory, FileAccess);
uint8_t *data = nullptr;
uint64_t length = 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 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 Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
@ -78,5 +81,3 @@ public:
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.
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();
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);
cs[sl] = 0;
String path;
path.parse_utf8(cs.ptr(), sl);
String path = String::utf8(cs.ptr(), sl);
uint64_t ofs = f->get_64();
uint64_t size = f->get_64();
uint8_t md5[16];
@ -550,7 +548,7 @@ String DirAccessPack::get_drive(int p_drive) {
}
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
if (p_dir == "..") {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef FILE_ACCESS_PACK_H
#define FILE_ACCESS_PACK_H
#pragma once
#include "core/io/dir_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_ 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_ bool has_directory(const String &p_path);
@ -156,6 +157,7 @@ public:
};
class FileAccessPack : public FileAccess {
GDSOFTCLASS(FileAccessPack, FileAccess);
PackedData::PackedFile pf;
mutable uint64_t pos;
@ -165,6 +167,8 @@ class FileAccessPack : public FileAccess {
Ref<FileAccess> f;
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_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 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);
};
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) {
String simplified_path = p_path.simplify_path().trim_prefix("res://");
PathMD5 pmd5(simplified_path.md5_buffer());
@ -225,6 +242,7 @@ bool PackedData::has_directory(const String &p_path) {
}
class DirAccessPack : public DirAccess {
GDSOFTCLASS(DirAccessPack, DirAccess);
PackedData::PackedDir *current;
List<String> list_dirs;
@ -272,5 +290,3 @@ Ref<DirAccess> PackedData::try_open_directory(const String &p_path) {
}
return da;
}
#endif // FILE_ACCESS_PACK_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef FILE_ACCESS_ZIP_H
#define FILE_ACCESS_ZIP_H
#pragma once
#ifdef MINIZIP_ENABLED
@ -74,6 +73,7 @@ public:
};
class FileAccessZip : public FileAccess {
GDSOFTCLASS(FileAccessZip, FileAccess);
unzFile zfile = nullptr;
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 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 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 // 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 query = "";
Array keys = p_dict.keys();
for (int i = 0; i < keys.size(); ++i) {
String encoded_key = String(keys[i]).uri_encode();
const Variant &value = p_dict[keys[i]];
for (const KeyValue<Variant, Variant> &kv : p_dict) {
String encoded_key = String(kv.key).uri_encode();
const Variant &value = kv.value;
switch (value.get_type()) {
case Variant::ARRAY: {
// Repeat the key with every values
@ -118,7 +117,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() {
continue;
}
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;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef HTTP_CLIENT_H
#define HTTP_CLIENT_H
#pragma once
#include "core/crypto/crypto.h"
#include "core/io/ip.h"
@ -205,5 +204,3 @@ public:
VARIANT_ENUM_CAST(HTTPClient::ResponseCode)
VARIANT_ENUM_CAST(HTTPClient::Method);
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();
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();
} else if (host_lower.begins_with("https://")) {
if (tls_options.is_null()) {
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);
@ -196,7 +196,7 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<
// Should it add utf8 encoding?
}
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) {
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')) {
// End of response, parse.
response_str.push_back(0);
String response;
response.parse_utf8((const char *)response_str.ptr(), response_str.size());
String response = String::utf8((const char *)response_str.ptr(), response_str.size());
Vector<String> responses = response.split("\n");
body_size = -1;
chunked = false;
@ -508,11 +507,11 @@ Error HTTPClientTCP::poll() {
continue;
}
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;
} 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") {
chunked = true;
}

View file

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

View file

@ -31,7 +31,6 @@
#include "image.h"
#include "core/config/project_settings.h"
#include "core/error/error_list.h"
#include "core/error/error_macros.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
@ -89,11 +88,13 @@ SavePNGFunc Image::save_png_func = nullptr;
SaveJPGFunc Image::save_jpg_func = nullptr;
SaveEXRFunc Image::save_exr_func = nullptr;
SaveWebPFunc Image::save_webp_func = nullptr;
SaveDDSFunc Image::save_dds_func = nullptr;
SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr;
SaveDDSBufferFunc Image::save_dds_buffer_func = nullptr;
// External loader function pointers.
@ -105,6 +106,7 @@ ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_dds_mem_loader_func = nullptr;
// 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) {
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;
}
@ -796,7 +798,7 @@ Image::Format Image::get_format() const {
}
static double _bicubic_interp_kernel(double x) {
x = ABS(x);
x = Math::abs(x);
double bc = 0;
@ -1139,7 +1141,7 @@ bool Image::is_size_po2() const {
}
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 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) {
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 */;
@ -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) {
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_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.");
@ -1515,7 +1516,7 @@ void Image::crop(int p_width, int p_height) {
}
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(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() {
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(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() {
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();
if (used_mipmaps) {
@ -1697,7 +1698,7 @@ void Image::flip_y() {
}
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();
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;
}
bool Image::_can_modify(Format p_format) const {
return !Image::is_format_compressed(p_format);
}
template <typename Component, int CC, bool renormalize,
void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
void (*renormalize_func)(Component *)>
@ -1926,7 +1923,7 @@ void Image::shrink_x2() {
memcpy(new_data.ptrw(), data.ptr() + ofs, new_size);
} else {
// 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));
ERR_FAIL_COND(data.is_empty() || new_data.is_empty());
@ -1963,7 +1960,7 @@ void Image::normalize() {
}
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(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 {
return (data.size() == 0);
return (data.is_empty());
}
Vector<uint8_t> Image::get_data() const {
@ -2297,7 +2294,7 @@ void Image::initialize_data(const char **p_xpm) {
switch (status) {
case READING_HEADER: {
String line_str = line_ptr;
line_str.replace("\t", " ");
line_str.replace_char('\t', ' ');
size_width = line_str.get_slicec(' ', 0).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 {
if (format == FORMAT_L8 || format == FORMAT_RGB8 || format == FORMAT_RG8) {
return false;
}
int64_t len = data.size();
int w, h;
int64_t len;
_get_mipmap_offset_and_size(1, len, w, h);
if (len == 0) {
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) {
case FORMAT_LA8: {
for (int i = 0; i < (len >> 1); i++) {
DETECT_NON_ALPHA(data_ptr[(i << 1) + 1]);
}
const int pixel_count = len / 2;
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;
case FORMAT_RGBA8: {
for (int i = 0; i < (len >> 2); i++) {
DETECT_NON_ALPHA(data_ptr[(i << 2) + 3])
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++) {
if ((pixeldata[i] & 0xFF000000) != 0) {
return false;
}
}
} break;
case FORMAT_RGBA4444: {
const int pixel_count = len / 2;
const uint16_t *pixeldata = reinterpret_cast<const uint16_t *>(data.ptr());
case FORMAT_DXT3:
case FORMAT_DXT5: {
detected = true;
for (int i = 0; i < pixel_count; i++) {
if ((pixeldata[i] & 0x000F) != 0) {
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;
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 {
@ -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);
}
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 {
if (save_webp_func == nullptr) {
return ERR_UNAVAILABLE;
@ -2682,6 +2722,19 @@ Error Image::decompress() {
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) {
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.");
@ -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(srcdsize == 0);
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 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) {
if (data.size() == 0) {
if (data.is_empty()) {
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();
@ -3059,10 +3112,10 @@ void Image::fill(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;
}
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());
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;
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;
((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) {
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();
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_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false));
ClassDB::bind_method(D_METHOD("save_dds", "path"), &Image::save_dds);
ClassDB::bind_method(D_METHOD("save_dds_to_buffer"), &Image::save_dds_to_buffer);
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));
@ -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_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_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_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() {
if (data.size() == 0) {
if (data.is_empty()) {
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) {
ERR_FAIL_COND(!_can_modify(format));
ERR_FAIL_COND(is_compressed());
clear_mipmaps();
convert(Image::FORMAT_RF);
@ -3799,7 +3856,7 @@ bool Image::detect_signed(bool p_include_mips) const {
}
void Image::srgb_to_linear() {
if (data.size() == 0) {
if (data.is_empty()) {
return;
}
@ -3830,7 +3887,7 @@ void Image::srgb_to_linear() {
}
void Image::linear_to_srgb() {
if (data.size() == 0) {
if (data.is_empty()) {
return;
}
@ -3861,7 +3918,7 @@ void Image::linear_to_srgb() {
}
void Image::premultiply_alpha() {
if (data.size() == 0) {
if (data.is_empty()) {
return;
}
@ -3883,7 +3940,7 @@ void Image::premultiply_alpha() {
}
void Image::fix_alpha_edges() {
if (data.size() == 0) {
if (data.is_empty()) {
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);
}
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) {
ERR_FAIL_NULL_V_MSG(
_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.
Dictionary result;
result["max"] = INFINITY;
result["mean"] = INFINITY;
result["mean_squared"] = INFINITY;
result["root_mean_squared"] = INFINITY;
result["max"] = Math::INF;
result["mean"] = Math::INF;
result["mean_squared"] = Math::INF;
result["root_mean_squared"] = Math::INF;
result["peak_snr"] = 0.0f;
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. */
/**************************************************************************/
#ifndef IMAGE_H
#define IMAGE_H
#pragma once
#include "core/io/resource.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 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 {
GDCLASS(Image, Resource);
@ -186,10 +188,12 @@ public:
static SaveJPGFunc save_jpg_func;
static SaveEXRFunc save_exr_func;
static SaveWebPFunc save_webp_func;
static SaveDDSFunc save_dds_func;
static SavePNGBufferFunc save_png_buffer_func;
static SaveEXRBufferFunc save_exr_buffer_func;
static SaveJPGBufferFunc save_jpg_buffer_func;
static SaveWebPBufferFunc save_webp_buffer_func;
static SaveDDSBufferFunc save_dds_buffer_func;
// External loader function pointers.
@ -201,6 +205,7 @@ public:
static ImageMemLoadFunc _bmp_mem_loader_func;
static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
static ImageMemLoadFunc _ktx_mem_loader_func;
static ImageMemLoadFunc _dds_mem_loader_func;
// 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.
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;
@ -334,9 +338,11 @@ public:
static Ref<Image> load_from_file(const String &p_path);
Error save_png(const String &p_path) 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_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_dds_to_buffer() const;
Error save_exr(const String &p_path, bool p_grayscale = false) const;
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
@ -373,6 +379,8 @@ public:
bool is_compressed() const;
static bool is_format_compressed(Format p_format);
static bool can_decompress(const String &p_format_tag);
void fix_alpha_edges();
void premultiply_alpha();
void srgb_to_linear();
@ -403,6 +411,7 @@ public:
Error load_tga_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_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_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::RoughnessChannel)
VARIANT_ENUM_CAST(Image::ASTCFormat)
#endif // IMAGE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
#pragma once
#include "core/core_bind.h"
#include "core/io/file_access.h"
@ -108,5 +107,3 @@ public:
virtual bool handles_type(const String &p_type) 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. */
/**************************************************************************/
#ifndef IP_H
#define IP_H
#pragma once
#include "core/io/ip_address.h"
#include "core/os/os.h"
@ -110,5 +109,3 @@ public:
VARIANT_ENUM_CAST(IP::Type);
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) {
String ip;
if (p_start != 0) {
ip = p_string.substr(p_start, p_string.length() - p_start);
ip = p_string.substr(p_start);
} else {
ip = p_string;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef IP_ADDRESS_H
#define IP_ADDRESS_H
#pragma once
#include "core/string/ustring.h"
@ -96,4 +95,6 @@ public:
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.");
p_markers.insert(d.id());
List<Variant> keys;
d.get_key_list(&keys);
LocalVector<Variant> keys = d.get_key_list();
if (p_sort_keys) {
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: {
const Vector2 v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
Array args = { v.x, v.y };
RETURN_ARGS;
} break;
case Variant::VECTOR2I: {
const Vector2i v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
Array args = { v.x, v.y };
RETURN_ARGS;
} break;
case Variant::RECT2: {
const Rect2 r = p_variant;
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);
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
RETURN_ARGS;
} break;
case Variant::RECT2I: {
const Rect2i r = p_variant;
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);
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
RETURN_ARGS;
} break;
case Variant::VECTOR3: {
const Vector3 v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
Array args = { v.x, v.y, v.z };
RETURN_ARGS;
} break;
case Variant::VECTOR3I: {
const Vector3i v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
Array args = { v.x, v.y, v.z };
RETURN_ARGS;
} break;
case Variant::TRANSFORM2D: {
const Transform2D t = p_variant;
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);
Array args = { t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y };
RETURN_ARGS;
} break;
case Variant::VECTOR4: {
const Vector4 v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
args.push_back(v.w);
Array args = { v.x, v.y, v.z, v.w };
RETURN_ARGS;
} break;
case Variant::VECTOR4I: {
const Vector4i v = p_variant;
Array args;
args.push_back(v.x);
args.push_back(v.y);
args.push_back(v.z);
args.push_back(v.w);
Array args = { v.x, v.y, v.z, v.w };
RETURN_ARGS;
} break;
case Variant::PLANE: {
const Plane p = p_variant;
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);
Array args = { p.normal.x, p.normal.y, p.normal.z, p.d };
RETURN_ARGS;
} break;
case Variant::QUATERNION: {
const Quaternion q = p_variant;
Array args;
args.push_back(q.x);
args.push_back(q.y);
args.push_back(q.z);
args.push_back(q.w);
Array args = { q.x, q.y, q.z, q.w };
RETURN_ARGS;
} break;
case Variant::AABB: {
const AABB aabb = p_variant;
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);
Array args = { aabb.position.x, aabb.position.y, aabb.position.z, aabb.size.x, aabb.size.y, aabb.size.z };
RETURN_ARGS;
} break;
case Variant::BASIS: {
const Basis b = p_variant;
Array args;
args.push_back(b.get_column(0).x);
args.push_back(b.get_column(0).y);
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);
Array args = { b.get_column(0).x, b.get_column(0).y, b.get_column(0).z,
b.get_column(1).x, b.get_column(1).y, b.get_column(1).z,
b.get_column(2).x, b.get_column(2).y, b.get_column(2).z };
RETURN_ARGS;
} break;
case Variant::TRANSFORM3D: {
const Transform3D t = p_variant;
Array args;
args.push_back(t.basis.get_column(0).x);
args.push_back(t.basis.get_column(0).y);
args.push_back(t.basis.get_column(0).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);
Array args = { t.basis.get_column(0).x, t.basis.get_column(0).y, t.basis.get_column(0).z,
t.basis.get_column(1).x, t.basis.get_column(1).y, t.basis.get_column(1).z,
t.basis.get_column(2).x, t.basis.get_column(2).y, t.basis.get_column(2).z,
t.origin.x, t.origin.y, t.origin.z };
RETURN_ARGS;
} break;
case Variant::PROJECTION: {
const Projection p = p_variant;
Array args;
args.push_back(p[0].x);
args.push_back(p[0].y);
args.push_back(p[0].z);
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);
Array args = { p[0].x, p[0].y, p[0].z, p[0].w,
p[1].x, p[1].y, p[1].z, p[1].w,
p[2].x, p[2].y, p[2].z, p[2].w,
p[3].x, p[3].y, p[3].z, p[3].w };
RETURN_ARGS;
} break;
case Variant::COLOR: {
const Color c = p_variant;
Array args;
args.push_back(c.r);
args.push_back(c.g);
args.push_back(c.b);
args.push_back(c.a);
Array args = { c.r, c.g, c.b, c.a };
RETURN_ARGS;
} 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.");
List<Variant> keys;
dict.get_key_list(&keys);
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));
for (const KeyValue<Variant, Variant> &kv : dict) {
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));
}
return ret;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef JSON_H
#define JSON_H
#pragma once
#include "core/io/resource.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 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 "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
#include "modules/regex/regex.h"
#else
class RegEx : public RefCounted {};
#endif // MODULE_REGEX_ENABLED
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
@ -156,7 +155,7 @@ void RotatedFileLogger::rotate_file() {
if (FileAccess::exists(base_path)) {
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;
if (!base_path.get_extension().is_empty()) {
backup_name += "." + base_path.get_extension();

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef LOGGER_H
#define LOGGER_H
#pragma once
#include "core/io/file_access.h"
#include "core/string/ustring.h"
@ -109,5 +108,3 @@ public:
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);
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;
// 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);
}
} 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 {
// No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`.
if (buf) {
@ -1849,19 +1849,16 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
r_len += 4;
List<Variant> keys;
dict.get_key_list(&keys);
for (const Variant &key : keys) {
for (const KeyValue<Variant, Variant> &kv : dict) {
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(len % 4, ERR_BUG);
r_len += len;
if (buf) {
buf += len;
}
const Variant *value = dict.getptr(key);
const Variant *value = dict.getptr(kv.key);
ERR_FAIL_NULL_V(value, ERR_BUG);
err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MARSHALLS_H
#define MARSHALLS_H
#pragma once
#include "core/math/math_defs.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);
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