Compare commits

...

10 commits

12413 changed files with 142 additions and 6094586 deletions

5
.gitignore vendored
View file

@ -7,3 +7,8 @@ config.log
.sconf_temp
engine/.github
project/.godot
build/PROJECT.pck
build/PROJECT.x86_64
build/PROJECT.exe
build.zip

3
.gitmodules vendored Normal file
View file

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

1
engine Submodule

@ -0,0 +1 @@
Subproject commit 215acd52e82f4c575abb715e25e54558deeef998

View file

@ -1,238 +0,0 @@
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 17.0.6).
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignArrayOfStructures: None
# AlignConsecutiveAssignments:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: true
# AlignConsecutiveBitFields:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveDeclarations:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveMacros:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveShortCaseStatements:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCaseColons: false
# AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLambdasOnASingleLine: All
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: MultiLine
# AttributeMacros:
# - __capability
# BinPackArguments: true
# BinPackParameters: true
# BitFieldColonSpacing: Both
# BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
# AfterControlStatement: Never
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# BeforeLambdaBody: false
# BeforeWhile: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakAfterAttributes: Never
# BreakAfterJavaFieldAnnotations: false
# BreakArrays: true
# BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
# BreakBeforeConceptDeclarations: Always
# BreakBeforeInlineASMColon: OnlyMultiline
# BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
# BreakInheritanceList: BeforeColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: "^ IWYU pragma:"
# CompactNamespaces: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DerivePointerAlignment: false
# DisableFormat: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IfMacros:
# - KJ_IF_MAYBE
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^".*"$
Priority: 1
- Regex: ^<.*\.h>$
Priority: 2
- Regex: ^<.*>$
Priority: 3
# IncludeIsMainRegex: (Test)?$
# IncludeIsMainSourceRegex: ""
# IndentAccessModifiers: false
# IndentCaseBlocks: false
IndentCaseLabels: true
# IndentExternBlock: AfterExternBlock
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentRequiresClause: true
IndentWidth: 4
# IndentWrappedFunctionNames: false
InsertBraces: true
# InsertNewlineAtEOF: false
# InsertTrailingCommas: None
# IntegerLiteralSeparator:
# Binary: 0
# BinaryMinDigits: 0
# Decimal: 0
# DecimalMinDigits: 0
# Hex: 0
# HexMinDigits: 0
JavaImportGroups:
- org.godotengine
- android
- androidx
- com.android
- com.google
- java
- javax
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtEOF: false
KeepEmptyLinesAtTheStartOfBlocks: false
# LambdaBodyIndentation: Signature
# Language: Cpp
# LineEnding: DeriveLF
# MacroBlockBegin: ""
# MacroBlockEnd: ""
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
# PPIndentWidth: -1
PackConstructorInitializers: NextLine
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakOpenParenthesis: 0
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyIndentedWhitespace: 0
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# QualifierAlignment: Leave
# ReferenceAlignment: Pointer
# ReflowComments: true
# RemoveBracesLLVM: false
# RemoveParentheses: Leave
RemoveSemicolon: true
# RequiresClausePosition: OwnLine
# RequiresExpressionIndentation: OuterScope
# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
# SortUsingDeclarations: LexicographicNumeric
# SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
# SpaceAfterTemplateKeyword: true
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCaseColon: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeJsonColon: false
# SpaceBeforeParens: ControlStatements
# SpaceBeforeParensOptions:
# AfterControlStatements: true
# AfterForeachMacros: true
# AfterFunctionDeclarationName: false
# AfterFunctionDefinitionName: false
# AfterIfMacros: true
# AfterOverloadedOperator: false
# AfterRequiresInClause: false
# AfterRequiresInExpression: false
# BeforeNonEmptyParentheses: false
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceBeforeSquareBrackets: false
# SpaceInEmptyBlock: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code.
Maximum: -1
# SpacesInParens: Never
# SpacesInParensOptions:
# InConditionalStatements: false
# InCStyleCasts: false
# InEmptyParentheses: false
# Other: false
# SpacesInSquareBrackets: false
Standard: c++20
# StatementAttributeLikeMacros:
# - Q_EMIT
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Always
# VerilogBreakBetweenInstancePorts: true
# WhitespaceSensitiveMacros:
# - BOOST_PP_STRINGIZE
# - CF_SWIFT_NAME
# - NS_SWIFT_NAME
# - PP_STRINGIZE
# - STRINGIZE

View file

@ -1,19 +0,0 @@
Checks:
- -*
- cppcoreguidelines-pro-type-member-init
- modernize-redundant-void-arg
- modernize-use-bool-literals
- modernize-use-default-member-init
- modernize-use-nullptr
- readability-braces-around-statements
- readability-redundant-member-init
HeaderFileExtensions: ["", h, hh, hpp, hxx, inc, glsl]
ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
FormatStyle: file
CheckOptions:
cppcoreguidelines-pro-type-member-init.IgnoreArrays: true
cppcoreguidelines-pro-type-member-init.UseAssignment: true
modernize-use-bool-literals.IgnoreMacros: false
modernize-use-default-member-init.IgnoreMacros: false
modernize-use-default-member-init.UseAssignment: true

View file

@ -1,31 +0,0 @@
# https://clangd.llvm.org/config
---
# Default conditions, apply everywhere.
Diagnostics:
Includes:
IgnoreHeader:
- core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere.
- \.compat\.inc
---
# Header-specific conditions.
If:
PathMatch: .*\.(h|hh|hpp|hxx|inc)
# Exclude certain, noisy warnings that lack full context. Replace with lowered severity if/when
# clangd gets diagnostic severity support. (See: https://github.com/clangd/clangd/issues/1937)
CompileFlags:
Add:
- -Wno-unneeded-internal-declaration
- -Wno-unused-const-variable
- -Wno-unused-function
- -Wno-unused-variable
---
# Suppress all third-party warnings.
If:
PathMatch: thirdparty/.*
Diagnostics:
Suppress: "*"

View file

@ -1,20 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
[{*.py,SConstruct,SCsub}]
indent_style = space
[{*.{yml,yaml},.clang{-format,-tidy,d}}]
indent_size = 2
indent_style = space
[*.svg]
insert_final_newline = false

View file

@ -1,68 +0,0 @@
# This file contains a list of Git commit hashes that should be hidden from the
# regular Git history. Typically, this includes commits involving mass auto-formatting
# or other normalizations. Commit hashes *must* use the full 40-character notation.
# To apply the ignore list in your local Git client, you must run:
#
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# This file is automatically used by GitHub.com's blame view.
# A Whole New World (clang-format edition)
5dbf1809c6e3e905b94b8764e99491e608122261
# Style: clang-format: Disable KeepEmptyLinesAtTheStartOfBlocks
0be6d925dc3c6413bce7a3ccb49631b8e4a6e67a
# Style: clang-format: Disable AllowShortIfStatementsOnASingleLine
e956e80c1fa1cc8aefcb1533e5acf5cf3c8ffdd9
# One Copyright Update to rule them all
d95794ec8a7c362b06a9cf080e2554ef77adb667
# Update copyright statements to 2022
fe52458154c64fb1b741df4f7bd10106395f7cbd
# Update copyright statements to 2021
b5334d14f7a471f94bcbd64d5bae2ad853d0b7f1
# Update copyright statements to 2020
a7f49ac9a107820a62677ee3fb49d38982a25165
# Update copyright statements to 2019
b16c309f82c77d606472c3c721a1857e323a09e7
# Update copyright statements to 2018
b50a9114b105dafafdda8248a38653bca314a6f3
# Welcome in 2017, dear changelog reader!
c7bc44d5ad9aae4902280012f7654e2318cd910e
# Update copyright to 2016 in headers
5be9ff7b6715a661e85f99b108f96340de7ef435
# Updated copyright year in all headers
fdaa2920eb21fff3320a17e9239e04dfadecdb00
# Add missing copyright headers and fix formatting
e4213e66b2dd8f5a87d8cf5015ac83ba3143279d
# Use HTTPS URL for Godot's website in the headers
bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
# Add "Godot Engine contributors" copyright line
df61dc4b2bd54a5a40c515493c76f5a458e5b541
# Enforce template syntax `typename` over `class`
9903e6779b70fc03aae70a37b9cf053f4f355b91
# Style: Apply new `clang-format` fixes
b37fc1014abf7adda70dc30b0822d775b3a4433f
# Set clang-format `RemoveSemicolon` rule to `true`
0d350e71086fffce0553811739aae9f6ad66136c
# Style: Apply clang-tidy fixes (superficial)
bb5f390fb9b466be35a5df7651323d7e66afca31
# Style: Enforce `AllowShortFunctionsOnASingleLine`
e06d83860d798b6766b23d6eae48557387a7db85

23
engine/.gitattributes vendored
View file

@ -1,23 +0,0 @@
# Properly detect languages on Github
*.h linguist-language=C++
*.inc linguist-language=C++
thirdparty/* linguist-vendored
# Normalize EOL for all files that Git considers text files
* text=auto eol=lf
# Except for Windows-only / Visual Studio files
*.bat eol=crlf
*.sln eol=crlf
*.csproj eol=crlf
misc/msvs/*.template eol=crlf
# And some test files where the EOL matters
*.test.txt -text
# The above only works properly for Git 2.10+, so for older versions
# we need to manually list the binary files we don't want modified.
*.icns binary
*.ico binary
*.jar binary
*.png binary
*.ttf binary
*.tza binary

383
engine/.gitignore vendored
View file

@ -1,383 +0,0 @@
# Godot .gitignore config
#
# Aims to encompass the most commonly found files that we don't want committed
# to Git, such as compilation output, IDE specific files, etc.
#
# It doesn't cover *all* thirdparty IDE extensions under the sun so if you have
# specific needs covered here, you can add them to:
# .git/info/exclude
#
# Or contribute them to this file if they're common enough that a good number of
# users would benefit from the shared rules.
#
# This file is organized by sections, with subsections ordered alphabetically.
# - Build configuration
# - Godot generated files
# - General build output
# - IDE and tool specific
# - Visual Studio specific
# - OS specific
###########################
### Build configuration ###
###########################
/custom.py
misc/hooks/pre-commit-custom-*
#############################
### Godot generated files ###
#############################
# Buildsystem
bin
*.gen.*
compile_commands.json
platform/windows/godot_res.res
# Ninja build files
*.ninja
.ninja/
run_ninja_env.bat
# Generated by Godot binary
.import/
/gdextension_interface.h
extension_api.json
logs/
# Generated by unit tests
tests/data/*.translation
tests/data/crypto/out*
############################
### General build output ###
############################
# C/C++ generated
*.a
*.ax
*.d
*.dll
*.lib
*.lo
*.o
*.os
*.ox
*.Plo
*.so
# Binutils tmp linker output of the form "stXXXXXX" where "X" is alphanumeric
st[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]
# Python development
.venv
venv
# Python generated
__pycache__/
*.pyc
# Python modules
.*_cache/
# Documentation
doc/_build/
# Android
.gradle/
local.properties
*.iml
.gradletasknamecache
project.properties
platform/android/java/*/.cxx/
platform/android/java/*/build/
platform/android/java/*/libs/
# iOS
*.dSYM
# Web platform
*.bc
platform/web/node_modules/
# Misc
*.debug
#############################
### IDE and tool specific ###
#############################
# Automake
.deps/*
.dirstamp
# ccls
.ccls-cache/
# clangd
.clangd/
.cache/
# CLion
cmake-build-debug
# Code::Blocks
*.cbp
*.layout
*.depend
# CodeLite
*.project
*.workspace
.codelite/
# Cppcheck
*.cppcheck
cppcheck-cppcheck-build-dir/
# Eclipse CDT
.cproject
.settings/
*.pydevproject
*.launch
# Emacs
\#*\#
.\#*
# GCOV code coverage
*.gcda
*.gcno
# Geany
*.geany
.geanyprj
# Gprof
gmon.out
# Jetbrains IDEs
.idea/
.fleet/
# Kate
*.kate-swp
.kateproject.build
# Kdevelop
*.kdev4
# Qt Creator
*.config
*.creator
*.creator.*
*.files
*.includes
*.cflags
*.cxxflags
# SCons
.sconf_temp
.sconsign*.dblite
.scons_env.json
.scons_node_count
# Sourcetrail
*.srctrl*
# Tags
# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
TAGS
!TAGS/
tags
*.tags
!tags/
gtags.files
GTAGS
GRTAGS
GPATH
cscope.files
cscope.out
cscope.in.out
cscope.po.out
# Vim
*.swo
*.swp
# Visual Studio Code
.vscode/
*.code-workspace
.history/
# Xcode
xcuserdata/
*.xcscmblueprint
*.xccheckout
*.xcodeproj/*
!misc/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
##############################
### Visual Studio specific ###
##############################
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# Ignore Visual Studio temporary files, build results, and
# files generated by popular Visual Studio add-ons.
# Actual VS project files we don't use
*.sln
*.vcxproj*
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Do not ignore arch-specific folders anywhere under thirdparty libraries
!thirdparty/**/x64/
!thirdparty/**/x86/
!thirdparty/**/arm/
!thirdparty/**/arm64/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Visual Studio 2017 auto generated files
Generated\ Files/
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# Others
ClientBin/
enc_temp_folder/
~$*
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# Hint file for IntelliSense
cpp.hint
###################
### OS specific ###
###################
# Linux
*~
.directory
# macOS
.DS_Store
__MACOSX
Godot.app
# Windows
# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
[Tt]humbs.db
[Tt]humbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msix
*.msm
*.msp
*.lnk
*.generated.props

View file

@ -1,195 +0,0 @@
Aaron Record <aaronjrecord@gmail.com>
ajreckof <66184050+ajreckof@users.noreply.github.com> <tbonhoure@ymail.com>
Alexander Hartmann <alex.hart.278@gmail.com>
Alexander Holland <alexander.holland@live.de>
Alexander Holland <alexander.holland@live.de> <alexander.holland@haw-hamburg.de>
Alexander Holland <alexander.holland@live.de> <AlexHolly>
Alfred Reinold Baudisch <alfred@alfredbaudisch.com>
Andrea Catania <info@andreacatania.com>
Anish Bhobe <anishbhobe@hotmail.com>
Anutrix <numaanzaheerahmed@yahoo.com>
Aren Villanueva <arenvillanueva@yomogi-soft.com> <aren@displaysweet.com>
Ariel Manzur <ariel@godotengine.org>
Ariel Manzur <ariel@godotengine.org> <puntob@gmail.com>
Ariel Manzur <ariel@godotengine.org> <punto@godotengine.org>
Ariel Manzur <ariel@godotengine.org> <ariel@okamstudio.com>
Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini.local>
Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini-2.local>
Arman Elgudzhyan <48544263+puchik@users.noreply.github.com>
A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> <over999ships@gmail.com>
Bastiaan Olij <mux213@gmail.com>
Benjamin <mafortion.benjamin@gmail.com>
Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.de>
Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.org>
Bruno Lourenço <madequa@users.noreply.github.com> <bmlourenco@gmail.com>
Chaosus <chaosus89@gmail.com>
ChibiDenDen <pdaniq@gmail.com>
Chris Bradfield <chris@kidscancode.org> <cb@scribe.net>
Clay John <claynjohn@gmail.com>
Clay John <claynjohn@gmail.com> <clayjohn@shaw.ca>
CookieBadger <emil.dobetsberger@gmail.com>
Dana Olson <dana@shineuponthee.com> <adolson@gmail.com>
dankan1890 <mewuidev2@gmail.com>
Daniel J. Ramirez <djrmuv@gmail.com>
Dario <dariosamo@gmail.com>
David Cambré <david.cambre@gmail.com> <David.Cambre@gmail.com>
DmitriySalnikov <salnikov.mine@yandex.ru>
DmitriySalnikov <salnikov.mine@yandex.ru> <dimokgamer@gmail.com>
Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
DeeJayLSP <djlsplays@gmail.com> <60024671+DeeJayLSP@users.noreply.github.com>
Emmanuel Barroga <emmanuelbarroga@gmail.com>
Eric M <itsjusteza@gmail.com>
Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
Erik Selecký <35656626+rxlecky@users.noreply.github.com>
Erik Selecký <35656626+rxlecky@users.noreply.github.com> <35656626+SeleckyErik@users.noreply.github.com>
Eveline Jarosz <marqin.pl@gmail.com>
Eveline Jarosz <marqin.pl@gmail.com> <marqin.pl+git@gmail.com>
Fabian <supagu@gmail.com>
Ferenc Arn <tagcup@yahoo.com>
Ferenc Arn <tagcup@yahoo.com> <tagcup@users.noreply.github.com>
FireForge <67974470+fire-forge@users.noreply.github.com> <isaacr.7.2005@gmail.com>
Florian Kothmeier <floriankothmeier@web.de>
foxydevloper <12120644+foxydevloper@users.noreply.github.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@google.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@fb.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@meta.com>
Geequlim <geequlim@gmail.com>
Gilles Roudiere <gilles.roudiere@gmail.com>
Gilles Roudiere <gilles.roudiere@gmail.com> <gilles.roudiere@laas.fr>
Gordon MacPherson <gordon@gordonite.tech>
Guilherme Felipe <guilhermefelipecgs@gmail.com>
Hakim <hakim.rouatbi@gmail.com>
Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
HaSa1002 <johawitt@outlook.de>
Hein-Pieter van Braam-Stewart <hp@tmm.cx>
Hugo Locurcio <hugo.locurcio@hugo.pro> <hugo.l@openmailbox.org>
Hugo Locurcio <hugo.locurcio@hugo.pro> <Calinou@users.noreply.github.com>
Hugo Locurcio <hugo.locurcio@hugo.pro> Calinou <calinou@opmbx.org>
Ian Bishop <ianb96@gmail.com>
Ignacio Etcheverry <ignalfonsore@gmail.com>
Ignacio Etcheverry <ignalfonsore@gmail.com> <neikeq@users.noreply.github.com>
Ilaria Cislaghi <cislaghi.ilaria@gmail.com>
Ilaria Cislaghi <cislaghi.ilaria@gmail.com> <ilaria.cislaghi@simedis.com>
Indah Sylvia <ISylvox@yahoo.com>
Ivan Shakhov <ivan.shakhov@jetbrains.com> <Ivan.Shakhov@jetbrains.com>
Ivan Shakhov <ivan.shakhov@jetbrains.com> <van800@gmail.com>
iwek <miwanczuk7@gmail.com>
J08nY <johny@neuromancer.sk> <jancar.jj@gmail.com>
J08nY <johny@neuromancer.sk> <J08nY@users.noreply.github.com>
Jake Young <young9003@gmail.com>
Jakub Grzesik <kubecz3k@gmail.com>
Jakub Marcowski <chubercikbattle@gmail.com> <01158831@pw.edu.pl>
Jakub Marcowski <chubercikbattle@gmail.com> <37378746+Chubercik@users.noreply.github.com>
janglee <merupatel123@gmail.com>
Jason Knight <00jknight@gmail.com> <jason@winterpixel.com>
Jean-Michel Bernard <jmb462@gmail.com>
Jérôme Gully <jerome.gully0@gmail.com>
JFonS <joan.fonssanchez@gmail.com>
jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
Johan Aires Rastén <johan@oljud.se>
Juan Linietsky <reduzio@gmail.com>
Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
Juan Linietsky <reduzio@gmail.com> <reduz@Juans-MBP.fibertel.com.ar>
Juan Linietsky <reduzio@gmail.com> <red@kyoko>
Julian Murgia <the.straton@gmail.com>
Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com>
karroffel <therzog@mail.de>
karroffel <therzog@mail.de> <thomas.herzog@mail.com>
karroffel <therzog@mail.de> <thomas.herzog@simedis.com>
Kasper Arnklit Frandsen <kasper.arnklit@gmail.com>
Kelly Thomas <kelly.thomas@hotmail.com.au>
Kongfa Waroros <gongpha@hotmail.com>
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> <fire@users.noreply.github.com>
kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
Leon Krause <lk@leonkrause.com> <eska@eska.me>
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
Liz Haas <27thLiz@gmail.com>
Liz Haas <27thLiz@gmail.com> <liu.gam3@gmail.com>
Liz Haas <27thLiz@gmail.com> <hinsbart@gmail.com>
Liz Haas <27thLiz@gmail.com> <hinsbart@users.noreply.github.com>
Liz Haas <27thLiz@gmail.com> <entenflugstuhl@gmail.com>
Logan Lang <devloglogan@gmail.com>
Manuele Finocchiaro <m4nu3lf@gmail.com>
Manuel Strey <manuel.strey@gmx.de>
Marcel Admiraal <madmiraal@users.noreply.github.com>
Marcelo Fernandez <marcelofg55@gmail.com>
Marcin Zawiejski <dragmz@gmail.com>
Marcus Elg <marcusaccounts@yahoo.se>
Mariano Javier Suligoy <marianognu.easyrpg@gmail.com>
Mario Schlack <m4r10.5ch14ck@gmail.com>
Mark DiBarry <markdibarry@protonmail.com>
marxin <mliska@suse.cz>
marynate <mary.w.nate@gmail.com> <marynate@github.com>
Mateo Kuruk Miccino <mateomiccino@gmail.com>
Max Hilbrunner <m.hilbrunner@gmail.com>
Max Hilbrunner <m.hilbrunner@gmail.com> <mhilbrunner@users.noreply.github.com>
MewPurPur <mew.pur.pur@abv.bg>
Michael Alexsander <michaelalexsander@protonmail.com>
Micky <micheledevita2@gmail.com> <66727710+Mickeon@users.noreply.github.com>
Nathan Franke <natfra@pm.me> <nathanwfranke@gmail.com>
Nathan Lovato <nathan@gdquest.com>
Nathan Warden <nathan@nathanwarden.com> <nathanwardenlee@icloud.com>
Nazarii <nazarii.yablonskyi.pp.2022@lpnu.ua>
Nicholas Huelin <62965063+SirQuartz@users.noreply.github.com>
Nils ANDRÉ-CHANG <nils@nilsand.re>
Nils ANDRÉ-CHANG <nils@nilsand.re> <nils.andre.chang@gmail.com>
Nông Văn Tình <vannongtinh@gmail.com>
Nuno Donato <nunodonato@gmail.com> <n.donato@estrelasustentavel.pt>
ocean (they/them) <anvilfolk@gmail.com>
Pawel Kowal <pkowal1982@gmail.com>
Pedro J. Estébanez <pedrojrulez@gmail.com> <RandomShaper@users.noreply.github.com>
Patrick Exner <patrick.exner1@web.de>
Patrick <firefly2442@gmail.com>
Paul Batty <p_batty@hotmail.co.uk>
Paul Batty <p_batty@hotmail.co.uk> <Paulb23@users.noreply.github.com>
Pāvels Nadtočajevs <7645683+bruvzg@users.noreply.github.com>
Pawel Kowal <pkowal1982@gmail.com> <pawel.kowal@javart.eu>
Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
Poommetee Ketson <poommetee@protonmail.com>
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
Radiant <69520693+RadiantUwU@users.noreply.github.com> <i.like.using.discord@gmail.com>
Rafał Mikrut <mikrutrafal@protonmail.com>
Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@users.noreply.github.com>
Ramesh Ravone <ramesh.maran443@gmail.com>
RaphaelHunter <raphael10241024@gmail.com>
RaphaelHunter <raphael10241024@gmail.com> <Raphael10241024@gmail.com>
RaphaelHunter <raphael10241024@gmail.com> <raphael20141024@gmail.com>
Rémi Verschelde <rverschelde@gmail.com> <remi@verschelde.fr>
Rhody Lugo <rhodylugo@gmail.com> <rhodylugo@me.com>
Ricardo Subtil <ricasubtil@gmail.com>
Rindbee <idleman@yeah.net>
Riteo Siuga <riteo@posteo.net>
Robin Hübner <profan@prfn.se> <robinhubner@gmail.com>
romulox_x <romulox_x@yahoo.com>
Rudolph Bester <Rudolph.f.Bester@gmail.com> <Rudolph.f.bester@gmail.com>
rune-scape <allie.smith.epic@gmail.com>
rune-scape <allie.smith.epic@gmail.com> <spartacrafter@gmail.com>
Ruslan Mustakov <r.mustakov@gmail.com> <ruslan.mustakov@xored.com>
Saracen <SaracenOne@gmail.com>
sheepandshepherd <sheepandshepherd@hotmail.com> <sheepandshepherd@users.noreply.github.com>
Silc 'Tokage' Renew <tokage.it.lab@gmail.com>
Silc 'Tokage' Renew <tokage.it.lab@gmail.com> <61938263+TokageItLab@users.noreply.github.com>
Swarnim Arun <swarnimarun11@gmail.com>
TechnoPorg <jonah.janzen@gmail.com> <69441745+TechnoPorg@users.noreply.github.com>
tetrapod00 <145553014+tetrapod00@users.noreply.github.com>
Theo Hallenius <redsymbzone@hotmail.com>
Tomasz Chabora <kobewi4e@gmail.com>
Twarit <wtwarit@gmail.com>
Vitika9 <vitika.program@gmail.com>
V.VamsiKrishna <vk@bsb.in> <vamsikrishna.v@gmail.com>
Wilhem Barbier <nounoursheureux@openmailbox.org> <wilhem.b@free.fr>
Wilhem Barbier <nounoursheureux@openmailbox.org> <schtroumps31@gmail.com>
Will Nations <willnationsdev@gmail.com>
yg2f <yoann@terminajones.com>
Yuri Sizov <yuris@humnom.net> <pycbouh@users.noreply.github.com>
Yuri Sizov <yuris@humnom.net> <yaschik4ilicha@gmail.com>
Zae <zaevi@live.com>
Zak Stam <zakscomputers@hotmail.com>
Zher Huei Lee <lee.zh.92@gmail.com>

View file

@ -1,192 +0,0 @@
default_language_version:
python: python3
exclude: |
(?x)^(
.*thirdparty/.*|
.*-so_wrap\.(h|c)|
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
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
rev: v1.3.5
hooks:
- id: clang-tidy
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
args: [--fix, --quiet, --use-color]
types_or: [text]
exclude: ^tests/python_build/.*
additional_dependencies: [clang-tidy==19.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
hooks:
- id: ruff
args: [--fix]
files: (\.py|SConstruct|SCsub)$
types_or: [text]
- id: ruff-format
files: (\.py|SConstruct|SCsub)$
types_or: [text]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1
hooks:
- id: mypy
files: \.py$
types_or: [text]
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies: [tomli]
### Requires Docker; look into alternative implementation.
# - repo: https://github.com/comkieffer/pre-commit-xmllint.git
# rev: 1.0.0
# hooks:
# - id: xmllint
# language: docker
# types_or: [text]
# files: ^(doc/classes|.*/doc_classes)/.*\.xml$
# args: [--schema, doc/class.xsd]
- repo: local
hooks:
- id: make-rst
name: make-rst
language: python
entry: python doc/tools/make_rst.py
args: [doc/classes, modules, platform, --dry-run, --color]
pass_filenames: false
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
- id: doc-status
name: doc-status
language: python
entry: python doc/tools/doc_status.py
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
pass_filenames: false
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
- id: eslint
name: eslint
language: node
entry: eslint
files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
args:
- --fix
- --no-warn-ignored
- --no-config-lookup
- --config
- platform/web/eslint.config.cjs
additional_dependencies:
- "@eslint/js@^9.3.0"
- "@html-eslint/eslint-plugin@^0.24.1"
- "@html-eslint/parser@^0.24.1"
- "@stylistic/eslint-plugin@^2.1.0"
- eslint@^9.3.0
- eslint-plugin-html@^8.1.1
- globals@^15.3.0
- espree@^10.0.1
- id: jsdoc
name: jsdoc
language: node
entry: jsdoc
files: ^platform/web/js/engine/(engine|config|features)\.js$
args:
- --template
- platform/web/js/jsdoc2rst/
- platform/web/js/engine/engine.js
- platform/web/js/engine/config.js
- platform/web/js/engine/features.js
- --destination
- ""
- -d
- dry-run
pass_filenames: false
additional_dependencies: [jsdoc@^4.0.3]
- id: svgo
name: svgo
language: node
entry: svgo
files: \.svg$
args: [--quiet, --config, misc/utility/svgo.config.mjs]
additional_dependencies: [svgo@3.3.2]
- id: copyright-headers
name: copyright-headers
language: python
entry: python misc/scripts/copyright_headers.py
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
exclude: |
(?x)^(
core/math/bvh_.*\.inc|
platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java|
platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java|
platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java
)$
- id: header-guards
name: header-guards
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
language: python
entry: python misc/scripts/file_format.py
types_or: [text]
exclude: |
(?x)^(
.*\.test\.txt|
.*\.svg|
.*\.patch|
.*\.out|
modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd|
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.norun\.gd|
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.norun\.gd|
tests/data/.*\.bin
)$
- id: dotnet-format
name: dotnet-format
language: python
entry: python misc/scripts/dotnet_format.py
types_or: [c#]
#
# End of upstream Godot pre-commit hooks.
#
# Keep this separation to let downstream forks add their own hooks to this file,
# without running into merge conflicts when rebasing on latest upstream.
#
# Start of downstream pre-commit hooks.
#
# This is still the "repo: local" scope, so new local hooks can be defined directly at this indentation:
# - id: new-local-hook
# To add external repo hooks, bring the indentation back to:
# - repo: my-remote-hook

View file

@ -1,359 +0,0 @@
# Godot Engine authors
Godot Engine is developed by a community of voluntary contributors who
contribute code, bug reports, documentation, translations, support, etc.,
across multiple repositories.
It is impossible to list them all; nevertheless, this file aims at listing
the developers who contributed significant improvements to the engine code.
To keep the list curated, we use a threshold of a minimum of 11 commits.
This file does not strictly reflect copyright ownership for the engine
source code. For this, refer to the Git history to know which contributor
wrote which part of the codebase.
GitHub usernames are indicated in parentheses, or as sole entry when no other
name is available.
## Project Founders
Juan Linietsky (reduz)
Ariel Manzur (punto-)
## Lead Developer
Juan Linietsky (reduz)
## Project Manager
Rémi Verschelde (akien-mga)
## Developers
Aaron Franke (aaronfranke)
Aaron Pagano (aaronp64)
Aaron Record (LightningAA)
Adam Scott (adamscott)
Alexander Hartmann (Alex2782)
Alexander Holland (AlexHolly)
Alex Drozd (brno32)
Alexey Khoroshavin (allkhor)
Allen Pestaluky (allenwp)
Alfred Reinold Baudisch (alfredbaudisch)
Alistair Leslie-Hughes (alesliehughes)
Alket Rexhepi (alketii)
Alvin Wong (alvinhochun)
Andrea Catania (AndreaCatania)
Andreia Gaita (shana)
Andrés Botero (0xafbf)
Andrii Doroshenko (Xrayez)
Andy Maloney (asmaloney)
Andy Moss (MillionOstrich)
Angad Kambli (angad-k)
Anilforextra (AnilBK)
Anish Bhobe (KidRigger)
Anish Mishra (syntaxerror247)
Anni Ryynänen (anniryynanen)
Anton Yabchinskiy (a12n)
Anutrix
Aren Villanueva (kurikaesu)
Ariel Manzur (punto-)
arkology
Arman Elgudzhyan (puchik)
Arseny Kapoulkine (zeux)
AThousandShips
aXu-AP
Bartłomiej T. Listwon (Listwon)
Bastiaan Olij (BastiaanOlij)
Ben Brookshire (sheepandshepherd)
Benjamin Larsson (Nallebeorn)
Bernhard Liebl (poke1024)
Bhuvan Vemula (Bhu1-V)
bitsawer
Błażej Szczygieł (zaps166)
BlueCube3310
Bojidar Marinov (bojidar-bg)
Brian Semrau (briansemrau)
Bruno Lourenço (MadEqua)
Cameron Reikes (creikey)
Camille Mohr-Daurat (pouleyKetchoupp)
Caner Demirer (cdemirer)
Carl Olsson (not-surt)
Carter Anderson (cart)
ChibiDenDen
Chris Bradfield (cbscribe)
Chris Cranford (Naros)
Christian Kaiser (ckaiser)
Clay John (clayjohn)
ConteZero
CookieBadger
Dana Olson (adolson)
Daniel J. Ramirez (djrm)
Daniel Rakos (aqnuep)
Daniel Zilberleyb (dzil123)
Danil Alexeev (dalexeev)
dankan1890
Darío Banini (DarioSamo)
David Cambré (Gallilus)
David Sichma (DavidSichma)
David Snopek (dsnopek)
derammo
Dharkael (lupoDharkael)
Dirk Steinmetz (rsjtdrjgfuzkfg)
Dmitry Koteroff (Krakean)
Dmitry Maganov (vonagam)
Dominik Jasiński (dreamsComeTrue)
Douglas Leão (DeeJayLSP)
DualMatrix
Ellen Poe (ellenhp)
Emilio Coppola (coppolaemilio)
Emmanuel Barroga (codecustard)
Emmanuel Leblond (touilleMan)
Eoin O'Neill (Eoin-ONeill-Yokai)
Eric Lasota (elasota)
Eric M (EricEzaM)
Eric Rybicki (ericrybick)
Erik Selecký (rxlecky)
est31
Eveline Jarosz (Marqin)
Fabian Mathews (supagu)
Fabio Alessandrelli (Faless)
Fabrice Cipolla (fabriceci)
Ferenc Arn (tagcup)
FireForge (fire-forge)
Florent Guiocheau (Flarkk)
Florian Kothmeier (Dragoncraft89)
follower
foxydevloper
François Belair (Razoric480)
Franklin Sobrinho (TheHX)
Fredia Huya-Kouadio (m4gr3d)
Geequlim
George Marques (vnen)
Gerrit Großkopf (Grosskopf)
Giganzo
Gilles Roudiere (groud)
Gordon MacPherson (RevoluPowered)
Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
Guillaume Mouton (kiroxas)
Hakim Rouatbi (hakro)
Hanif Bin Ariffin (hbina)
Haoyu Qiu (timothyqiu)
Hein-Pieter van Braam-Stewart (hpvb)
Hendrik Brucker (Geometror)
Hilderin
Hiroshi Ogawa (hi-ogawa)
HolonProduction
homer666
hoontee
Hugo Locurcio (Calinou)
Ian Bishop (ianb96)
Ibrahn Sahir (ibrahn)
Ignacio Roldán Etcheverry (neikeq)
Igor Kordiukiewicz (IgorKordiukiewicz)
Ilaria Cislaghi (QbieShay)
Indah Sylvia (ISylvox)
Ivan Šachov (van800)
J08nY
Jake Young (Duroxxigar)
Jakub Grzesik (kubecz3k)
Jakub Marcowski (Chubercik)
James Buck (jbuck3)
Jan Haller (Bromeon)
Jason Knight (jasonwinterpixel)
Jean-Michel Bernard (jmb462)
Jérôme Gully (Nutriz)
Jia Jun Chai (SkyLucilfer)
jitspoe
Joan Fons Sanchez (JFonS)
Johan Aires Rastén (JohanAR)
Johan Manuel (29jm)
Johannes Witt (HaSa1002)
Jonathan Nicholl (jtnicholl)
Jordan Schidlowsky (winterpixelgames)
Josh Jones (DarkKilauea)
Joshua Grams (JoshuaGrams)
Juan Linietsky (reduz)
Julian Murgia (StraToN)
Julien Nguyen (Blackiris)
Jummit
Justo Delgado (mrcdk)
karroffel
Kassandra Pucher (PucklaJ)
Kelly Thomas (KellyThomas)
kleonc
Kongfa Waroros (gongpha)
Kostadin Damyanov (Max-Might)
K. S. Ernest (iFire) Lee (fire)
Kyle Eichlin (likeich)
Lars Pettersson (larspet)
lawnjelly
Leon Krause (leonkrause)
Liz Haas (27thLiz)
Logan Lang (devloglogan)
Lucien Menassol (Kanabenki)
Lukas Tenbrink (Ivorforce)
Lyuma
Maganty Rushyendra (mrushyendra)
Magian (magian1127)
Mai Lavelle (maiself)
Malcolm Anderson (Meorge)
Malcolm Nixon (Malcolmnixon)
Manuele Finocchiaro (m4nu3lf)
Marcel Admiraal (madmiraal)
Marcelo Fernandez (marcelofg55)
Marc Gilleron (Zylann)
Marcin Zawiejski (dragmz)
Marcus Brummer (mbrlabs)
Marcus Elg (MCrafterzz)
Mariano Javier Suligoy (MarianoGnu)
Mario Liebisch (MarioLiebisch)
Mario Schlack (hurikhan)
Marios Staikopoulos (marstaik)
Marius Hanl (Maran23)
Mark DiBarry (markdibarry)
Mark Riedesel (klowner)
Markus Sauermann (Sauermann)
Martin Capitanio (capnm)
Martin Liška (marxin)
Martin Sjursen (binbitten)
marynate
Masoud BH (masoudbh3)
Mateo Kuruk Miccino (kuruk-mm)
Matias N. Goldberg (darksylinc)
Matthew Murphy (mashumafi)
Matthew (skyace65)
Matthias Hölzl (hoelzl)
Max Hilbrunner (mhilbrunner)
merumelu
Meru Patel (Janglee123)
MewPurPur
Michael Alexsander (YeldhamDev)
Michał Iwańczuk (iwek7)
MichiRecRoom (LikeLakers2)
Micky (Mickeon)
Mikael Hermansson (mihe)
Mika Viskari (miv391)
MinusKube
MJacred
Mounir Tohami (WhalesState)
mrezai
Muhammad Huri (CakHuri)
muiroc
myaaaaaaaaa
Nathalie Galla (MurderVeggie)
Nathan Franke (nathanfranke)
Nathan Lovato (NathanLovato)
Nathan Warden (NathanWarden)
Nazarii Yablonskyi (Nazarwadim)
Nicholas Huelin (SirQuartz)
Nikita Lita (nikitalita)
Nils André-Chang (NilsIrl)
Noah Beard (TwistedTwigleg)
Nông Văn Tình (nongvantinh)
Nuno Donato (nunodonato)
ocean (they/them) (anvilfolk)
Omar El Sheikh (The-O-King)
Ovnuniarchos
Pablo Andres Fuente (pafuent)
Pascal Richter (ShyRed)
passivestar
Patrick Dawson (pkdawson)
Patrick Exner (FlameLizard)
Patrick (firefly2442)
patwork
Paul Batty (Paulb23)
Paul Joannon (paulloz)
Paul Trojahn (ptrojahn)
Pāvels Nadtočajevs (bruvzg)
Paweł Fertyk (pfertyk)
Pawel Kowal (pkowal1982)
Pawel Lampe (Scony)
Pedro J. Estébanez (RandomShaper)
Pieter-Jan Briers (PJB3005)
Poommetee Ketson (Noshyaar)
Przemysław Gołąb (n-pigeon)
Radiant (radiantgurl)
Rafael M. G. (rafallus)
Rafał Mikrut (qarmin)
Raffaele Picca (RPicster)
Ralf Hölzemer (rollenrolm)
Ramesh Ravone (RameshRavone)
Raphael2048
Raul Santos (raulsntos)
Ray Koopa (RayKoopa)
RedMser
RedworkDE
Rémi Verschelde (akien-mga)
Rhody Lugo (rraallvv)
Ricardo Buring (rburing)
Ricardo Subtil (Ev1lbl0w)
Riteo Siuga (Riteo)
Roberto F. Arroyo (robfram)
Robert Yevdokimov (ryevdokimov)
Robin Hübner (profan)
romulox-x
Rudolph Bester (Rudolph-B)
Rune Smith (rune-scape)
Ruslan Mustakov (endragor)
Ryan Roden-Corrent (rrcore)
Saniko (sanikoyes)
santouits
SaracenOne
Septian Ganendra S. K. (sepTN)
Sergey Minakov (naithar)
sersoong
Shiqing (kawa-yoiko)
Silc 'Tokage' Renew (TokageItLab)
Simon Wenner (swenner)
smix8
snailrhymer
Sofox (TheSofox)
Stanislav Labzyuk (DarkMessiah)
Stijn Hinlopen (hinlopen)
stmSi
Stuart Carnie (stuartcarnie)
Swarnim Arun (minraws)
TC (floppyhammer)
TechnoPorg
tetrapod00
Thaddeus Crews (Repiteo)
Thakee Nathees (ThakeeNathees)
thebestnom
Theo Hallenius (TheoXD)
Thomas ten Cate (ttencate)
Timo Schwarzer (timoschwarzer)
Timothé Bonhoure (ajreckof)
Timo (toger5)
Tomasz Chabora (KoBeWi)
Travis Lange (TCROC)
trollodel
Twarit Waikar (IronicallySerious)
Umang Kalra (theoway)
Victor Hampel (havi05)
Vinzenz Feenstra (vinzenz)
Vitika Soni (Vitika9)
박한얼 (volzhs)
V. Vamsi Krishna (vkbsb)
Wilhem Barbier (nounoursheureux)
William Deurwaarder (williamd67)
Will Nations (willnationsdev)
Wilson E. Alvarez (Rubonnek)
Xavier Cho (mysticfall)
Yaohua Xiong (xiongyaohua)
Yevhen Babiichuk (dustdfg)
yg2f (SuperUserNameMan)
Yordan Dolchinkov (Jordyfel)
Yufeng Ying (YYF233333)
Yuri Rubinsky (Chaosus)
Yuri Sizov (YuriSizov)
Zae Chao (zaevi)
Zak Stam (zaksnet)
Zher Huei Lee (leezh)
Zi Ye (MajorMcDoom)
ZuBsPaCe
Дмитрий Сальников (DmitriySalnikov)
忘忧の (Daylily-Zeleen)
谢天 (jsjtxietian)
风青山 (Rindbee)

File diff suppressed because it is too large Load diff

View file

@ -1,213 +0,0 @@
# Contributors guidelines
This document summarizes the most important points for people interested in
contributing to Godot, especially via bug reports or pull requests.
The Godot documentation has a dedicated [Contributing section](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
which details these points and more, and is a recommended read.
## Table of contents
- [Reporting bugs](#reporting-bugs)
- [Proposing features or improvements](#proposing-features-or-improvements)
- [Contributing pull requests](#contributing-pull-requests)
- [Contributing to Godot translations](#contributing-to-godot-translations)
- [Communicating with developers](#communicating-with-developers)
## Reporting bugs
Report bugs [here](https://github.com/godotengine/godot/issues/new?assignees=&labels=&template=bug_report.yml).
Please follow the instructions in the template when you do.
Notably, please include a Minimal Reproduction Project (MRP), which is a small
Godot project which reproduces the issue, with no unnecessary files included.
Be sure to not include the `.godot` folder in the archive to save space.
Make sure that the bug you are experiencing is reproducible in the latest Godot
releases. You can find an overview of all Godot releases [on the website](https://godotengine.org/download/archive/)
to confirm whether your current version is the latest one. It's worth testing
against both the latest stable release and the latest dev snapshot for the next
Godot release.
If you run into a bug which wasn't present in an earlier Godot version (what we
call a _regression_), please mention it and clarify which versions you tested
(both the one(s) working and the one(s) exhibiting the bug).
## Proposing features or improvements
**The main issue tracker is for bug reports and does not accept feature proposals.**
Instead, head to the [Godot Proposals repository](https://github.com/godotengine/godot-proposals)
and follow the instructions in the README file and issue template.
## Contributing pull requests
If you want to add new engine features, please make sure that:
- This functionality is desired, which means that it solves a common use case
that several users will need in their real-life projects.
- You talked to other developers on how to implement it best. See also
[Proposing features or improvements](#proposing-features-or-improvements).
- Even if it doesn't get merged, your PR is useful for future work by another
developer.
Similar rules can be applied when contributing bug fixes - it's always best to
discuss the implementation in the bug report first if you are not 100% about
what would be the best fix.
You can refer to the [Pull request review process](https://docs.godotengine.org/en/latest/contributing/workflow/pr_review_guidelines.html)
for insights into the intended lifecycle of pull requests. This should help you
ensure that your pull request fulfills the requirements.
In addition to the following tips, also take a look at the
[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html)
for an introduction to developing on Godot.
The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
(with a helpful guide for Git usage), and our [Code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html)
which all contributions need to follow.
### Be mindful of your commits
Try to make simple PRs that handle one specific topic. Just like for reporting
issues, it's better to open 3 different PRs that each address a different issue
than one big PR with three commits. This makes it easier to review, approve, and
merge the changes independently.
When updating your fork with upstream changes, please use ``git pull --rebase``
to avoid creating "merge commits". Those commits unnecessarily pollute the git
history when coming from PRs.
Also try to make commits that bring the engine from one stable state to another
stable state, i.e. if your first commit has a bug that you fixed in the second
commit, try to merge them together before making your pull request. This
includes fixing build issues or typos, adding documentation, etc.
See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
documentation for tips on using Git, amending commits and rebasing branches.
This [Git style guide](https://github.com/agis-/git-style-guide) also has some
good practices to have in mind.
### Format your commit messages with readability in mind
The way you format your commit messages is quite important to ensure that the
commit history and changelog will be easy to read and understand. A Git commit
message is formatted as a short title (first line) and an extended description
(everything after the first line and an empty separation line).
The short title is the most important part, as it is what will appear in the
changelog or in the GitHub interface unless you click the "expand" button.
Try to keep that first line under 72 characters, but you can go slightly above
if necessary to keep the sentence clear.
It should be written in English, starting with a capital letter, and usually
with a verb in imperative form. A typical bugfix would start with "Fix", while
the addition of a new feature would start with "Add". A prefix can be added to
specify the engine area affected by the commit. Some examples:
- Add C# iOS support
- Show doc tooltips when hovering properties in the theme editor
- Fix GLES3 instanced rendering color and custom data defaults
- Core: Fix `Object::has_method()` for script static methods
If your commit fixes a reported issue, please include it in the _description_
of the PR (not in the title, or the commit message) using one of the
[GitHub closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
such as "Fixes #1234". This will cause the issue to be closed automatically if
the PR is merged. Adding it to the commit message is easier, but adds a lot of
unnecessary updates in the issue distracting from the thread.
Here's an example of a well-formatted commit message (note how the extended
description is also manually wrapped at 80 chars for readability):
```text
Prevent French fries carbonization by fixing heat regulation
When using the French fries frying module, Godot would not regulate the heat
and thus bring the oil bath to supercritical liquid conditions, thus causing
unwanted side effects in the physics engine.
By fixing the regulation system via an added binding to the internal feature,
this commit now ensures that Godot will not go past the ebullition temperature
of cooking oil under normal atmospheric conditions.
```
**Note:** When using the GitHub online editor or its drag-and-drop
feature, *please* edit the commit title to something meaningful. Commits named
"Update my_file.cpp" won't be accepted.
### Document your changes
If your pull request adds methods, properties or signals that are exposed to
scripting APIs, you **must** update the class reference to document those.
This is to ensure the documentation coverage doesn't decrease as contributions
are merged.
[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html)
using your compiled binary, then fill in the descriptions.
Follow the style guide described in the
[Documentation writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html).
If your pull request modifies parts of the code in a non-obvious way, make sure
to add comments in the code as well. This helps other people understand the
change without having to dive into the Git history.
### Write unit tests
When fixing a bug or contributing a new feature, we recommend including unit
tests in the same commit as the rest of the pull request. Unit tests are pieces
of code that compare the output to a predetermined *expected result* to detect
regressions. Tests are compiled and run on GitHub Actions for every commit and
pull request.
Pull requests that include tests are more likely to be merged, since we can have
greater confidence in them not being the target of regressions in the future.
For bugs, the unit tests should cover the functionality that was previously
broken. If done well, this ensures regressions won't appear in the future
again. For new features, the unit tests should cover the newly added
functionality, testing both the "success" and "expected failure" cases if
applicable.
Feel free to contribute standalone pull requests to add new tests or improve
existing tests as well.
See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html)
for information on writing tests in Godot's C++ codebase.
## Contributing to Godot translations
You can contribute to Godot translations on [Hosted Weblate](https://hosted.weblate.org/projects/godot-engine/),
an open source and web-based translation platform.
Please refer to our [editor and documentation localization guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/editor_and_docs_localization.html)
for an overview of the translation resources and what they correspond to.
## Communicating with developers
The Godot Engine community has [many communication
channels](https://godotengine.org/community), some used more for user-level
discussions and support, others more for development discussions.
To communicate with developers (e.g. to discuss a feature you want to implement
or a bug you want to fix), the following channels can be used:
- [Godot Contributors Chat](https://chat.godotengine.org): You will
find most core developers there, so it's the go-to platform for direct chat
about Godot Engine development. Browse the [Directory](https://chat.godotengine.org/directory/channels)
for an overview of public channels focusing on various engine areas which you
might be interested in.
- [Bug tracker](https://github.com/godotengine/godot/issues): If there is an
existing issue about a topic you want to discuss, you can participate directly.
If not, you can open a new issue. Please mind the guidelines outlined above
for bug reporting.
- [Feature proposals](https://github.com/godotengine/godot-proposals/issues):
To propose a new feature, we have a dedicated issue tracker for that. Don't
hesitate to start by talking about your idea on the Godot Contributors Chat
to make sure that it makes sense in Godot's context.
Thanks for your interest in contributing!
—The Godot development team

File diff suppressed because it is too large Load diff

View file

@ -1,293 +0,0 @@
# Donors to the Godot Engine project
Godot Engine is a non-profit project developed by a community of voluntary
contributors, as well as occasional paid contributors thanks to the financial
support of generous donors.
The ways to donate to the project, as well as details on how the funds are
used, are described on [Godot's website](https://godotengine.org/donate).
The following is a list of the current monthly donors, who will have their
generous deed immortalized in the next stable release of Godot Engine.
## Patrons
Khronos® Group <https://www.khronos.org/>
OSS Capital <https://oss.capital/>
## Platinum sponsors
Scorewarrior <https://scwr.gg/godot>
V-Sekai <https://github.com/V-Sekai>
W4 Games <https://w4games.com/>
## Gold sponsors
Mega Crit <https://www.megacrit.com/>
Prehensile Tales <https://prehensile-tales.com>
Robot Gentleman <http://robotgentleman.com/>
## Silver sponsors
Bippinbits <https://bippinbits.com/>
Broken Rules <https://brokenrul.es>
Chasing Carrots <https://www.chasing-carrots.com>
Copia Wealth Studios <https://copiawealthstudios.com/>
LoadComplete <https://loadcomplete.com/>
Null <https://null.com/>
Orbital Knight <https://www.orbitalknight.com/>
Playful Studios <https://playfulstudios.com/>
Re-Logic <https://re-logic.com/>
## Diamond members
ASIFA-Hollywood <https://www.asifa-hollywood.org/>
Christina Coffin <https://bsky.app/profile/christinacoffin.bsky.social>
Dominic Harris <https://wayfarer-games.com/>
Kiri "ExpiredPopsicle" Artemis <https://expiredpopsicle.com/>
Petr Kharitonov <https://petrkharitonov.com/>
Seats.aero <https://seats.aero/>
Sylv <https://rankith.itch.io/unnamed-space-idle-prototype>
And 5 anonymous donors
## Titanium members
Adriaan de Jongh <https://adriaan.games>
Basically Games
Draknek & Friends <https://www.draknek.org/>
Garry Newman
Gigabrain AI Reddit Search Engine <https://thegigabrain.com/?utm_source=godot>
Jettelly <https://jettelly.com/>
Justo Delgado Baudí <https://portfolio.mrcdk.com/>
Kenney <https://kenney.nl/>
Lucid Silence Games
Matthew Hall <https://crossyroad.com/>
PolyMars <https://polymars.dev/>
Purple Moss Collectors <https://purplemosscollectors.com/>
RPG in a Box <https://www.rpginabox.com>
Starkandco <https://github.com/Starkandco>
Studio Sunshower <https://www.studiosunshower.com/>
TrampolineTales <https://TrampolineTales.com/>
粟二华 (Su Erhua)
And 4 anonymous donors
## Platinum members
Andy Touch
BlockImperiumGames (BIG)
Bytten Studio
Christopher Shifflett
Cody Bentley
Darrin Massena
Fabio Alessandrelli
HP van Braam
iCommitGames
Jason Hamilton
Jonah Stich
Josh Anthony
Ludvig Temperli Risan
Matthew Ekenstedt
Memories in 8Bit
Michael Martin
Mike King
Neal Gompa (Conan Kudo)
Nico Ulriksen
Nikita Blizniuk
Raptor85
Rémi Verschelde
Ronnie Cheng
Ryan Heath
ShikadiGum
Silver Creek Entertainment
Stephan Kessler
Stephen Rice
And 14 anonymous donors
## Gold members
2 Nerdy Nerds
73unny
80px
Abigail F.
Admiral Potato
afreytes
AinaVT
Ajat BlackSun
Alex177Alex
alMoo Games
Alva Majo
Andrew Eiche
Antti Vesanen
Arediss
Asher Glick
Axthelm
BangTheWall
Benito
Benjamin Bridges
Ben Rog-Wilhelm
BetaTester704
Brut
Bryce Dixon
Carlo Cabanilla
Carlo del Mundo
Carl van der Geest
Chocolate Software
Chris Backas
Chris Lambson
Christine Elisabeth Koppel
Cindy Trieu
ClarkThyLord
Codex404
cora
Daniel Eichler
Daniel Krafft
Datzju
David Chen Zhen
David Coles
David Hubber
David Snopek
Deakcor
Delton Ding
dgehrig
Disco Cat
Distorted Realities
DitherDream
Dominik Frizel
Don't You Know Who I Am? Inc.
Dustuu
Dylan Dromard
Edelweiss
eelSkillz
Emily Flion
Ends
Eren Ogrul
Eric Brand
Eric Phy
Faisal Al-Kubaisi (QatariGameDev)
Fanny Pack Studios
Felix Adam
FeralBytes
Francisco Aliaga
Francis Jasmin
Frozen Fractal
Gaudipern
GetIntoGameDev
GlassBrick
Grau
Grzegorz Wereszko
Guangzhou Lingchan
Guilherme Cattani
Hayden Oliver
hiulit
https://domi.zip
Huedeane
Ikuti
Illyan
I.M.I.Self
Immaculate Lift Studio
Intrepid Marmot LLC
Isaac Marovitz
Ivan Tabashki
jakemiki
Jam
Jason Cawood
Jeff Hungerford
Jesús Chicharro
Johannes Wuensch
John Gabriel
Jonas Yamazaki
Jonathan
José Canepa
Julian Todd
Justin Laster
Justin Sasso
Kalydi Balázs
KAR Games
Kiryonn
kodebold
KOGA Mitsuhiro (@shiena)
korinVR
Kristian Kriehl
KyletheDab
Lars Thießen
Lisandro Lorea (Red Mage Games)
Logan Apple
Luca Junge
LyaaaaaGames
m1n1ster
Madison Nicole Videogames
Mara Huldra
Marek Belski
Martin Šenkeřík
Matthias B.
Michael Alexsander
Michael Gooch
Michael Harrington
Modus Ponens
Moshe Harris
Moth Soup
Mr. Byte
Muscarian Softworks
Nassor Paulino da Silva
Neuroticfly Games
nezticle
nikkehtine
Niklas Wahrman
Nitzan Bueno
NotNet
Oathbringer
Officine Pixel
ohanaya3
Okatima AB
Oscar Robin
ovym
Patrick Traynor
Péter Horváth-Lázár
Petr Maláč
pirey
protogames
Rafa Laguna
Reid Hannaford
@reilaos
Request
re:thinc
Richard Ivánek
Robin Ward
Ronny Mühle
Rubén Rüger
Samuel Judd
Santi_FC
Seref Karahan
shazzner
Shiny Shinken
Silverclad Studios
Skie Radscale
Snow Diamond
Sofox
Space Kraken Studios
Spoony Panda
tenuki
ThatGamer
Thomas Lobig
Tobias Bocanegra
Tom Langwaldt
Trevor Slocum
tukon
twitch.tv/RobitussinMD
Tyler C
Urban Protagonist
Vincent Foulon
Vojtech Lacina
Voxel Floof
Watchinofoye
Yannick
zikes
Zoey Smith
嗯大爷
And 143 anonymous donors
## Silver and bronze donors
There are even more donors that support the project with a small monthly donation.
Every bit counts and we thank every one of them for their amazing support!

View file

@ -1,20 +0,0 @@
Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md).
Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,5 +0,0 @@
Godot Engine Logo
Copyright (c) 2017 Andrea Calabró
This work is licensed under the Creative Commons Attribution 4.0 International
license (CC BY 4.0 International): https://creativecommons.org/licenses/by/4.0/

View file

@ -1,78 +0,0 @@
# Godot Engine
<p align="center">
<a href="https://godotengine.org">
<img src="logo_outlined.svg" width="400" alt="Godot Engine logo">
</a>
</p>
## 2D and 3D cross-platform game engine
**[Godot Engine](https://godotengine.org) is a feature-packed, cross-platform
game engine to create 2D and 3D games from a unified interface.** It provides a
comprehensive set of [common tools](https://godotengine.org/features), so that
users can focus on making games without having to reinvent the wheel. Games can
be exported with one click to a number of platforms, including the major desktop
platforms (Linux, macOS, Windows), mobile platforms (Android, iOS), as well as
Web-based platforms and [consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html).
## Free, open source and community-driven
Godot is completely free and open source under the very permissive [MIT license](https://godotengine.org/license).
No strings attached, no royalties, nothing. The users' games are theirs, down
to the last line of engine code. Godot's development is fully independent and
community-driven, empowering users to help shape their engine to match their
expectations. It is supported by the [Godot Foundation](https://godot.foundation/)
not-for-profit.
Before being open sourced in [February 2014](https://github.com/godotengine/godot/commit/0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac),
Godot had been developed by [Juan Linietsky](https://github.com/reduz) and
[Ariel Manzur](https://github.com/punto-) (both still maintaining the project)
for several years as an in-house engine, used to publish several work-for-hire
titles.
![Screenshot of a 3D scene in the Godot Engine editor](https://raw.githubusercontent.com/godotengine/godot-design/master/screenshots/editor_tps_demo_1920x1080.jpg)
## Getting the engine
### Binary downloads
Official binaries for the Godot editor and the export templates can be found
[on the Godot website](https://godotengine.org/download).
### Compiling from source
[See the official docs](https://docs.godotengine.org/en/latest/contributing/development/compiling)
for compilation instructions for every supported platform.
## Community and contributing
Godot is not only an engine but an ever-growing community of users and engine
developers. The main community channels are listed [on the homepage](https://godotengine.org/community).
The best way to get in touch with the core engine developers is to join the
[Godot Contributors Chat](https://chat.godotengine.org).
To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md).
This document also includes guidelines for reporting bugs.
## Documentation and demos
The official documentation is hosted on [Read the Docs](https://docs.godotengine.org).
It is maintained by the Godot community in its own [GitHub repository](https://github.com/godotengine/godot-docs).
The [class reference](https://docs.godotengine.org/en/latest/classes/)
is also accessible from the Godot editor.
We also maintain official demos in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
as well as a list of [awesome Godot community resources](https://github.com/godotengine/awesome-godot).
There are also a number of other
[learning resources](https://docs.godotengine.org/en/latest/community/tutorials.html)
provided by the community, such as text and video tutorials, demos, etc.
Consult the [community channels](https://godotengine.org/community)
for more information.
[![Code Triagers Badge](https://www.codetriage.com/godotengine/godot/badges/users.svg)](https://www.codetriage.com/godotengine/godot)
[![Translate on Weblate](https://hosted.weblate.org/widgets/godot-engine/-/godot/svg-badge.svg)](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/godotengine/godot)](https://www.tickgit.com/browse?repo=github.com/godotengine/godot)

File diff suppressed because it is too large Load diff

View file

@ -1,301 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
import os
import core_builders
import methods
env.core_sources = []
# Add required thirdparty code.
thirdparty_obj = []
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
# Misc thirdparty code: header paths are hardcoded, we don't need to append
# to the include path (saves a few chars on the compiler invocation for touchy MSVC...)
thirdparty_misc_dir = "#thirdparty/misc/"
thirdparty_misc_sources = [
# C sources
"fastlz.c",
"r128.c",
"smaz.c",
# C++ sources
"pcg.cpp",
"polypartition.cpp",
"smolv.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
# Brotli
if env["brotli"] and env["builtin_brotli"]:
thirdparty_brotli_dir = "#thirdparty/brotli/"
thirdparty_brotli_sources = [
"common/constants.c",
"common/context.c",
"common/dictionary.c",
"common/platform.c",
"common/shared_dictionary.c",
"common/transform.c",
"dec/bit_reader.c",
"dec/decode.c",
"dec/huffman.c",
"dec/state.c",
]
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"])
if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_brotli_sources)
# Clipper2 Thirdparty source files used for polygon and polyline boolean operations.
if env["builtin_clipper2"]:
thirdparty_clipper_dir = "#thirdparty/clipper2/"
thirdparty_clipper_sources = [
"src/clipper.engine.cpp",
"src/clipper.offset.cpp",
"src/clipper.rectclip.cpp",
]
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.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_clipper_sources)
# Zlib library, can be unbundled
if env["builtin_zlib"]:
thirdparty_zlib_dir = "#thirdparty/zlib/"
thirdparty_zlib_sources = [
"adler32.c",
"compress.c",
"crc32.c",
"deflate.c",
"inffast.c",
"inflate.c",
"inftrees.c",
"trees.c",
"uncompr.c",
"zutil.c",
]
thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too
env.Prepend(CPPPATH=[thirdparty_zlib_dir])
if env.dev_build:
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
# Affects headers so it should also be defined for Godot code
env.Append(CPPDEFINES=["ZLIB_DEBUG"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
# Minizip library, could be unbundled in theory
# However, our version has some custom modifications, so it won't compile with the system one
thirdparty_minizip_dir = "#thirdparty/minizip/"
thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_minizip_sources)
# Zstd library, can be unbundled in theory
# though we currently use some private symbols
# https://github.com/godotengine/godot/issues/17374
if env["builtin_zstd"]:
thirdparty_zstd_dir = "#thirdparty/zstd/"
thirdparty_zstd_sources = [
"common/debug.c",
"common/entropy_common.c",
"common/error_private.c",
"common/fse_decompress.c",
"common/pool.c",
"common/threading.c",
"common/xxhash.c",
"common/zstd_common.c",
"compress/fse_compress.c",
"compress/hist.c",
"compress/huf_compress.c",
"compress/zstd_compress.c",
"compress/zstd_double_fast.c",
"compress/zstd_fast.c",
"compress/zstd_lazy.c",
"compress/zstd_ldm.c",
"compress/zstd_opt.c",
"compress/zstdmt_compress.c",
"compress/zstd_compress_literals.c",
"compress/zstd_compress_sequences.c",
"compress/zstd_compress_superblock.c",
"decompress/huf_decompress.c",
"decompress/zstd_ddict.c",
"decompress/zstd_decompress_block.c",
"decompress/zstd_decompress.c",
]
if env["platform"] in ["android", "ios", "linuxbsd", "macos"] and env["arch"] == "x86_64":
# Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
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.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
env.Prepend(CPPPATH=thirdparty_zstd_dir)
# Also needed in main env includes will trigger warnings
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zstd_sources)
env.core_sources += thirdparty_obj
# Godot source files
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:
for c in source[0].read():
cs = c.strip()
if cs != "":
file.write(f"#define ClassDB_Disable_{cs} 1\n")
env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
# Generate version info
def version_info_builder(target, source, env):
with methods.generated_wrapper(target) 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)
)
env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder))
# Generate version hash
def version_hash_builder(target, source, env):
with methods.generated_wrapper(target) 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)
)
gen_hash = env.CommandNoCache(
"version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
)
env.add_source_files(env.core_sources, gen_hash)
# Generate AES256 script encryption key
def encryption_key_builder(target, source, env):
with methods.generated_wrapper(target) as file:
file.write(
f"""\
#include "core/config/project_settings.h"
uint8_t script_encryption_key[32] = {{
{source[0]}
}};"""
)
gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
ec_valid = len(gdkey) == 64
if ec_valid:
try:
gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
except Exception:
ec_valid = False
if not ec_valid:
methods.print_error(
f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
"Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
"or make sure that it contains exactly 64 hexadecimal characters."
)
Exit(255)
gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
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",
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))
# Donors
env.Depends("#core/donors.gen.h", "../DONORS.md")
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),
)
# Chain load SCsubs
SConscript("os/SCsub")
SConscript("math/SCsub")
SConscript("crypto/SCsub")
SConscript("io/SCsub")
SConscript("debugger/SCsub")
SConscript("input/SCsub")
SConscript("variant/SCsub")
SConscript("extension/SCsub")
SConscript("object/SCsub")
SConscript("templates/SCsub")
SConscript("string/SCsub")
SConscript("config/SCsub")
SConscript("error/SCsub")
# Build it all as a library
lib = env.add_library("core", env.core_sources)
env.Prepend(LIBS=[lib])
# Needed to force rebuilding the core files when the thirdparty code is updated.
env.Depends(lib, thirdparty_obj)

View file

@ -1,8 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env_config = env.Clone()
env_config.add_source_files(env.core_sources, "*.cpp")

View file

@ -1,446 +0,0 @@
/**************************************************************************/
/* engine.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "engine.h"
#include "core/authors.gen.h"
#include "core/config/project_settings.h"
#include "core/donors.gen.h"
#include "core/license.gen.h"
#include "core/variant/typed_array.h"
#include "core/version.h"
#include "servers/rendering/rendering_device.h"
void Engine::set_physics_ticks_per_second(int p_ips) {
ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
ips = p_ips;
}
int Engine::get_physics_ticks_per_second() const {
return ips;
}
void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
max_physics_steps_per_frame = p_max_physics_steps;
}
int Engine::get_max_physics_steps_per_frame() const {
return max_physics_steps_per_frame;
}
void Engine::set_physics_jitter_fix(double p_threshold) {
if (p_threshold < 0) {
p_threshold = 0;
}
physics_jitter_fix = p_threshold;
}
double Engine::get_physics_jitter_fix() const {
return physics_jitter_fix;
}
void Engine::set_max_fps(int p_fps) {
_max_fps = p_fps > 0 ? p_fps : 0;
RenderingDevice *rd = RenderingDevice::get_singleton();
if (rd) {
rd->_set_max_fps(_max_fps);
}
}
int Engine::get_max_fps() const {
return _max_fps;
}
void Engine::set_audio_output_latency(int p_msec) {
_audio_output_latency = p_msec > 1 ? p_msec : 1;
}
int Engine::get_audio_output_latency() const {
return _audio_output_latency;
}
void Engine::increment_frames_drawn() {
if (frame_server_synced) {
server_syncs++;
} else {
server_syncs = 0;
}
frame_server_synced = false;
frames_drawn++;
}
uint64_t Engine::get_frames_drawn() {
return frames_drawn;
}
void Engine::set_frame_delay(uint32_t p_msec) {
_frame_delay = p_msec;
}
uint32_t Engine::get_frame_delay() const {
return _frame_delay;
}
void Engine::set_time_scale(double p_scale) {
_time_scale = p_scale;
}
double Engine::get_time_scale() const {
return freeze_time_scale ? 0 : _time_scale;
}
double Engine::get_unfrozen_time_scale() const {
return _time_scale;
}
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;
String hash = String(VERSION_HASH);
dict["hash"] = hash.is_empty() ? String("unknown") : hash;
dict["timestamp"] = VERSION_TIMESTAMP;
String stringver = String(dict["major"]) + "." + String(dict["minor"]);
if ((int)dict["patch"] != 0) {
stringver += "." + String(dict["patch"]);
}
stringver += "-" + String(dict["status"]) + " (" + String(dict["build"]) + ")";
dict["string"] = stringver;
return dict;
}
static Array array_from_info(const char *const *info_list) {
Array arr;
for (int i = 0; info_list[i] != nullptr; i++) {
arr.push_back(String::utf8(info_list[i]));
}
return arr;
}
static Array array_from_info_count(const char *const *info_list, int info_count) {
Array arr;
for (int i = 0; i < info_count; i++) {
arr.push_back(String::utf8(info_list[i]));
}
return arr;
}
Dictionary Engine::get_author_info() const {
Dictionary dict;
dict["lead_developers"] = array_from_info(AUTHORS_LEAD_DEVELOPERS);
dict["project_managers"] = array_from_info(AUTHORS_PROJECT_MANAGERS);
dict["founders"] = array_from_info(AUTHORS_FOUNDERS);
dict["developers"] = array_from_info(AUTHORS_DEVELOPERS);
return dict;
}
TypedArray<Dictionary> Engine::get_copyright_info() const {
TypedArray<Dictionary> components;
for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
Dictionary component_dict;
component_dict["name"] = String::utf8(cp_info.name);
Array parts;
for (int i = 0; i < cp_info.part_count; i++) {
const ComponentCopyrightPart &cp_part = cp_info.parts[i];
Dictionary part_dict;
part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count);
part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count);
part_dict["license"] = String::utf8(cp_part.license);
parts.push_back(part_dict);
}
component_dict["parts"] = parts;
components.push_back(component_dict);
}
return components;
}
Dictionary Engine::get_donor_info() const {
Dictionary donors;
donors["patrons"] = array_from_info(DONORS_PATRONS);
donors["platinum_sponsors"] = array_from_info(DONORS_SPONSORS_PLATINUM);
donors["gold_sponsors"] = array_from_info(DONORS_SPONSORS_GOLD);
donors["silver_sponsors"] = array_from_info(DONORS_SPONSORS_SILVER);
donors["diamond_members"] = array_from_info(DONORS_MEMBERS_DIAMOND);
donors["titanium_members"] = array_from_info(DONORS_MEMBERS_TITANIUM);
donors["platinum_members"] = array_from_info(DONORS_MEMBERS_PLATINUM);
donors["gold_members"] = array_from_info(DONORS_MEMBERS_GOLD);
return donors;
}
Dictionary Engine::get_license_info() const {
Dictionary licenses;
for (int i = 0; i < LICENSE_COUNT; i++) {
licenses[LICENSE_NAMES[i]] = LICENSE_BODIES[i];
}
return licenses;
}
String Engine::get_license_text() const {
return String(GODOT_LICENSE_TEXT);
}
String Engine::get_architecture_name() const {
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
return "x86_64";
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
return "x86_32";
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
return "arm64";
#elif defined(__arm__) || defined(_M_ARM)
return "arm32";
#elif defined(__riscv)
#if __riscv_xlen == 8
return "rv64";
#else
return "riscv";
#endif
#elif defined(__powerpc__)
#if defined(__powerpc64__)
return "ppc64";
#else
return "ppc";
#endif
#elif defined(__loongarch64)
return "loongarch64";
#elif defined(__wasm__)
#if defined(__wasm64__)
return "wasm64";
#elif defined(__wasm32__)
return "wasm32";
#endif
#endif
}
bool Engine::is_abort_on_gpu_errors_enabled() const {
return abort_on_gpu_errors;
}
int32_t Engine::get_gpu_index() const {
return gpu_idx;
}
bool Engine::is_validation_layers_enabled() const {
return use_validation_layers;
}
bool Engine::is_generate_spirv_debug_info_enabled() const {
return generate_spirv_debug_info;
}
bool Engine::is_extra_gpu_memory_tracking_enabled() const {
return extra_gpu_memory_tracking;
}
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
bool Engine::is_accurate_breadcrumbs_enabled() const {
return accurate_breadcrumbs;
}
#endif
void Engine::set_print_to_stdout(bool p_enabled) {
CoreGlobals::print_line_enabled = p_enabled;
}
bool Engine::is_printing_to_stdout() const {
return CoreGlobals::print_line_enabled;
}
void Engine::set_print_error_messages(bool p_enabled) {
CoreGlobals::print_error_enabled = p_enabled;
}
bool Engine::is_printing_error_messages() const {
return CoreGlobals::print_error_enabled;
}
void Engine::print_header(const String &p_string) const {
if (_print_header) {
print_line(p_string);
}
}
void Engine::print_header_rich(const String &p_string) const {
if (_print_header) {
print_line_rich(p_string);
}
}
void Engine::add_singleton(const Singleton &p_singleton) {
ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
singletons.push_back(p_singleton);
singleton_ptrs[p_singleton.name] = p_singleton.ptr;
}
Object *Engine::get_singleton_object(const StringName &p_name) const {
HashMap<StringName, Object *>::ConstIterator E = singleton_ptrs.find(p_name);
ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("Failed to retrieve non-existent singleton '%s'.", p_name));
#ifdef TOOLS_ENABLED
if (!is_editor_hint() && is_singleton_editor_only(p_name)) {
ERR_FAIL_V_MSG(nullptr, vformat("Can't retrieve singleton '%s' outside of editor.", p_name));
}
#endif
return E->value;
}
bool Engine::is_singleton_user_created(const StringName &p_name) const {
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
for (const Singleton &E : singletons) {
if (E.name == p_name && E.user_created) {
return true;
}
}
return false;
}
bool Engine::is_singleton_editor_only(const StringName &p_name) const {
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
for (const Singleton &E : singletons) {
if (E.name == p_name && E.editor_only) {
return true;
}
}
return false;
}
void Engine::remove_singleton(const StringName &p_name) {
ERR_FAIL_COND(!singleton_ptrs.has(p_name));
for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) {
if (E->get().name == p_name) {
singletons.erase(E);
singleton_ptrs.erase(p_name);
return;
}
}
}
bool Engine::has_singleton(const StringName &p_name) const {
return singleton_ptrs.has(p_name);
}
void Engine::get_singletons(List<Singleton> *p_singletons) {
for (const Singleton &E : singletons) {
#ifdef TOOLS_ENABLED
if (!is_editor_hint() && E.editor_only) {
continue;
}
#endif
p_singletons->push_back(E);
}
}
String Engine::get_write_movie_path() const {
return write_movie_path;
}
void Engine::set_write_movie_path(const String &p_path) {
write_movie_path = p_path;
}
void Engine::set_shader_cache_path(const String &p_path) {
shader_cache_path = p_path;
}
String Engine::get_shader_cache_path() const {
return shader_cache_path;
}
Engine *Engine::singleton = nullptr;
Engine *Engine::get_singleton() {
return singleton;
}
bool Engine::notify_frame_server_synced() {
frame_server_synced = true;
return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
}
void Engine::set_freeze_time_scale(bool p_frozen) {
freeze_time_scale = p_frozen;
}
void Engine::set_embedded_in_editor(bool p_enabled) {
embedded_in_editor = p_enabled;
}
bool Engine::is_embedded_in_editor() const {
return embedded_in_editor;
}
Engine::Engine() {
singleton = this;
}
Engine::~Engine() {
if (singleton == this) {
singleton = nullptr;
}
}
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
name(p_name),
ptr(p_ptr),
class_name(p_class_name) {
#ifdef DEBUG_ENABLED
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
if (rc && !rc->is_referenced()) {
WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
}
#endif
}

View file

@ -1,218 +0,0 @@
/**************************************************************************/
/* engine.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_H
#define ENGINE_H
#include "core/os/main_loop.h"
#include "core/string/ustring.h"
#include "core/templates/list.h"
template <typename T>
class TypedArray;
class Engine {
public:
struct Singleton {
StringName name;
Object *ptr = nullptr;
StringName class_name; // Used for binding generation hinting.
// Singleton scope flags.
bool user_created = false;
bool editor_only = false;
Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName());
};
private:
friend class Main;
uint64_t frames_drawn = 0;
uint32_t _frame_delay = 0;
uint64_t _frame_ticks = 0;
double _process_step = 0;
int ips = 60;
double physics_jitter_fix = 0.5;
double _fps = 1;
int _max_fps = 0;
int _audio_output_latency = 0;
double _time_scale = 1.0;
uint64_t _physics_frames = 0;
int max_physics_steps_per_frame = 8;
double _physics_interpolation_fraction = 0.0f;
bool abort_on_gpu_errors = false;
bool use_validation_layers = false;
bool generate_spirv_debug_info = false;
bool extra_gpu_memory_tracking = false;
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
bool accurate_breadcrumbs = false;
#endif
int32_t gpu_idx = -1;
uint64_t _process_frames = 0;
bool _in_physics = false;
List<Singleton> singletons;
HashMap<StringName, Object *> singleton_ptrs;
bool editor_hint = false;
bool project_manager_hint = false;
bool extension_reloading = false;
bool embedded_in_editor = false;
bool recovery_mode_hint = false;
bool _print_header = true;
static Engine *singleton;
String write_movie_path;
String shader_cache_path;
static constexpr int SERVER_SYNC_FRAME_COUNT_WARNING = 5;
int server_syncs = 0;
bool frame_server_synced = false;
bool freeze_time_scale = false;
public:
static Engine *get_singleton();
virtual void set_physics_ticks_per_second(int p_ips);
virtual int get_physics_ticks_per_second() const;
virtual void set_max_physics_steps_per_frame(int p_max_physics_steps);
virtual int get_max_physics_steps_per_frame() const;
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
virtual void set_max_fps(int p_fps);
virtual int get_max_fps() const;
virtual void set_audio_output_latency(int p_msec);
virtual int get_audio_output_latency() const;
virtual double get_frames_per_second() const { return _fps; }
uint64_t get_frames_drawn();
uint64_t get_physics_frames() const { return _physics_frames; }
uint64_t get_process_frames() const { return _process_frames; }
bool is_in_physics_frame() const { return _in_physics; }
uint64_t get_frame_ticks() const { return _frame_ticks; }
double get_process_step() const { return _process_step; }
double get_physics_interpolation_fraction() const { return _physics_interpolation_fraction; }
void set_time_scale(double p_scale);
double get_time_scale() const;
double get_unfrozen_time_scale() const;
void set_print_to_stdout(bool p_enabled);
bool is_printing_to_stdout() const;
void set_print_error_messages(bool p_enabled);
bool is_printing_error_messages() const;
void print_header(const String &p_string) const;
void print_header_rich(const String &p_string) const;
void set_frame_delay(uint32_t p_msec);
uint32_t get_frame_delay() const;
void add_singleton(const Singleton &p_singleton);
void get_singletons(List<Singleton> *p_singletons);
bool has_singleton(const StringName &p_name) const;
Object *get_singleton_object(const StringName &p_name) const;
void remove_singleton(const StringName &p_name);
bool is_singleton_user_created(const StringName &p_name) const;
bool is_singleton_editor_only(const StringName &p_name) const;
#ifdef TOOLS_ENABLED
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; }
_FORCE_INLINE_ bool is_editor_hint() const { return editor_hint; }
_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) { project_manager_hint = p_enabled; }
_FORCE_INLINE_ bool is_project_manager_hint() const { return project_manager_hint; }
_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; }
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return extension_reloading; }
_FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) { recovery_mode_hint = p_enabled; }
_FORCE_INLINE_ bool is_recovery_mode_hint() const { return recovery_mode_hint; }
#else
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
_FORCE_INLINE_ bool is_editor_hint() const { return false; }
_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) {}
_FORCE_INLINE_ bool is_project_manager_hint() const { return false; }
_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; }
_FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) {}
_FORCE_INLINE_ bool is_recovery_mode_hint() const { return false; }
#endif
Dictionary get_version_info() const;
Dictionary get_author_info() const;
TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
void set_write_movie_path(const String &p_path);
String get_write_movie_path() const;
String get_architecture_name() const;
void set_shader_cache_path(const String &p_path);
String get_shader_cache_path() const;
bool is_abort_on_gpu_errors_enabled() const;
bool is_validation_layers_enabled() const;
bool is_generate_spirv_debug_info_enabled() const;
bool is_extra_gpu_memory_tracking_enabled() const;
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
bool is_accurate_breadcrumbs_enabled() const;
#endif
int32_t get_gpu_index() const;
void increment_frames_drawn();
bool notify_frame_server_synced();
void set_freeze_time_scale(bool p_frozen);
void set_embedded_in_editor(bool p_enabled);
bool is_embedded_in_editor() const;
Engine();
virtual ~Engine();
};
#endif // ENGINE_H

File diff suppressed because it is too large Load diff

View file

@ -1,247 +0,0 @@
/**************************************************************************/
/* project_settings.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PROJECT_SETTINGS_H
#define PROJECT_SETTINGS_H
#include "core/object/class_db.h"
template <typename T>
class TypedArray;
class ProjectSettings : public Object {
GDCLASS(ProjectSettings, Object);
_THREAD_SAFE_CLASS_
friend class TestProjectSettingsInternalsAccessor;
bool is_changed = false;
public:
typedef HashMap<String, Variant> CustomMap;
static const String PROJECT_DATA_DIR_NAME_SUFFIX;
// Properties that are not for built in values begin from this value, so builtin ones are displayed first.
constexpr static const int32_t NO_BUILTIN_ORDER_BASE = 1 << 16;
#ifdef TOOLS_ENABLED
const static PackedStringArray get_required_features();
const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
#endif // TOOLS_ENABLED
struct AutoloadInfo {
StringName name;
String path;
bool is_singleton = false;
};
protected:
struct VariantContainer {
int order = 0;
bool persist = false;
bool basic = false;
bool internal = false;
Variant variant;
Variant initial;
bool hide_from_editor = false;
bool restart_if_changed = false;
#ifdef DEBUG_METHODS_ENABLED
bool ignore_value_in_docs = false;
#endif
VariantContainer() {}
VariantContainer(const Variant &p_variant, int p_order, bool p_persist = false) :
order(p_order),
persist(p_persist),
variant(p_variant) {
}
};
int last_order = NO_BUILTIN_ORDER_BASE;
int last_builtin_order = 0;
uint64_t last_save_time = 0;
RBMap<StringName, VariantContainer> props; // NOTE: Key order is used e.g. in the save_custom method.
String resource_path;
HashMap<StringName, PropertyInfo> custom_prop_info;
bool using_datapack = false;
bool project_loaded = false;
List<String> input_presets;
HashSet<String> custom_features;
HashMap<StringName, LocalVector<Pair<StringName, StringName>>> feature_overrides;
LocalVector<String> hidden_prefixes;
HashMap<StringName, AutoloadInfo> autoloads;
HashMap<StringName, String> global_groups;
HashMap<StringName, HashSet<StringName>> scene_groups_cache;
Array global_class_list;
bool is_global_class_list_loaded = false;
String project_data_dir_name;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
void _queue_changed();
void _emit_changed();
static ProjectSettings *singleton;
Error _load_settings_text(const String &p_path);
Error _load_settings_binary(const String &p_path);
Error _load_settings_text_or_binary(const String &p_text_path, const String &p_bin_path);
Error _save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
Error _save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
Error _save_custom_bnd(const String &p_file);
#ifdef TOOLS_ENABLED
const static PackedStringArray _get_supported_features();
const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
#endif // TOOLS_ENABLED
void _convert_to_last_version(int p_from_version);
bool load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset);
bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0, bool p_main_pack = false);
void _add_property_info_bind(const Dictionary &p_info);
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
void _add_builtin_input_map();
protected:
static void _bind_methods();
public:
static const int CONFIG_VERSION = 5;
void set_setting(const String &p_setting, const Variant &p_value);
Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
TypedArray<Dictionary> get_global_class_list();
void refresh_global_class_list();
void store_global_class_list(const Array &p_classes);
String get_global_class_list_path() const;
bool has_setting(const String &p_var) const;
String localize_path(const String &p_path) const;
String globalize_path(const String &p_path) const;
void set_initial_value(const String &p_name, const Variant &p_value);
void set_as_basic(const String &p_name, bool p_basic);
void set_as_internal(const String &p_name, bool p_internal);
void set_restart_if_changed(const String &p_name, bool p_restart);
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
bool get_ignore_value_in_docs(const String &p_name) const;
void add_hidden_prefix(const String &p_prefix);
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
String get_imported_files_path() const;
static ProjectSettings *get_singleton();
void clear(const String &p_name);
int get_order(const String &p_name) const;
void set_order(const String &p_name, int p_order);
void set_builtin_order(const String &p_name);
bool is_builtin_setting(const String &p_name) const;
Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
Error load_custom(const String &p_path);
Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true);
Error save();
void set_custom_property_info(const PropertyInfo &p_info);
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
uint64_t get_last_saved_time() { return last_save_time; }
List<String> get_input_presets() const { return input_presets; }
Variant get_setting_with_override(const StringName &p_name) const;
bool is_using_datapack() const;
bool is_project_loaded() const;
bool has_custom_feature(const String &p_feature) const;
const HashMap<StringName, AutoloadInfo> &get_autoload_list() const;
void add_autoload(const AutoloadInfo &p_autoload);
void remove_autoload(const StringName &p_autoload);
bool has_autoload(const StringName &p_autoload) const;
AutoloadInfo get_autoload(const StringName &p_name) const;
const HashMap<StringName, String> &get_global_groups_list() const;
void add_global_group(const StringName &p_name, const String &p_description);
void remove_global_group(const StringName &p_name);
bool has_global_group(const StringName &p_name) const;
const HashMap<StringName, HashSet<StringName>> &get_scene_groups_cache() const;
void add_scene_groups_cache(const StringName &p_path, const HashSet<StringName> &p_cache);
void remove_scene_groups_cache(const StringName &p_path);
void save_scene_groups_cache();
String get_scene_groups_cache_path() const;
void load_scene_groups_cache();
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
ProjectSettings();
ProjectSettings(const String &p_path);
~ProjectSettings();
};
// Not a macro any longer.
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
#define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true)
#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
#define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true)
#endif // PROJECT_SETTINGS_H

View file

@ -1,62 +0,0 @@
/**************************************************************************/
/* core_bind.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
namespace core_bind {
// Semaphore
void Semaphore::_post_bind_compat_93605() {
post(1);
}
void Semaphore::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("post"), &Semaphore::_post_bind_compat_93605);
}
// OS
String OS::_read_string_from_stdin_bind_compat_91201() {
return read_string_from_stdin(1024);
}
Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
return execute_with_pipe(p_path, p_arguments, true);
}
void OS::_bind_compatibility_methods() {
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
#endif // DISABLE_DEPRECATED

File diff suppressed because it is too large Load diff

View file

@ -1,674 +0,0 @@
/**************************************************************************/
/* core_bind.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_BIND_H
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
class MainLoop;
template <typename T>
class TypedArray;
namespace core_bind {
class ResourceLoader : public Object {
GDCLASS(ResourceLoader, Object);
protected:
static void _bind_methods();
static ResourceLoader *singleton;
public:
enum ThreadLoadStatus {
THREAD_LOAD_INVALID_RESOURCE,
THREAD_LOAD_IN_PROGRESS,
THREAD_LOAD_FAILED,
THREAD_LOAD_LOADED
};
enum CacheMode {
CACHE_MODE_IGNORE,
CACHE_MODE_REUSE,
CACHE_MODE_REPLACE,
CACHE_MODE_IGNORE_DEEP,
CACHE_MODE_REPLACE_DEEP,
};
static ResourceLoader *get_singleton() { return singleton; }
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, CacheMode p_cache_mode = CACHE_MODE_REUSE);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = ClassDB::default_array_arg);
Ref<Resource> load_threaded_get(const String &p_path);
Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front);
void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
bool has_cached(const String &p_path);
Ref<Resource> get_cached_ref(const String &p_path);
bool exists(const String &p_path, const String &p_type_hint = "");
ResourceUID::ID get_resource_uid(const String &p_path);
Vector<String> list_directory(const String &p_directory);
ResourceLoader() { singleton = this; }
};
class ResourceSaver : public Object {
GDCLASS(ResourceSaver, Object);
protected:
static void _bind_methods();
static ResourceSaver *singleton;
public:
enum SaverFlags {
FLAG_NONE = 0,
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
FLAG_OMIT_EDITOR_PROPERTIES = 8,
FLAG_SAVE_BIG_ENDIAN = 16,
FLAG_COMPRESS = 32,
FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
};
static ResourceSaver *get_singleton() { return singleton; }
Error save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags);
Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false);
ResourceSaver() { singleton = this; }
};
class OS : public Object {
GDCLASS(OS, Object);
mutable HashMap<String, bool> feature_cache;
protected:
static void _bind_methods();
static OS *singleton;
#ifndef DISABLE_DEPRECATED
Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments);
String _read_string_from_stdin_bind_compat_91201();
static void _bind_compatibility_methods();
#endif
public:
enum RenderingDriver {
RENDERING_DRIVER_VULKAN,
RENDERING_DRIVER_OPENGL3,
RENDERING_DRIVER_D3D12,
RENDERING_DRIVER_METAL,
};
PackedByteArray get_entropy(int p_bytes);
String get_system_ca_certificates();
enum StdHandleType {
STD_HANDLE_INVALID,
STD_HANDLE_CONSOLE,
STD_HANDLE_FILE,
STD_HANDLE_PIPE,
STD_HANDLE_UNKNOWN,
};
virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
void set_low_processor_usage_mode(bool p_enabled);
bool is_in_low_processor_usage_mode() const;
void set_low_processor_usage_mode_sleep_usec(int p_usec);
int get_low_processor_usage_mode_sleep_usec() const;
void set_delta_smoothing(bool p_enabled);
bool is_delta_smoothing_enabled() const;
void alert(const String &p_alert, const String &p_title = "ALERT!");
void crash(const String &p_message);
Vector<String> get_system_fonts() const;
String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
String get_executable_path() const;
String read_string_from_stdin(int64_t p_buffer_size = 1024);
PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024);
StdHandleType get_stdin_type() const;
StdHandleType get_stdout_type() const;
StdHandleType get_stderr_type() const;
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false);
Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
int create_instance(const Vector<String> &p_arguments);
Error kill(int p_pid);
Error shell_open(const String &p_uri);
Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);
bool is_process_running(int p_pid) const;
int get_process_exit_code(int p_pid) const;
int get_process_id() const;
void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
bool is_restart_on_exit_set() const;
Vector<String> get_restart_on_exit_arguments() const;
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
void set_environment(const String &p_var, const String &p_value) const;
void unset_environment(const String &p_var) const;
String get_name() const;
String get_distribution_name() const;
String get_version() const;
String get_version_alias() const;
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
Vector<String> get_video_adapter_driver_info() const;
String get_locale() const;
String get_locale_language() const;
String get_model_name() const;
bool is_debug_build() const;
String get_unique_id() const;
String get_keycode_string(Key p_code) const;
bool is_keycode_unicode(char32_t p_unicode) const;
Key find_keycode_from_string(const String &p_code) const;
void set_use_file_access_save_and_swap(bool p_enable);
uint64_t get_static_memory_usage() const;
uint64_t get_static_memory_peak_usage() const;
Dictionary get_memory_info() const;
void delay_usec(int p_usec) const;
void delay_msec(int p_msec) const;
uint64_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
bool is_userfs_persistent() const;
bool is_stdout_verbose() const;
int get_processor_count() const;
String get_processor_name() const;
enum SystemDir {
SYSTEM_DIR_DESKTOP,
SYSTEM_DIR_DCIM,
SYSTEM_DIR_DOCUMENTS,
SYSTEM_DIR_DOWNLOADS,
SYSTEM_DIR_MOVIES,
SYSTEM_DIR_MUSIC,
SYSTEM_DIR_PICTURES,
SYSTEM_DIR_RINGTONES,
};
String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const;
Error move_to_trash(const String &p_path) const;
String get_user_data_dir() const;
String get_config_dir() const;
String get_data_dir() const;
String get_cache_dir() const;
String get_temp_dir() const;
Error set_thread_name(const String &p_name);
::Thread::ID get_thread_caller_id() const;
::Thread::ID get_main_thread_id() const;
bool has_feature(const String &p_feature) const;
bool is_sandboxed() const;
bool request_permission(const String &p_name);
bool request_permissions();
Vector<String> get_granted_permissions() const;
void revoke_granted_permissions();
static OS *get_singleton() { return singleton; }
OS() { singleton = this; }
};
class Geometry2D : public Object {
GDCLASS(Geometry2D, Object);
static Geometry2D *singleton;
protected:
static void _bind_methods();
public:
static Geometry2D *get_singleton();
Variant segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b);
Variant line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b);
Vector<Vector2> get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2);
Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
bool point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const;
bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius);
real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius);
bool is_polygon_clockwise(const Vector<Vector2> &p_polygon);
bool is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon);
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
Vector<Point2> convex_hull(const Vector<Point2> &p_points);
TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
enum PolyBooleanOperation {
OPERATION_UNION,
OPERATION_DIFFERENCE,
OPERATION_INTERSECTION,
OPERATION_XOR
};
// 2D polygon boolean operations.
TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
// 2D polyline vs polygon operations.
TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
// 2D offset polygons/polylines.
enum PolyJoinType {
JOIN_SQUARE,
JOIN_ROUND,
JOIN_MITER
};
enum PolyEndType {
END_POLYGON,
END_JOINED,
END_BUTT,
END_SQUARE,
END_ROUND
};
TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
Dictionary make_atlas(const Vector<Size2> &p_rects);
TypedArray<Point2i> bresenham_line(const Point2i &p_from, const Point2i &p_to);
Geometry2D() { singleton = this; }
};
class Geometry3D : public Object {
GDCLASS(Geometry3D, Object);
static Geometry3D *singleton;
protected:
static void _bind_methods();
public:
static Geometry3D *get_singleton();
Vector<Vector3> compute_convex_mesh_points(const TypedArray<Plane> &p_planes);
TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes);
Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
Vector<int32_t> tetrahedralize_delaunay(const Vector<Vector3> &p_points);
Geometry3D() { singleton = this; }
};
class Marshalls : public Object {
GDCLASS(Marshalls, Object);
static Marshalls *singleton;
protected:
static void _bind_methods();
public:
static Marshalls *get_singleton();
String variant_to_base64(const Variant &p_var, bool p_full_objects = false);
Variant base64_to_variant(const String &p_str, bool p_allow_objects = false);
String raw_to_base64(const Vector<uint8_t> &p_arr);
Vector<uint8_t> base64_to_raw(const String &p_str);
String utf8_to_base64(const String &p_str);
String base64_to_utf8(const String &p_str);
Marshalls() { singleton = this; }
~Marshalls() { singleton = nullptr; }
};
class Mutex : public RefCounted {
GDCLASS(Mutex, RefCounted);
::Mutex mutex;
static void _bind_methods();
public:
void lock();
bool try_lock();
void unlock();
};
class Semaphore : public RefCounted {
GDCLASS(Semaphore, RefCounted);
::Semaphore semaphore;
protected:
static void _bind_methods();
#ifndef DISABLE_DEPRECATED
void _post_bind_compat_93605();
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED
public:
void wait();
bool try_wait();
void post(int p_count = 1);
};
class Thread : public RefCounted {
GDCLASS(Thread, RefCounted);
protected:
Variant ret;
SafeFlag running;
Callable target_callable;
::Thread thread;
static void _bind_methods();
static void _start_func(void *ud);
public:
enum Priority {
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH,
PRIORITY_MAX
};
Error start(const Callable &p_callable, Priority p_priority = PRIORITY_NORMAL);
String get_id() const;
bool is_started() const;
bool is_alive() const;
Variant wait_to_finish();
static void set_thread_safety_checks_enabled(bool p_enabled);
};
namespace special {
class ClassDB : public Object {
GDCLASS(ClassDB, Object);
protected:
static void _bind_methods();
public:
enum APIType {
API_CORE,
API_EDITOR,
API_EXTENSION,
API_EDITOR_EXTENSION,
API_NONE,
};
PackedStringArray get_class_list() const;
PackedStringArray get_inheriters_from_class(const StringName &p_class) const;
StringName get_parent_class(const StringName &p_class) const;
bool class_exists(const StringName &p_class) const;
bool is_parent_class(const StringName &p_class, const StringName &p_inherits) const;
bool can_instantiate(const StringName &p_class) const;
Variant instantiate(const StringName &p_class) const;
APIType class_get_api_type(const StringName &p_class) const;
bool class_has_signal(const StringName &p_class, const StringName &p_signal) const;
Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const;
TypedArray<Dictionary> class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const;
TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const;
StringName class_get_property_getter(const StringName &p_class, const StringName &p_property);
StringName class_get_property_setter(const StringName &p_class, const StringName &p_property);
Variant class_get_property(Object *p_object, const StringName &p_property) const;
Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const;
bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
Variant class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error);
PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
int64_t class_get_integer_constant(const StringName &p_class, const StringName &p_name) const;
bool class_has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
PackedStringArray class_get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
bool is_class_enabled(const StringName &p_class) const;
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
ClassDB() {}
~ClassDB() {}
};
} // namespace special
class Engine : public Object {
GDCLASS(Engine, Object);
protected:
static void _bind_methods();
static Engine *singleton;
public:
static Engine *get_singleton() { return singleton; }
void set_physics_ticks_per_second(int p_ips);
int get_physics_ticks_per_second() const;
void set_max_physics_steps_per_frame(int p_max_physics_steps);
int get_max_physics_steps_per_frame() const;
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
double get_physics_interpolation_fraction() const;
void set_max_fps(int p_fps);
int get_max_fps() const;
double get_frames_per_second() const;
uint64_t get_physics_frames() const;
uint64_t get_process_frames() const;
int get_frames_drawn();
void set_time_scale(double p_scale);
double get_time_scale();
MainLoop *get_main_loop() const;
Dictionary get_version_info() const;
Dictionary get_author_info() const;
TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
String get_architecture_name() const;
bool is_in_physics_frame() const;
bool has_singleton(const StringName &p_name) const;
Object *get_singleton_object(const StringName &p_name) const;
void register_singleton(const StringName &p_name, Object *p_object);
void unregister_singleton(const StringName &p_name);
Vector<String> get_singleton_list() const;
Error register_script_language(ScriptLanguage *p_language);
Error unregister_script_language(const ScriptLanguage *p_language);
int get_script_language_count();
ScriptLanguage *get_script_language(int p_index) const;
void set_editor_hint(bool p_enabled);
bool is_editor_hint() const;
bool is_embedded_in_editor() const;
// `set_write_movie_path()` is not exposed to the scripting API as changing it at run-time has no effect.
String get_write_movie_path() const;
void set_print_to_stdout(bool p_enabled);
bool is_printing_to_stdout() const;
void set_print_error_messages(bool p_enabled);
bool is_printing_error_messages() const;
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
Engine() { singleton = this; }
};
class EngineDebugger : public Object {
GDCLASS(EngineDebugger, Object);
HashMap<StringName, Callable> captures;
HashMap<StringName, Ref<EngineProfiler>> profilers;
protected:
static void _bind_methods();
static EngineDebugger *singleton;
public:
static EngineDebugger *get_singleton() { return singleton; }
bool is_active();
void register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler);
void unregister_profiler(const StringName &p_name);
bool is_profiling(const StringName &p_name);
bool has_profiler(const StringName &p_name);
void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
void register_message_capture(const StringName &p_name, const Callable &p_callable);
void unregister_message_capture(const StringName &p_name);
bool has_capture(const StringName &p_name);
void send_message(const String &p_msg, const Array &p_data);
void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
void script_debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
void line_poll();
void set_lines_left(int p_lines);
int get_lines_left() const;
void set_depth(int p_depth);
int get_depth() const;
bool is_breakpoint(int p_line, const StringName &p_source) const;
bool is_skipping_breakpoints() const;
void insert_breakpoint(int p_line, const StringName &p_source);
void remove_breakpoint(int p_line, const StringName &p_source);
void clear_breakpoints();
EngineDebugger() { singleton = this; }
~EngineDebugger();
};
} // namespace core_bind
VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus);
VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
VARIANT_BITFIELD_CAST(core_bind::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(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
VARIANT_ENUM_CAST(core_bind::special::ClassDB::APIType);
#endif // CORE_BIND_H

View file

@ -1,315 +0,0 @@
"""Functions used to generate source files during build time"""
import zlib
def escape_string(s):
def charcode_to_c_escapes(c):
rev_result = []
while c >= 256:
c, low = (c // 256, c % 256)
rev_result.append("\\%03o" % low)
rev_result.append("\\%03o" % c)
return "".join(reversed(rev_result))
result = ""
if isinstance(s, str):
s = s.encode("utf-8")
for c in s:
if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
result += charcode_to_c_escapes(c)
else:
result += chr(c)
return result
def make_certs_header(target, source, env):
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")
# 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))
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")
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",
]
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
def close_section():
g.write("\t0\n")
g.write("};\n")
for line in f:
if reading:
if line.startswith(" "):
g.write('\t"' + escape_string(line.strip()) + '",\n')
continue
if 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
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",
]
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
def close_section():
g.write("\t0\n")
g.write("};\n")
for line in f:
if reading >= 0:
if line.startswith(" "):
g.write('\t"' + escape_string(line.strip()) + '",\n')
continue
if 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
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):
self._license_file = license_file
self.line_num = 0
self.current = self.next_line()
def next_line(self):
line = self._license_file.readline()
self.line_num += 1
while line.startswith("#"):
line = self._license_file.readline()
self.line_num += 1
self.current = line
return line
def next_tag(self):
if ":" not in self.current:
return ("", [])
tag, line = self.current.split(":", 1)
lines = [line.strip()]
while self.next_line() and self.current.startswith(" "):
lines.append(self.current.strip())
return (tag, lines)
from collections import OrderedDict
projects: dict = OrderedDict()
license_list = []
with open(src_copyright, "r", encoding="utf-8") as copyright_file:
reader = LicenseReader(copyright_file)
part = {}
while reader.current:
tag, content = reader.next_tag()
if tag in ("Files", "Copyright", "License"):
part[tag] = content[:]
elif tag == "Comment" and part:
# attach non-empty part to named project
projects[content[0]] = projects.get(content[0], []) + [part]
if not tag or not reader.current:
# end of a paragraph start a new part
if "License" in part and "Files" not in part:
# no Files tag in this one, so assume standalone license
license_list.append(part["License"])
part = {}
reader.next_line()
data_list: list = []
for project in iter(projects.values()):
for part in project:
part["file_index"] = len(data_list)
data_list += part["Files"]
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 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")
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"
)
f.write(
"struct ComponentCopyright {\n"
"\tconst char *name;\n"
"\tconst ComponentCopyrightPart *parts;\n"
"\tint part_count;\n"
"};\n\n"
)
f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
for line in data_list:
f.write('\t"' + escape_string(line) + '",\n')
f.write("};\n\n")
f.write("const 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"
)
part_index += 1
f.write("};\n\n")
f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
f.write("const 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"
)
f.write("};\n\n")
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
f.write("const char *const LICENSE_NAMES[] = {\n")
for license in license_list:
f.write('\t"' + escape_string(license[0]) + '",\n')
f.write("};\n\n")
f.write("const char *const LICENSE_BODIES[] = {\n\n")
for license in license_list:
for line in license[1:]:
if line == ".":
f.write('\t"\\n"\n')
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")

View file

@ -1,862 +0,0 @@
/**************************************************************************/
/* core_constants.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "core_constants.h"
#include "core/input/input_event.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
#include "core/variant/variant.h"
struct _CoreConstant {
#ifdef DEBUG_METHODS_ENABLED
bool ignore_value_in_docs = false;
bool is_bitfield = false;
#endif
StringName enum_name;
const char *name = nullptr;
int64_t value = 0;
_CoreConstant() {}
#ifdef DEBUG_METHODS_ENABLED
_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value, bool p_ignore_value_in_docs = false, bool p_is_bitfield = false) :
ignore_value_in_docs(p_ignore_value_in_docs),
is_bitfield(p_is_bitfield),
enum_name(p_enum_name),
name(p_name),
value(p_value) {
}
#else
_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value) :
enum_name(p_enum_name),
name(p_name),
value(p_value) {
}
#endif
};
static Vector<_CoreConstant> _global_constants;
static HashMap<StringName, int> _global_constants_map;
static HashMap<StringName, Vector<_CoreConstant>> _global_enums;
#ifdef DEBUG_METHODS_ENABLED
#define BIND_CORE_CONSTANT(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, false, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
// This just binds enum classes as if they were regular enum constants.
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, false, true)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member, false, true)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, true)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant, true)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#else
#define BIND_CORE_CONSTANT(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
// This just binds enum classes as if they were regular enum constants.
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
{ \
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name); \
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
{ \
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1;
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
{ \
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
}
#endif
void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
BIND_CORE_ENUM_CONSTANT(SIDE_TOP);
BIND_CORE_ENUM_CONSTANT(SIDE_RIGHT);
BIND_CORE_ENUM_CONSTANT(SIDE_BOTTOM);
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_LEFT);
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_RIGHT);
BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
BIND_CORE_ENUM_CONSTANT(VERTICAL);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
BIND_CORE_ENUM_CONSTANT(CLOCKWISE);
BIND_CORE_ENUM_CONSTANT(COUNTERCLOCKWISE);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_LEFT);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_CENTER);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_RIGHT);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_FILL);
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_TOP);
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_CENTER);
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_BOTTOM);
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_FILL);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BASELINE_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_TOP);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_CENTER);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BASELINE);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BOTTOM);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XYZ);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XZY);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YXZ);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YZX);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZXY);
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZYX);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TAB);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKTAB);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSPACE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ENTER);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ENTER);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, INSERT);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_DELETE, KEY_DELETE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAUSE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PRINT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SYSREQ);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CLEAR);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOME);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, END);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEUP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEDOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SHIFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CTRL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, META);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ALT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CAPSLOCK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMLOCK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SCROLLLOCK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F1);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F2);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F3);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F4);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F5);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F6);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F7);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F8);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F9);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F10);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F11);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F12);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F13);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F14);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F15);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F16);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F17);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F18);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F19);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F20);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F21);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F22);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F23);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F24);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F25);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F26);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F27);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F28);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F29);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F30);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F31);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F32);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F33);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F34);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F35);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_MULTIPLY);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_DIVIDE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_SUBTRACT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_PERIOD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ADD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_0);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_1);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_2);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_3);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_4);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_5);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_6);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_7);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_8);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_9);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MENU);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HELP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FORWARD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STOP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, REFRESH);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEDOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEMUTE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEUP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPLAY);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIASTOP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPREVIOUS);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIANEXT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIARECORD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOMEPAGE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FAVORITES);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEARCH);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STANDBY);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OPENURL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMAIL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMEDIA);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH0);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH1);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH2);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH3);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH4);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH5);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH6);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH7);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH8);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH9);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHA);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHB);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHC);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHF);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNKNOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPACE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EXCLAM);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTEDBL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMBERSIGN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOLLAR);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERCENT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AMPERSAND);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, APOSTROPHE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENLEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENRIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASTERISK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PLUS);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COMMA);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MINUS);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERIOD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SLASH);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_0, KEY_0);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_1, KEY_1);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_2, KEY_2);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_3, KEY_3);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_4, KEY_4);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_5, KEY_5);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_6, KEY_6);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_7, KEY_7);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_8, KEY_8);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_9, KEY_9);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COLON);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEMICOLON);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LESS);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EQUAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GREATER);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUESTION);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, A);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, B);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, C);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, D);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, E);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, G);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, H);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, I);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, J);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, K);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, L);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, M);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, N);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, O);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, P);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Q);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, R);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, S);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, T);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, U);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, V);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, W);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, X);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Y);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Z);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETLEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSLASH);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETRIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIICIRCUM);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNDERSCORE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTELEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACELEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BAR);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACERIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIITILDE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YEN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SECTION);
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK);
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CMD_OR_CTRL);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, SHIFT);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, ALT);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, META);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CTRL);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, KPAD);
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, UNSPECIFIED);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, MIDDLE);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_UP);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_DOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON1, MB_XBUTTON1);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON2, MB_XBUTTON2);
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, LEFT);
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, RIGHT);
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MIDDLE);
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON1);
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON2);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, INVALID);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, A);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, B);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, X);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, Y);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, BACK);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, GUIDE);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, START);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_STICK);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_STICK);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_SHOULDER);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_SHOULDER);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_UP);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_DOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC1);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE1);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE2);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE3);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE4);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, TOUCHPAD);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, SDL_MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, INVALID);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_X);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_Y);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_X);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_Y);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, SDL_MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_OFF);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_ON);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, AFTERTOUCH);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTROL_CHANGE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PROGRAM_CHANGE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CHANNEL_PRESSURE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PITCH_BEND);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_EXCLUSIVE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, QUARTER_FRAME);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_POSITION_POINTER);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_SELECT);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TUNE_REQUEST);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TIMING_CLOCK);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, START);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTINUE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, STOP);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, ACTIVE_SENSING);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_RESET);
// error list
BIND_CORE_ENUM_CONSTANT(OK); // (0)
BIND_CORE_ENUM_CONSTANT(FAILED);
BIND_CORE_ENUM_CONSTANT(ERR_UNAVAILABLE);
BIND_CORE_ENUM_CONSTANT(ERR_UNCONFIGURED);
BIND_CORE_ENUM_CONSTANT(ERR_UNAUTHORIZED);
BIND_CORE_ENUM_CONSTANT(ERR_PARAMETER_RANGE_ERROR); // (5)
BIND_CORE_ENUM_CONSTANT(ERR_OUT_OF_MEMORY);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_NOT_FOUND);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_DRIVE);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_PATH);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_NO_PERMISSION); // (10)
BIND_CORE_ENUM_CONSTANT(ERR_FILE_ALREADY_IN_USE);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_OPEN);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_WRITE);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_READ);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_UNRECOGNIZED); // (15)
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CORRUPT);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_MISSING_DEPENDENCIES);
BIND_CORE_ENUM_CONSTANT(ERR_FILE_EOF);
BIND_CORE_ENUM_CONSTANT(ERR_CANT_OPEN);
BIND_CORE_ENUM_CONSTANT(ERR_CANT_CREATE); // (20)
BIND_CORE_ENUM_CONSTANT(ERR_QUERY_FAILED);
BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_IN_USE);
BIND_CORE_ENUM_CONSTANT(ERR_LOCKED);
BIND_CORE_ENUM_CONSTANT(ERR_TIMEOUT);
BIND_CORE_ENUM_CONSTANT(ERR_CANT_CONNECT); // (25)
BIND_CORE_ENUM_CONSTANT(ERR_CANT_RESOLVE);
BIND_CORE_ENUM_CONSTANT(ERR_CONNECTION_ERROR);
BIND_CORE_ENUM_CONSTANT(ERR_CANT_ACQUIRE_RESOURCE);
BIND_CORE_ENUM_CONSTANT(ERR_CANT_FORK);
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DATA); // (30)
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_PARAMETER);
BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_EXISTS);
BIND_CORE_ENUM_CONSTANT(ERR_DOES_NOT_EXIST);
BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_READ);
BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_WRITE); // (35)
BIND_CORE_ENUM_CONSTANT(ERR_COMPILATION_FAILED);
BIND_CORE_ENUM_CONSTANT(ERR_METHOD_NOT_FOUND);
BIND_CORE_ENUM_CONSTANT(ERR_LINK_FAILED);
BIND_CORE_ENUM_CONSTANT(ERR_SCRIPT_FAILED);
BIND_CORE_ENUM_CONSTANT(ERR_CYCLIC_LINK); // (40)
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DECLARATION);
BIND_CORE_ENUM_CONSTANT(ERR_DUPLICATE_SYMBOL);
BIND_CORE_ENUM_CONSTANT(ERR_PARSE_ERROR);
BIND_CORE_ENUM_CONSTANT(ERR_BUSY);
BIND_CORE_ENUM_CONSTANT(ERR_SKIP); // (45)
BIND_CORE_ENUM_CONSTANT(ERR_HELP);
BIND_CORE_ENUM_CONSTANT(ERR_BUG);
BIND_CORE_ENUM_CONSTANT(ERR_PRINTER_ON_FIRE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LINK);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_NAVIGATION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_NAVIGATION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_AVOIDANCE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_SAVE_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DICTIONARY_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ONESHOT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORAGE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_INTERNAL);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKABLE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKED);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_GROUP);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CATEGORY);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SUBGROUP);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_BITFIELD);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_INSTANCE_STATE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESTART_IF_CHANGED);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_VARIABLE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORE_IF_NULL);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_ENUM);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NIL_IS_VARIANT);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ARRAY);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ALWAYS_DUPLICATE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NEVER_DUPLICATE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_HIGH_END_GFX);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_KEYING_INCREMENTS);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFERRED_SET_RESOURCE);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_BASIC_SETTING);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_READ_ONLY);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SECRET);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFAULT);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_EDITOR);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_NORMAL);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_EDITOR);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_CONST);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VARARG);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_STATIC);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_OBJECT_CORE);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL_REQUIRED);
BIND_CORE_BITFIELD_FLAG(METHOD_FLAGS_DEFAULT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT", Variant::FLOAT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING", Variant::STRING);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2", Variant::VECTOR2);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2I", Variant::VECTOR2I);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2", Variant::RECT2);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2I", Variant::RECT2I);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3", Variant::VECTOR3);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4", Variant::VECTOR4);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4I", Variant::VECTOR4I);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PROJECTION", Variant::PROJECTION);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::RID);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_BYTE_ARRAY", Variant::PACKED_BYTE_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT32_ARRAY", Variant::PACKED_INT32_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT64_ARRAY", Variant::PACKED_INT64_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT32_ARRAY", Variant::PACKED_FLOAT32_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT64_ARRAY", Variant::PACKED_FLOAT64_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_STRING_ARRAY", Variant::PACKED_STRING_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR2_ARRAY", Variant::PACKED_VECTOR2_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR3_ARRAY", Variant::PACKED_VECTOR3_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_COLOR_ARRAY", Variant::PACKED_COLOR_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR4_ARRAY", Variant::PACKED_VECTOR4_ARRAY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
//comparison
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
//mathematic
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POWER", Variant::OP_POWER);
//bitwise
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
//logic
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
//containment
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
}
void unregister_global_constants() {
_global_constants.clear();
_global_constants_map.clear();
_global_enums.clear();
}
int CoreConstants::get_global_constant_count() {
return _global_constants.size();
}
StringName CoreConstants::get_global_constant_enum(int p_idx) {
return _global_constants[p_idx].enum_name;
}
#ifdef DEBUG_METHODS_ENABLED
bool CoreConstants::is_global_constant_bitfield(int p_idx) {
return _global_constants[p_idx].is_bitfield;
}
bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
return _global_constants[p_idx].ignore_value_in_docs;
}
#else
bool CoreConstants::is_global_constant_bitfield(int p_idx) {
return false;
}
bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
return false;
}
#endif
const char *CoreConstants::get_global_constant_name(int p_idx) {
return _global_constants[p_idx].name;
}
int64_t CoreConstants::get_global_constant_value(int p_idx) {
return _global_constants[p_idx].value;
}
bool CoreConstants::is_global_constant(const StringName &p_name) {
return _global_constants_map.has(p_name);
}
int CoreConstants::get_global_constant_index(const StringName &p_name) {
ERR_FAIL_COND_V_MSG(!_global_constants_map.has(p_name), -1, "Trying to get index of non-existing constant.");
return _global_constants_map[p_name];
}
bool CoreConstants::is_global_enum(const StringName &p_enum) {
return _global_enums.has(p_enum);
}
void CoreConstants::get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values) {
ERR_FAIL_NULL_MSG(p_values, "Trying to get enum values with null map.");
ERR_FAIL_COND_MSG(!_global_enums.has(p_enum), "Trying to get values of non-existing enum.");
for (const _CoreConstant &constant : _global_enums[p_enum]) {
(*p_values)[constant.name] = constant.value;
}
}

View file

@ -1,51 +0,0 @@
/**************************************************************************/
/* core_constants.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_CONSTANTS_H
#define CORE_CONSTANTS_H
#include "core/string/string_name.h"
#include "core/templates/hash_map.h"
class CoreConstants {
public:
static int get_global_constant_count();
static StringName get_global_constant_enum(int p_idx);
static bool is_global_constant_bitfield(int p_idx);
static bool get_ignore_value_in_docs(int p_idx);
static const char *get_global_constant_name(int p_idx);
static int64_t get_global_constant_value(int p_idx);
static bool is_global_constant(const StringName &p_name);
static int get_global_constant_index(const StringName &p_name);
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

@ -1,35 +0,0 @@
/**************************************************************************/
/* core_globals.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "core_globals.h"
bool CoreGlobals::leak_reporting_enabled = true;
bool CoreGlobals::print_line_enabled = true;
bool CoreGlobals::print_error_enabled = true;

View file

@ -1,44 +0,0 @@
/**************************************************************************/
/* core_globals.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_GLOBALS_H
#define CORE_GLOBALS_H
// Home for state needed from global functions
// that cannot be stored in Engine or OS due to e.g. circular includes
class CoreGlobals {
public:
static bool leak_reporting_enabled;
static bool print_line_enabled;
static bool print_error_enabled;
};
#endif // CORE_GLOBALS_H

View file

@ -1,91 +0,0 @@
/**************************************************************************/
/* core_string_names.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CORE_STRING_NAMES_H
#define CORE_STRING_NAMES_H
#include "core/string/string_name.h"
class CoreStringNames {
inline static CoreStringNames *singleton = nullptr;
public:
static void create() { singleton = memnew(CoreStringNames); }
static void free() {
memdelete(singleton);
singleton = nullptr;
}
_FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; }
const StringName free_ = StaticCString::create("free"); // free would conflict with C++ keyword.
const StringName changed = StaticCString::create("changed");
const StringName script = StaticCString::create("script");
const StringName script_changed = StaticCString::create("script_changed");
const StringName _iter_init = StaticCString::create("_iter_init");
const StringName _iter_next = StaticCString::create("_iter_next");
const StringName _iter_get = StaticCString::create("_iter_get");
const StringName get_rid = StaticCString::create("get_rid");
const StringName _to_string = StaticCString::create("_to_string");
const StringName _custom_features = StaticCString::create("_custom_features");
const StringName x = StaticCString::create("x");
const StringName y = StaticCString::create("y");
const StringName z = StaticCString::create("z");
const StringName w = StaticCString::create("w");
const StringName r = StaticCString::create("r");
const StringName g = StaticCString::create("g");
const StringName b = StaticCString::create("b");
const StringName a = StaticCString::create("a");
const StringName position = StaticCString::create("position");
const StringName size = StaticCString::create("size");
const StringName end = StaticCString::create("end");
const StringName basis = StaticCString::create("basis");
const StringName origin = StaticCString::create("origin");
const StringName normal = StaticCString::create("normal");
const StringName d = StaticCString::create("d");
const StringName h = StaticCString::create("h");
const StringName s = StaticCString::create("s");
const StringName v = StaticCString::create("v");
const StringName r8 = StaticCString::create("r8");
const StringName g8 = StaticCString::create("g8");
const StringName b8 = StaticCString::create("b8");
const StringName a8 = StaticCString::create("a8");
const StringName call = StaticCString::create("call");
const StringName call_deferred = StaticCString::create("call_deferred");
const StringName bind = StaticCString::create("bind");
const StringName notification = StaticCString::create("notification");
const StringName property_list_changed = StaticCString::create("property_list_changed");
};
#define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name
#endif // CORE_STRING_NAMES_H

View file

@ -1,65 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env_crypto = env.Clone()
is_builtin = env["builtin_mbedtls"]
has_module = env["module_mbedtls_enabled"]
thirdparty_obj = []
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"])
# MbedTLS core functions (for CryptoCore).
# If the mbedtls module is compiled we don't need to add the .c files with our
# custom config since they will be built by the module itself.
# Only if the module is not enabled, we must compile here the required sources
# to make a "light" build with only the necessary mbedtls files.
if not has_module:
# Minimal mbedTLS config file
config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Build minimal mbedTLS library (MD5/SHA/Base64/AES).
env_thirdparty = env_crypto.Clone()
env_thirdparty.disable_warnings()
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
thirdparty_mbedtls_sources = [
"aes.c",
"base64.c",
"constant_time.c",
"ctr_drbg.c",
"entropy.c",
"md.c",
"md5.c",
"sha1.c",
"sha256.c",
"godot_core_mbedtls_platform.c",
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
# Needed to force rebuilding the library when the configuration file is updated.
env_thirdparty.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_core_mbedtls_config.h")
env.core_sources += thirdparty_obj
elif is_builtin:
# Module mbedTLS config file
config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Needed to force rebuilding the core files when the configuration file is updated.
thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
# Godot source files
core_obj = []
env_crypto.add_source_files(core_obj, "*.cpp")
env.core_sources += core_obj
# Needed to force rebuilding the core files when the thirdparty library is updated.
env.Depends(core_obj, thirdparty_obj)

View file

@ -1,115 +0,0 @@
/**************************************************************************/
/* aes_context.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "core/crypto/aes_context.h"
Error AESContext::start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv) {
ERR_FAIL_COND_V_MSG(mode != MODE_MAX, ERR_ALREADY_IN_USE, "AESContext already started. Call 'finish' before starting a new one.");
ERR_FAIL_COND_V_MSG(p_mode < 0 || p_mode >= MODE_MAX, ERR_INVALID_PARAMETER, "Invalid mode requested.");
// Key check.
int key_bits = p_key.size() << 3;
ERR_FAIL_COND_V_MSG(key_bits != 128 && key_bits != 256, ERR_INVALID_PARAMETER, "AES key must be either 16 or 32 bytes");
// Initialization vector.
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_CBC_DECRYPT) {
ERR_FAIL_COND_V_MSG(p_iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes.");
iv.resize(0);
iv.append_array(p_iv);
}
// Encryption/decryption key.
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_ECB_ENCRYPT) {
ctx.set_encode_key(p_key.ptr(), key_bits);
} else {
ctx.set_decode_key(p_key.ptr(), key_bits);
}
mode = p_mode;
return OK;
}
PackedByteArray AESContext::update(const PackedByteArray &p_src) {
ERR_FAIL_COND_V_MSG(mode < 0 || mode >= MODE_MAX, PackedByteArray(), "AESContext not started. Call 'start' before calling 'update'.");
int len = p_src.size();
ERR_FAIL_COND_V_MSG(len % 16, PackedByteArray(), "The number of bytes to be encrypted must be multiple of 16. Add padding if needed");
PackedByteArray out;
out.resize(len);
const uint8_t *src_ptr = p_src.ptr();
uint8_t *out_ptr = out.ptrw();
switch (mode) {
case MODE_ECB_ENCRYPT: {
for (int i = 0; i < len; i += 16) {
Error err = ctx.encrypt_ecb(src_ptr + i, out_ptr + i);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
}
} break;
case MODE_ECB_DECRYPT: {
for (int i = 0; i < len; i += 16) {
Error err = ctx.decrypt_ecb(src_ptr + i, out_ptr + i);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
}
} break;
case MODE_CBC_ENCRYPT: {
Error err = ctx.encrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
ERR_FAIL_COND_V(err != OK, PackedByteArray());
} break;
case MODE_CBC_DECRYPT: {
Error err = ctx.decrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
ERR_FAIL_COND_V(err != OK, PackedByteArray());
} break;
default:
ERR_FAIL_V_MSG(PackedByteArray(), "Bug!");
}
return out;
}
PackedByteArray AESContext::get_iv_state() {
ERR_FAIL_COND_V_MSG(mode != MODE_CBC_ENCRYPT && mode != MODE_CBC_DECRYPT, PackedByteArray(), "Calling 'get_iv_state' only makes sense when the context is started in CBC mode.");
PackedByteArray out;
out.append_array(iv);
return out;
}
void AESContext::finish() {
mode = MODE_MAX;
iv.resize(0);
}
void AESContext::_bind_methods() {
ClassDB::bind_method(D_METHOD("start", "mode", "key", "iv"), &AESContext::start, DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("update", "src"), &AESContext::update);
ClassDB::bind_method(D_METHOD("get_iv_state"), &AESContext::get_iv_state);
ClassDB::bind_method(D_METHOD("finish"), &AESContext::finish);
BIND_ENUM_CONSTANT(MODE_ECB_ENCRYPT);
BIND_ENUM_CONSTANT(MODE_ECB_DECRYPT);
BIND_ENUM_CONSTANT(MODE_CBC_ENCRYPT);
BIND_ENUM_CONSTANT(MODE_CBC_DECRYPT);
BIND_ENUM_CONSTANT(MODE_MAX);
}
AESContext::AESContext() {
}

View file

@ -1,68 +0,0 @@
/**************************************************************************/
/* aes_context.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef AES_CONTEXT_H
#define AES_CONTEXT_H
#include "core/crypto/crypto_core.h"
#include "core/object/ref_counted.h"
class AESContext : public RefCounted {
GDCLASS(AESContext, RefCounted);
public:
enum Mode : int32_t {
MODE_ECB_ENCRYPT,
MODE_ECB_DECRYPT,
MODE_CBC_ENCRYPT,
MODE_CBC_DECRYPT,
MODE_MAX
};
private:
Mode mode = MODE_MAX;
CryptoCore::AESContext ctx;
PackedByteArray iv;
protected:
static void _bind_methods();
public:
Error start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv = PackedByteArray());
PackedByteArray update(const PackedByteArray &p_src);
PackedByteArray get_iv_state();
void finish();
AESContext();
};
VARIANT_ENUM_CAST(AESContext::Mode);
#endif // AES_CONTEXT_H

View file

@ -1,259 +0,0 @@
/**************************************************************************/
/* crypto.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "crypto.h"
/// Resources
CryptoKey *(*CryptoKey::_create)(bool p_notify_postinitialize) = nullptr;
CryptoKey *CryptoKey::create(bool p_notify_postinitialize) {
if (_create) {
return _create(p_notify_postinitialize);
}
return nullptr;
}
void CryptoKey::_bind_methods() {
ClassDB::bind_method(D_METHOD("save", "path", "public_only"), &CryptoKey::save, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load", "path", "public_only"), &CryptoKey::load, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_public_only"), &CryptoKey::is_public_only);
ClassDB::bind_method(D_METHOD("save_to_string", "public_only"), &CryptoKey::save_to_string, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false));
}
X509Certificate *(*X509Certificate::_create)(bool p_notify_postinitialize) = nullptr;
X509Certificate *X509Certificate::create(bool p_notify_postinitialize) {
if (_create) {
return _create(p_notify_postinitialize);
}
return nullptr;
}
void X509Certificate::_bind_methods() {
ClassDB::bind_method(D_METHOD("save", "path"), &X509Certificate::save);
ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load);
ClassDB::bind_method(D_METHOD("save_to_string"), &X509Certificate::save_to_string);
ClassDB::bind_method(D_METHOD("load_from_string", "string"), &X509Certificate::load_from_string);
}
/// TLSOptions
Ref<TLSOptions> TLSOptions::client(Ref<X509Certificate> p_trusted_chain, const String &p_common_name_override) {
Ref<TLSOptions> opts;
opts.instantiate();
opts->mode = MODE_CLIENT;
opts->trusted_ca_chain = p_trusted_chain;
opts->common_name = p_common_name_override;
return opts;
}
Ref<TLSOptions> TLSOptions::client_unsafe(Ref<X509Certificate> p_trusted_chain) {
Ref<TLSOptions> opts;
opts.instantiate();
opts->mode = MODE_CLIENT_UNSAFE;
opts->trusted_ca_chain = p_trusted_chain;
return opts;
}
Ref<TLSOptions> TLSOptions::server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate) {
Ref<TLSOptions> opts;
opts.instantiate();
opts->mode = MODE_SERVER;
opts->own_certificate = p_own_certificate;
opts->private_key = p_own_key;
return opts;
}
void TLSOptions::_bind_methods() {
ClassDB::bind_static_method("TLSOptions", D_METHOD("client", "trusted_chain", "common_name_override"), &TLSOptions::client, DEFVAL(Ref<X509Certificate>()), DEFVAL(String()));
ClassDB::bind_static_method("TLSOptions", D_METHOD("client_unsafe", "trusted_chain"), &TLSOptions::client_unsafe, DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_static_method("TLSOptions", D_METHOD("server", "key", "certificate"), &TLSOptions::server);
ClassDB::bind_method(D_METHOD("is_server"), &TLSOptions::is_server);
ClassDB::bind_method(D_METHOD("is_unsafe_client"), &TLSOptions::is_unsafe_client);
ClassDB::bind_method(D_METHOD("get_common_name_override"), &TLSOptions::get_common_name_override);
ClassDB::bind_method(D_METHOD("get_trusted_ca_chain"), &TLSOptions::get_trusted_ca_chain);
ClassDB::bind_method(D_METHOD("get_private_key"), &TLSOptions::get_private_key);
ClassDB::bind_method(D_METHOD("get_own_certificate"), &TLSOptions::get_own_certificate);
}
/// HMACContext
void HMACContext::_bind_methods() {
ClassDB::bind_method(D_METHOD("start", "hash_type", "key"), &HMACContext::start);
ClassDB::bind_method(D_METHOD("update", "data"), &HMACContext::update);
ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
}
HMACContext *(*HMACContext::_create)(bool p_notify_postinitialize) = nullptr;
HMACContext *HMACContext::create(bool p_notify_postinitialize) {
if (_create) {
return _create(p_notify_postinitialize);
}
ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
}
/// Crypto
void (*Crypto::_load_default_certificates)(const String &p_path) = nullptr;
Crypto *(*Crypto::_create)(bool p_notify_postinitialize) = nullptr;
Crypto *Crypto::create(bool p_notify_postinitialize) {
if (_create) {
return _create(p_notify_postinitialize);
}
ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled.");
}
void Crypto::load_default_certificates(const String &p_path) {
if (_load_default_certificates) {
_load_default_certificates(p_path);
}
}
PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg) {
Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available without mbedtls module.");
Error err = ctx->start(p_hash_type, p_key);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
err = ctx->update(p_msg);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
return ctx->finish();
}
// Compares two HMACS for equality without leaking timing information in order to prevent timing attacks.
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
bool Crypto::constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received) {
const uint8_t *t = p_trusted.ptr();
const uint8_t *r = p_received.ptr();
int tlen = p_trusted.size();
int rlen = p_received.size();
// If the lengths are different then nothing else matters.
if (tlen != rlen) {
return false;
}
uint8_t v = 0;
for (int i = 0; i < tlen; i++) {
v |= t[i] ^ r[i];
}
return v == 0;
}
void Crypto::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes);
ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa);
ClassDB::bind_method(D_METHOD("generate_self_signed_certificate", "key", "issuer_name", "not_before", "not_after"), &Crypto::generate_self_signed_certificate, DEFVAL("CN=myserver,O=myorganisation,C=IT"), DEFVAL("20140101000000"), DEFVAL("20340101000000"));
ClassDB::bind_method(D_METHOD("sign", "hash_type", "hash", "key"), &Crypto::sign);
ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify);
ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt);
ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt);
ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest);
ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare);
}
/// Resource loader/saver
Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
if (cert) {
cert->load(p_path);
}
return cert;
} else if (el == "key") {
CryptoKey *key = CryptoKey::create();
if (key) {
key->load(p_path, false);
}
return key;
} else if (el == "pub") {
CryptoKey *key = CryptoKey::create();
if (key) {
key->load(p_path, true);
}
return key;
}
return nullptr;
}
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("crt");
p_extensions->push_back("key");
p_extensions->push_back("pub");
}
bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
return p_type == "X509Certificate" || p_type == "CryptoKey";
}
String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
return "X509Certificate";
} else if (el == "key" || el == "pub") {
return "CryptoKey";
}
return "";
}
Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Error err;
Ref<X509Certificate> cert = p_resource;
Ref<CryptoKey> key = p_resource;
if (cert.is_valid()) {
err = cert->save(p_path);
} else if (key.is_valid()) {
String el = p_path.get_extension().to_lower();
err = key->save(p_path, el == "pub");
} else {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path));
return OK;
}
void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
if (cert) {
p_extensions->push_back("crt");
}
if (key) {
if (!key->is_public_only()) {
p_extensions->push_back("key");
}
p_extensions->push_back("pub");
}
}
bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
}

View file

@ -1,171 +0,0 @@
/**************************************************************************/
/* crypto.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CRYPTO_H
#define CRYPTO_H
#include "core/crypto/hashing_context.h"
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/ref_counted.h"
class CryptoKey : public Resource {
GDCLASS(CryptoKey, Resource);
protected:
static void _bind_methods();
static CryptoKey *(*_create)(bool p_notify_postinitialize);
public:
static CryptoKey *create(bool p_notify_postinitialize = true);
virtual Error load(const String &p_path, bool p_public_only = false) = 0;
virtual Error save(const String &p_path, bool p_public_only = false) = 0;
virtual String save_to_string(bool p_public_only = false) = 0;
virtual Error load_from_string(const String &p_string_key, bool p_public_only = false) = 0;
virtual bool is_public_only() const = 0;
};
class X509Certificate : public Resource {
GDCLASS(X509Certificate, Resource);
protected:
static void _bind_methods();
static X509Certificate *(*_create)(bool p_notify_postinitialize);
public:
static X509Certificate *create(bool p_notify_postinitialize = true);
virtual Error load(const String &p_path) = 0;
virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
virtual Error save(const String &p_path) = 0;
virtual String save_to_string() = 0;
virtual Error load_from_string(const String &string) = 0;
};
class TLSOptions : public RefCounted {
GDCLASS(TLSOptions, RefCounted);
private:
enum Mode {
MODE_CLIENT = 0,
MODE_CLIENT_UNSAFE = 1,
MODE_SERVER = 2,
};
Mode mode = MODE_CLIENT;
String common_name;
Ref<X509Certificate> trusted_ca_chain;
Ref<X509Certificate> own_certificate;
Ref<CryptoKey> private_key;
protected:
static void _bind_methods();
public:
static Ref<TLSOptions> client(Ref<X509Certificate> p_trusted_chain = Ref<X509Certificate>(), const String &p_common_name_override = String());
static Ref<TLSOptions> client_unsafe(Ref<X509Certificate> p_trusted_chain);
static Ref<TLSOptions> server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate);
String get_common_name_override() const { return common_name; }
Ref<X509Certificate> get_trusted_ca_chain() const { return trusted_ca_chain; }
Ref<X509Certificate> get_own_certificate() const { return own_certificate; }
Ref<CryptoKey> get_private_key() const { return private_key; }
bool is_server() const { return mode == MODE_SERVER; }
bool is_unsafe_client() const { return mode == MODE_CLIENT_UNSAFE; }
};
class HMACContext : public RefCounted {
GDCLASS(HMACContext, RefCounted);
protected:
static void _bind_methods();
static HMACContext *(*_create)(bool p_notify_postinitialize);
public:
static HMACContext *create(bool p_notify_postinitialize = true);
virtual Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) = 0;
virtual Error update(const PackedByteArray &p_data) = 0;
virtual PackedByteArray finish() = 0;
HMACContext() {}
virtual ~HMACContext() {}
};
class Crypto : public RefCounted {
GDCLASS(Crypto, RefCounted);
protected:
static void _bind_methods();
static Crypto *(*_create)(bool p_notify_postinitialize);
static void (*_load_default_certificates)(const String &p_path);
public:
static Crypto *create(bool p_notify_postinitialize = true);
static void load_default_certificates(const String &p_path);
virtual PackedByteArray generate_random_bytes(int p_bytes) = 0;
virtual Ref<CryptoKey> generate_rsa(int p_bytes) = 0;
virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) = 0;
virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) = 0;
virtual bool verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) = 0;
virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) = 0;
virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) = 0;
PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg);
// Compares two PackedByteArrays for equality without leaking timing information in order to prevent timing attacks.
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
bool constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received);
Crypto() {}
};
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
virtual bool handles_type(const String &p_type) const override;
virtual String get_resource_type(const String &p_path) const override;
// Treat certificates as text files, do not generate a `*.{crt,key,pub}.uid` file.
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override { return ResourceUID::INVALID_ID; }
virtual bool has_custom_uid_support() const override { return true; }
};
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
public:
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
virtual bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // CRYPTO_H

View file

@ -1,251 +0,0 @@
/**************************************************************************/
/* crypto_core.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "crypto_core.h"
#include "core/os/os.h"
#include <mbedtls/aes.h>
#include <mbedtls/base64.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/md5.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#if MBEDTLS_VERSION_MAJOR >= 3
#include <mbedtls/compat-2.x.h>
#endif
// RandomGenerator
CryptoCore::RandomGenerator::RandomGenerator() {
entropy = memalloc(sizeof(mbedtls_entropy_context));
mbedtls_entropy_init((mbedtls_entropy_context *)entropy);
mbedtls_entropy_add_source((mbedtls_entropy_context *)entropy, &CryptoCore::RandomGenerator::_entropy_poll, nullptr, 256, MBEDTLS_ENTROPY_SOURCE_STRONG);
ctx = memalloc(sizeof(mbedtls_ctr_drbg_context));
mbedtls_ctr_drbg_init((mbedtls_ctr_drbg_context *)ctx);
}
CryptoCore::RandomGenerator::~RandomGenerator() {
mbedtls_ctr_drbg_free((mbedtls_ctr_drbg_context *)ctx);
memfree(ctx);
mbedtls_entropy_free((mbedtls_entropy_context *)entropy);
memfree(entropy);
}
int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len) {
*r_len = 0;
Error err = OS::get_singleton()->get_entropy(r_buffer, p_len);
ERR_FAIL_COND_V(err, MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
*r_len = p_len;
return 0;
}
Error CryptoCore::RandomGenerator::init() {
int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
if (ret) {
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
}
return OK;
}
Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
return OK;
}
// MD5
CryptoCore::MD5Context::MD5Context() {
ctx = memalloc(sizeof(mbedtls_md5_context));
mbedtls_md5_init((mbedtls_md5_context *)ctx);
}
CryptoCore::MD5Context::~MD5Context() {
mbedtls_md5_free((mbedtls_md5_context *)ctx);
memfree((mbedtls_md5_context *)ctx);
}
Error CryptoCore::MD5Context::start() {
int ret = mbedtls_md5_starts_ret((mbedtls_md5_context *)ctx);
return ret ? FAILED : OK;
}
Error CryptoCore::MD5Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_md5_update_ret((mbedtls_md5_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
Error CryptoCore::MD5Context::finish(unsigned char r_hash[16]) {
int ret = mbedtls_md5_finish_ret((mbedtls_md5_context *)ctx, r_hash);
return ret ? FAILED : OK;
}
// SHA1
CryptoCore::SHA1Context::SHA1Context() {
ctx = memalloc(sizeof(mbedtls_sha1_context));
mbedtls_sha1_init((mbedtls_sha1_context *)ctx);
}
CryptoCore::SHA1Context::~SHA1Context() {
mbedtls_sha1_free((mbedtls_sha1_context *)ctx);
memfree((mbedtls_sha1_context *)ctx);
}
Error CryptoCore::SHA1Context::start() {
int ret = mbedtls_sha1_starts_ret((mbedtls_sha1_context *)ctx);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA1Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_sha1_update_ret((mbedtls_sha1_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA1Context::finish(unsigned char r_hash[20]) {
int ret = mbedtls_sha1_finish_ret((mbedtls_sha1_context *)ctx, r_hash);
return ret ? FAILED : OK;
}
// SHA256
CryptoCore::SHA256Context::SHA256Context() {
ctx = memalloc(sizeof(mbedtls_sha256_context));
mbedtls_sha256_init((mbedtls_sha256_context *)ctx);
}
CryptoCore::SHA256Context::~SHA256Context() {
mbedtls_sha256_free((mbedtls_sha256_context *)ctx);
memfree((mbedtls_sha256_context *)ctx);
}
Error CryptoCore::SHA256Context::start() {
int ret = mbedtls_sha256_starts_ret((mbedtls_sha256_context *)ctx, 0);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA256Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_sha256_update_ret((mbedtls_sha256_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA256Context::finish(unsigned char r_hash[32]) {
int ret = mbedtls_sha256_finish_ret((mbedtls_sha256_context *)ctx, r_hash);
return ret ? FAILED : OK;
}
// AES256
CryptoCore::AESContext::AESContext() {
ctx = memalloc(sizeof(mbedtls_aes_context));
mbedtls_aes_init((mbedtls_aes_context *)ctx);
}
CryptoCore::AESContext::~AESContext() {
mbedtls_aes_free((mbedtls_aes_context *)ctx);
memfree((mbedtls_aes_context *)ctx);
}
Error CryptoCore::AESContext::set_encode_key(const uint8_t *p_key, size_t p_bits) {
int ret = mbedtls_aes_setkey_enc((mbedtls_aes_context *)ctx, p_key, p_bits);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::set_decode_key(const uint8_t *p_key, size_t p_bits) {
int ret = mbedtls_aes_setkey_dec((mbedtls_aes_context *)ctx, p_key, p_bits);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_src, r_dst);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, r_iv, p_src, r_dst);
return ret ? FAILED : OK;
}
Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
return ret ? FAILED : OK;
}
// CryptoCore
String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
int b64len = p_src_len / 3 * 4 + 4 + 1;
Vector<uint8_t> b64buff;
b64buff.resize(b64len);
uint8_t *w64 = b64buff.ptrw();
size_t strlen = 0;
int ret = b64_encode(&w64[0], b64len, &strlen, p_src, p_src_len);
w64[strlen] = 0;
return ret ? String() : (const char *)&w64[0];
}
Error CryptoCore::b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) {
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) {
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]) {
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]) {
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]) {
int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
return ret ? FAILED : OK;
}

View file

@ -1,119 +0,0 @@
/**************************************************************************/
/* crypto_core.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CRYPTO_CORE_H
#define CRYPTO_CORE_H
#include "core/object/ref_counted.h"
class CryptoCore {
public:
class RandomGenerator {
private:
void *entropy = nullptr;
void *ctx = nullptr;
static int _entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len);
public:
RandomGenerator();
~RandomGenerator();
Error init();
Error get_random_bytes(uint8_t *r_buffer, size_t p_bytes);
};
class MD5Context {
private:
void *ctx = nullptr;
public:
MD5Context();
~MD5Context();
Error start();
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[16]);
};
class SHA1Context {
private:
void *ctx = nullptr;
public:
SHA1Context();
~SHA1Context();
Error start();
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[20]);
};
class SHA256Context {
private:
void *ctx = nullptr;
public:
SHA256Context();
~SHA256Context();
Error start();
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[32]);
};
class AESContext {
private:
void *ctx = nullptr;
public:
AESContext();
~AESContext();
Error set_encode_key(const uint8_t *p_key, size_t p_bits);
Error set_decode_key(const uint8_t *p_key, size_t p_bits);
Error encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
Error encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
};
static 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 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]);
};
#endif // CRYPTO_CORE_H

View file

@ -1,134 +0,0 @@
/**************************************************************************/
/* hashing_context.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "hashing_context.h"
#include "core/crypto/crypto_core.h"
Error HashingContext::start(HashType p_type) {
ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
_create_ctx(p_type);
ERR_FAIL_NULL_V(ctx, ERR_UNAVAILABLE);
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->start();
case HASH_SHA1:
return ((CryptoCore::SHA1Context *)ctx)->start();
case HASH_SHA256:
return ((CryptoCore::SHA256Context *)ctx)->start();
}
return ERR_UNAVAILABLE;
}
Error HashingContext::update(const PackedByteArray &p_chunk) {
ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
size_t len = p_chunk.size();
ERR_FAIL_COND_V(len == 0, FAILED);
const uint8_t *r = p_chunk.ptr();
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->update(&r[0], len);
case HASH_SHA1:
return ((CryptoCore::SHA1Context *)ctx)->update(&r[0], len);
case HASH_SHA256:
return ((CryptoCore::SHA256Context *)ctx)->update(&r[0], len);
}
return ERR_UNAVAILABLE;
}
PackedByteArray HashingContext::finish() {
ERR_FAIL_NULL_V(ctx, PackedByteArray());
PackedByteArray out;
Error err = FAILED;
switch (type) {
case HASH_MD5:
out.resize(16);
err = ((CryptoCore::MD5Context *)ctx)->finish(out.ptrw());
break;
case HASH_SHA1:
out.resize(20);
err = ((CryptoCore::SHA1Context *)ctx)->finish(out.ptrw());
break;
case HASH_SHA256:
out.resize(32);
err = ((CryptoCore::SHA256Context *)ctx)->finish(out.ptrw());
break;
}
_delete_ctx();
ERR_FAIL_COND_V(err != OK, PackedByteArray());
return out;
}
void HashingContext::_create_ctx(HashType p_type) {
type = p_type;
switch (type) {
case HASH_MD5:
ctx = memnew(CryptoCore::MD5Context);
break;
case HASH_SHA1:
ctx = memnew(CryptoCore::SHA1Context);
break;
case HASH_SHA256:
ctx = memnew(CryptoCore::SHA256Context);
break;
default:
ctx = nullptr;
}
}
void HashingContext::_delete_ctx() {
switch (type) {
case HASH_MD5:
memdelete((CryptoCore::MD5Context *)ctx);
break;
case HASH_SHA1:
memdelete((CryptoCore::SHA1Context *)ctx);
break;
case HASH_SHA256:
memdelete((CryptoCore::SHA256Context *)ctx);
break;
}
ctx = nullptr;
}
void HashingContext::_bind_methods() {
ClassDB::bind_method(D_METHOD("start", "type"), &HashingContext::start);
ClassDB::bind_method(D_METHOD("update", "chunk"), &HashingContext::update);
ClassDB::bind_method(D_METHOD("finish"), &HashingContext::finish);
BIND_ENUM_CONSTANT(HASH_MD5);
BIND_ENUM_CONSTANT(HASH_SHA1);
BIND_ENUM_CONSTANT(HASH_SHA256);
}
HashingContext::~HashingContext() {
if (ctx != nullptr) {
_delete_ctx();
}
}

View file

@ -1,66 +0,0 @@
/**************************************************************************/
/* hashing_context.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef HASHING_CONTEXT_H
#define HASHING_CONTEXT_H
#include "core/object/ref_counted.h"
class HashingContext : public RefCounted {
GDCLASS(HashingContext, RefCounted);
public:
enum HashType : int32_t {
HASH_MD5,
HASH_SHA1,
HASH_SHA256
};
private:
void *ctx = nullptr;
HashType type = HASH_MD5;
protected:
static void _bind_methods();
void _create_ctx(HashType p_type);
void _delete_ctx();
public:
Error start(HashType p_type);
Error update(const PackedByteArray &p_chunk);
PackedByteArray finish();
HashingContext() {}
~HashingContext();
};
VARIANT_ENUM_CAST(HashingContext::HashType);
#endif // HASHING_CONTEXT_H

View file

@ -1,6 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env.add_source_files(env.core_sources, "*.cpp")

View file

@ -1,183 +0,0 @@
/**************************************************************************/
/* debugger_marshalls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "debugger_marshalls.h"
#include "core/io/marshalls.h"
#define CHECK_SIZE(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 short. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
Array DebuggerMarshalls::ScriptStackDump::serialize() {
Array arr;
arr.push_back(frames.size() * 3);
for (const ScriptLanguage::StackInfo &frame : frames) {
arr.push_back(frame.file);
arr.push_back(frame.line);
arr.push_back(frame.func);
}
return arr;
}
bool DebuggerMarshalls::ScriptStackDump::deserialize(const Array &p_arr) {
CHECK_SIZE(p_arr, 1, "ScriptStackDump");
uint32_t size = p_arr[0];
CHECK_SIZE(p_arr, size, "ScriptStackDump");
int idx = 1;
for (uint32_t i = 0; i < size / 3; i++) {
ScriptLanguage::StackInfo sf;
sf.file = p_arr[idx];
sf.line = p_arr[idx + 1];
sf.func = p_arr[idx + 2];
frames.push_back(sf);
idx += 3;
}
CHECK_END(p_arr, idx, "ScriptStackDump");
return true;
}
Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
Array arr;
arr.push_back(name);
arr.push_back(type);
arr.push_back(value.get_type());
Variant var = value;
if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
var = Variant();
}
int len = 0;
Error err = encode_variant(var, nullptr, len, false);
if (err != OK) {
ERR_PRINT("Failed to encode variant.");
}
if (len > max_size) {
arr.push_back(Variant());
} else {
arr.push_back(var);
}
return arr;
}
bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
name = p_arr[0];
type = p_arr[1];
var_type = p_arr[2];
value = p_arr[3];
CHECK_END(p_arr, 4, "ScriptStackVariable");
return true;
}
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();
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);
arr.push_back(r[i].line);
}
return arr;
}
bool DebuggerMarshalls::OutputError::deserialize(const Array &p_arr) {
CHECK_SIZE(p_arr, 11, "OutputError");
hr = p_arr[0];
min = p_arr[1];
sec = p_arr[2];
msec = p_arr[3];
source_file = p_arr[4];
source_func = p_arr[5];
source_line = p_arr[6];
error = p_arr[7];
error_descr = p_arr[8];
warning = p_arr[9];
unsigned int stack_size = p_arr[10];
CHECK_SIZE(p_arr, stack_size, "OutputError");
int idx = 11;
callstack.resize(stack_size / 3);
ScriptLanguage::StackInfo *w = callstack.ptrw();
for (unsigned int i = 0; i < stack_size / 3; i++) {
w[i].file = p_arr[idx];
w[i].func = p_arr[idx + 1];
w[i].line = p_arr[idx + 2];
idx += 3;
}
CHECK_END(p_arr, idx, "OutputError");
return true;
}
Array DebuggerMarshalls::serialize_key_shortcut(const Ref<Shortcut> &p_shortcut) {
ERR_FAIL_COND_V(p_shortcut.is_null(), Array());
Array keys;
for (const Ref<InputEvent> ev : p_shortcut->get_events()) {
const Ref<InputEventKey> kev = ev;
ERR_CONTINUE(kev.is_null());
if (kev->get_physical_keycode() != Key::NONE) {
keys.push_back(true);
keys.push_back(kev->get_physical_keycode_with_modifiers());
} else {
keys.push_back(false);
keys.push_back(kev->get_keycode_with_modifiers());
}
}
return keys;
}
Ref<Shortcut> DebuggerMarshalls::deserialize_key_shortcut(const Array &p_keys) {
Array key_events;
ERR_FAIL_COND_V(p_keys.size() % 2 != 0, Ref<Shortcut>());
for (int i = 0; i < p_keys.size(); i += 2) {
ERR_CONTINUE(p_keys[i].get_type() != Variant::BOOL);
ERR_CONTINUE(p_keys[i + 1].get_type() != Variant::INT);
key_events.push_back(InputEventKey::create_reference((Key)p_keys[i + 1].operator int(), p_keys[i].operator bool()));
}
if (key_events.is_empty()) {
return Ref<Shortcut>();
}
Ref<Shortcut> shortcut;
shortcut.instantiate();
shortcut->set_events(key_events);
return shortcut;
}

View file

@ -1,77 +0,0 @@
/**************************************************************************/
/* debugger_marshalls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DEBUGGER_MARSHALLS_H
#define DEBUGGER_MARSHALLS_H
#include "core/input/shortcut.h"
#include "core/object/script_language.h"
struct DebuggerMarshalls {
struct ScriptStackVariable {
String name;
Variant value;
int type = -1;
int var_type = -1;
Array serialize(int max_size = 1 << 20); // 1 MiB default.
bool deserialize(const Array &p_arr);
};
struct ScriptStackDump {
List<ScriptLanguage::StackInfo> frames;
ScriptStackDump() {}
Array serialize();
bool deserialize(const Array &p_arr);
};
struct OutputError {
int hr = -1;
int min = -1;
int sec = -1;
int msec = -1;
String source_file;
String source_func;
int source_line = -1;
String error;
String error_descr;
bool warning = false;
Vector<ScriptLanguage::StackInfo> callstack;
Array serialize();
bool deserialize(const Array &p_arr);
};
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

@ -1,203 +0,0 @@
/**************************************************************************/
/* engine_debugger.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "engine_debugger.h"
#include "core/debugger/local_debugger.h"
#include "core/debugger/remote_debugger.h"
#include "core/debugger/remote_debugger_peer.h"
#include "core/debugger/script_debugger.h"
#include "core/os/os.h"
EngineDebugger *EngineDebugger::singleton = nullptr;
ScriptDebugger *EngineDebugger::script_debugger = nullptr;
HashMap<StringName, EngineDebugger::Profiler> EngineDebugger::profilers;
HashMap<StringName, EngineDebugger::Capture> EngineDebugger::captures;
HashMap<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols;
void (*EngineDebugger::allow_focus_steal_fn)();
void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
ERR_FAIL_COND_MSG(profilers.has(p_name), vformat("Profiler already registered: '%s'.", p_name));
profilers.insert(p_name, p_func);
}
void EngineDebugger::unregister_profiler(const StringName &p_name) {
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name));
Profiler &p = profilers[p_name];
if (p.active && p.toggle) {
p.toggle(p.data, false, Array());
p.active = false;
}
profilers.erase(p_name);
}
void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) {
ERR_FAIL_COND_MSG(captures.has(p_name), vformat("Capture already registered: '%s'.", p_name));
captures.insert(p_name, p_func);
}
void EngineDebugger::unregister_message_capture(const StringName &p_name) {
ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name));
captures.erase(p_name);
}
void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
ERR_FAIL_COND_MSG(protocols.has(p_protocol), vformat("Protocol handler already registered: '%s'.", p_protocol));
protocols.insert(p_protocol, p_func);
}
void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't change profiler state, no profiler: '%s'.", p_name));
Profiler &p = profilers[p_name];
if (p.toggle) {
p.toggle(p.data, p_enabled, p_opts);
}
p.active = p_enabled;
}
void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't add frame data, no profiler: '%s'.", p_name));
Profiler &p = profilers[p_name];
if (p.add) {
p.add(p.data, p_data);
}
}
bool EngineDebugger::is_profiling(const StringName &p_name) {
return profilers.has(p_name) && profilers[p_name].active;
}
bool EngineDebugger::has_profiler(const StringName &p_name) {
return profilers.has(p_name);
}
bool EngineDebugger::has_capture(const StringName &p_name) {
return captures.has(p_name);
}
Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) {
r_captured = false;
ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, vformat("Capture not registered: '%s'.", p_name));
const Capture &cap = captures[p_name];
return cap.capture(cap.data, p_msg, p_args, r_captured);
}
void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time) {
frame_time = USEC_TO_SEC(p_frame_ticks);
process_time = USEC_TO_SEC(p_process_ticks);
physics_time = USEC_TO_SEC(p_physics_ticks);
physics_frame_time = p_physics_frame_time;
// Notify tick to running profilers
for (KeyValue<StringName, Profiler> &E : profilers) {
Profiler &p = E.value;
if (!p.active || !p.tick) {
continue;
}
p.tick(p.data, frame_time, process_time, physics_time, physics_frame_time);
}
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)()) {
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
if (p_uri.is_empty()) {
return;
}
if (p_uri == "local://") {
singleton = memnew(LocalDebugger);
script_debugger = memnew(ScriptDebugger);
// Tell the OS that we want to handle termination signals.
OS::get_singleton()->initialize_debugging();
} else if (p_uri.contains("://")) {
const String proto = p_uri.substr(0, p_uri.find("://") + 3);
if (!protocols.has(proto)) {
return;
}
RemoteDebuggerPeer *peer = protocols[proto](p_uri);
if (!peer) {
return;
}
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());
singleton->send_message("set_pid", msg);
}
if (!singleton) {
return;
}
// There is a debugger, parse breakpoints.
ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger();
singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints);
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));
}
allow_focus_steal_fn = p_allow_focus_steal_fn;
}
void EngineDebugger::deinitialize() {
if (singleton) {
// Stop all profilers
for (const KeyValue<StringName, Profiler> &E : profilers) {
if (E.value.active) {
singleton->profiler_enable(E.key, false);
}
}
// Flush any remaining message
singleton->poll_events(false);
memdelete(singleton);
singleton = nullptr;
}
// Clear profilers/captures/protocol handlers.
profilers.clear();
captures.clear();
protocols.clear();
}
EngineDebugger::~EngineDebugger() {
if (script_debugger) {
memdelete(script_debugger);
}
script_debugger = nullptr;
singleton = nullptr;
}

View file

@ -1,144 +0,0 @@
/**************************************************************************/
/* engine_debugger.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_DEBUGGER_H
#define ENGINE_DEBUGGER_H
#include "core/string/string_name.h"
#include "core/string/ustring.h"
#include "core/templates/hash_map.h"
#include "core/templates/vector.h"
#include "core/variant/array.h"
class RemoteDebuggerPeer;
class ScriptDebugger;
class EngineDebugger {
public:
typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts);
typedef void (*ProfilingTick)(void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr);
typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri);
class Profiler {
friend class EngineDebugger;
ProfilingToggle toggle = nullptr;
ProfilingAdd add = nullptr;
ProfilingTick tick = nullptr;
void *data = nullptr;
bool active = false;
public:
Profiler() {}
Profiler(void *p_data, ProfilingToggle p_toggle, ProfilingAdd p_add, ProfilingTick p_tick) {
data = p_data;
toggle = p_toggle;
add = p_add;
tick = p_tick;
}
};
class Capture {
friend class EngineDebugger;
CaptureFunc capture = nullptr;
void *data = nullptr;
public:
Capture() {}
Capture(void *p_data, CaptureFunc p_capture) {
data = p_data;
capture = p_capture;
}
};
private:
double frame_time = 0.0;
double process_time = 0.0;
double physics_time = 0.0;
double physics_frame_time = 0.0;
uint32_t poll_every = 0;
protected:
static EngineDebugger *singleton;
static ScriptDebugger *script_debugger;
static HashMap<StringName, Profiler> profilers;
static HashMap<StringName, Capture> captures;
static HashMap<String, CreatePeerFunc> protocols;
static void (*allow_focus_steal_fn)();
public:
_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
_FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
_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 deinitialize();
static void register_profiler(const StringName &p_name, const Profiler &p_profiler);
static void unregister_profiler(const StringName &p_name);
static bool is_profiling(const StringName &p_name);
static bool has_profiler(const StringName &p_name);
static void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
static void register_message_capture(const StringName &p_name, Capture p_func);
static void unregister_message_capture(const StringName &p_name);
static bool has_capture(const StringName &p_name);
static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func);
void iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time);
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured);
void line_poll() {
// The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught.
if (unlikely(poll_every % 2048) == 0) {
poll_events(false);
}
poll_every++;
}
virtual void poll_events(bool p_is_idle) {}
virtual void send_message(const String &p_msg, const Array &p_data) = 0;
virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) = 0;
virtual void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false) = 0;
virtual ~EngineDebugger();
};
#endif // ENGINE_DEBUGGER_H

View file

@ -1,82 +0,0 @@
/**************************************************************************/
/* engine_profiler.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "engine_profiler.h"
#include "core/debugger/engine_debugger.h"
void EngineProfiler::_bind_methods() {
GDVIRTUAL_BIND(_toggle, "enable", "options");
GDVIRTUAL_BIND(_add_frame, "data");
GDVIRTUAL_BIND(_tick, "frame_time", "process_time", "physics_time", "physics_frame_time");
}
void EngineProfiler::toggle(bool p_enable, const Array &p_array) {
GDVIRTUAL_CALL(_toggle, p_enable, p_array);
}
void EngineProfiler::add(const Array &p_data) {
GDVIRTUAL_CALL(_add_frame, p_data);
}
void EngineProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
GDVIRTUAL_CALL(_tick, p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
}
Error EngineProfiler::bind(const String &p_name) {
ERR_FAIL_COND_V(is_bound(), ERR_ALREADY_IN_USE);
EngineDebugger::Profiler prof(
this,
[](void *p_user, bool p_enable, const Array &p_opts) {
static_cast<EngineProfiler *>(p_user)->toggle(p_enable, p_opts);
},
[](void *p_user, const Array &p_data) {
static_cast<EngineProfiler *>(p_user)->add(p_data);
},
[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
static_cast<EngineProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
});
registration = p_name;
EngineDebugger::register_profiler(p_name, prof);
return OK;
}
Error EngineProfiler::unbind() {
ERR_FAIL_COND_V(!is_bound(), ERR_UNCONFIGURED);
EngineDebugger::unregister_profiler(registration);
registration.clear();
return OK;
}
EngineProfiler::~EngineProfiler() {
if (is_bound()) {
unbind();
}
}

View file

@ -1,63 +0,0 @@
/**************************************************************************/
/* engine_profiler.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ENGINE_PROFILER_H
#define ENGINE_PROFILER_H
#include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h"
class EngineProfiler : public RefCounted {
GDCLASS(EngineProfiler, RefCounted);
private:
String registration;
protected:
static void _bind_methods();
public:
virtual void toggle(bool p_enable, const Array &p_opts);
virtual void add(const Array &p_data);
virtual void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
Error bind(const String &p_name);
Error unbind();
bool is_bound() const { return registration.length() > 0; }
GDVIRTUAL2(_toggle, bool, Array);
GDVIRTUAL1(_add_frame, Array);
GDVIRTUAL4(_tick, double, double, double, double);
EngineProfiler() {}
virtual ~EngineProfiler();
};
#endif // ENGINE_PROFILER_H

View file

@ -1,390 +0,0 @@
/**************************************************************************/
/* local_debugger.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "local_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/os/os.h"
struct LocalDebugger::ScriptsProfiler {
struct ProfileInfoSort {
bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const {
return A.total_time > B.total_time;
}
};
double frame_time = 0;
uint64_t idle_accum = 0;
Vector<ScriptLanguage::ProfilingInfo> pinfo;
void toggle(bool p_enable, const Array &p_opts) {
if (p_enable) {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->profiling_start();
}
print_line("BEGIN PROFILING");
pinfo.resize(32768);
} else {
_print_frame_data(true);
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->profiling_stop();
}
}
}
void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
frame_time = p_frame_time;
_print_frame_data(false);
}
void _print_frame_data(bool p_accumulated) {
uint64_t diff = OS::get_singleton()->get_ticks_usec() - idle_accum;
if (!p_accumulated && diff < 1000000) { //show every one second
return;
}
idle_accum = OS::get_singleton()->get_ticks_usec();
int ofs = 0;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
if (p_accumulated) {
ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo.write[ofs], pinfo.size() - ofs);
} else {
ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo.write[ofs], pinfo.size() - ofs);
}
}
SortArray<ScriptLanguage::ProfilingInfo, ProfileInfoSort> sort;
sort.sort(pinfo.ptrw(), ofs);
// compute total script frame time
uint64_t script_time_us = 0;
for (int i = 0; i < ofs; i++) {
script_time_us += pinfo[i].self_time;
}
double script_time = USEC_TO_SEC(script_time_us);
double total_time = p_accumulated ? script_time : frame_time;
if (!p_accumulated) {
print_line("FRAME: total: " + rtos(total_time) + " script: " + rtos(script_time) + "/" + itos(script_time * 100 / total_time) + " %");
} else {
print_line("ACCUMULATED: total: " + rtos(total_time));
}
for (int i = 0; i < ofs; i++) {
print_line(itos(i) + ":" + pinfo[i].signature);
double tt = USEC_TO_SEC(pinfo[i].total_time);
double st = USEC_TO_SEC(pinfo[i].self_time);
print_line("\ttotal: " + rtos(tt) + "/" + itos(tt * 100 / total_time) + " % \tself: " + rtos(st) + "/" + itos(st * 100 / total_time) + " % tcalls: " + itos(pinfo[i].call_count));
}
}
ScriptsProfiler() {
idle_accum = OS::get_singleton()->get_ticks_usec();
}
};
void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
ScriptLanguage *script_lang = script_debugger->get_break_language();
if (!target_function.is_empty()) {
String current_function = script_lang->debug_get_stack_level_function(0);
if (current_function != target_function) {
script_debugger->set_depth(0);
script_debugger->set_lines_left(1);
return;
}
target_function = "";
}
print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
print_line("*Frame " + itos(0) + " - " + script_lang->debug_get_stack_level_source(0) + ":" + itos(script_lang->debug_get_stack_level_line(0)) + " in function '" + script_lang->debug_get_stack_level_function(0) + "'");
print_line("Enter \"help\" for assistance.");
int current_frame = 0;
int total_frames = script_lang->debug_get_stack_level_count();
while (true) {
OS::get_singleton()->print("debug> ");
String line = OS::get_singleton()->get_stdin_string().strip_edges();
// Cache options
String variable_prefix = options["variable_prefix"];
if (line.is_empty() && !feof(stdin)) {
print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
print_line("Enter \"help\" for assistance.");
} else if (line == "c" || line == "continue") {
break;
} else if (line == "bt" || line == "breakpoint") {
for (int i = 0; i < total_frames; i++) {
String cfi = (current_frame == i) ? "*" : " "; //current frame indicator
print_line(cfi + "Frame " + itos(i) + " - " + script_lang->debug_get_stack_level_source(i) + ":" + itos(script_lang->debug_get_stack_level_line(i)) + " in function '" + script_lang->debug_get_stack_level_function(i) + "'");
}
} else if (line.begins_with("fr") || line.begins_with("frame")) {
if (line.get_slice_count(" ") == 1) {
print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
} else {
int frame = line.get_slicec(' ', 1).to_int();
if (frame < 0 || frame >= total_frames) {
print_line("Error: Invalid frame.");
} else {
current_frame = frame;
print_line("*Frame " + itos(frame) + " - " + script_lang->debug_get_stack_level_source(frame) + ":" + itos(script_lang->debug_get_stack_level_line(frame)) + " in function '" + script_lang->debug_get_stack_level_function(frame) + "'");
}
}
} else if (line.begins_with("set")) {
if (line.get_slice_count(" ") == 1) {
for (const KeyValue<String, String> &E : options) {
print_line("\t" + E.key + "=" + E.value);
}
} else {
String key_value = line.get_slicec(' ', 1);
int value_pos = key_value.find_char('=');
if (value_pos < 0) {
print_line("Error: Invalid set format. Use: set key=value");
} else {
String key = key_value.left(value_pos);
if (!options.has(key)) {
print_line("Error: Unknown option " + key);
} else {
// Allow explicit tab character
String value = key_value.substr(value_pos + 1).replace("\\t", "\t");
options[key] = value;
}
}
}
} else if (line == "lv" || line == "locals") {
List<String> locals;
List<Variant> values;
script_lang->debug_get_stack_level_locals(current_frame, &locals, &values);
print_variables(locals, values, variable_prefix);
} else if (line == "gv" || line == "globals") {
List<String> globals;
List<Variant> values;
script_lang->debug_get_globals(&globals, &values);
print_variables(globals, values, variable_prefix);
} else if (line == "mv" || line == "members") {
List<String> members;
List<Variant> values;
script_lang->debug_get_stack_level_members(current_frame, &members, &values);
print_variables(members, values, variable_prefix);
} else if (line.begins_with("p") || line.begins_with("print")) {
if (line.find_char(' ') < 0) {
print_line("Usage: print <expression>");
} else {
String expr = line.split(" ", true, 1)[1];
String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
print_line(res);
}
} else if (line == "s" || line == "step") {
script_debugger->set_depth(-1);
script_debugger->set_lines_left(1);
break;
} else if (line == "n" || line == "next") {
script_debugger->set_depth(0);
script_debugger->set_lines_left(1);
break;
} else if (line == "fin" || line == "finish") {
String current_function = script_lang->debug_get_stack_level_function(0);
for (int i = 0; i < total_frames; i++) {
target_function = script_lang->debug_get_stack_level_function(i);
if (target_function != current_function) {
script_debugger->set_depth(0);
script_debugger->set_lines_left(1);
return;
}
}
print_line("Error: Reached last frame.");
target_function = "";
} 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) {
print_line("No Breakpoints.");
continue;
}
print_line("Breakpoint(s): " + itos(breakpoints.size()));
for (const KeyValue<int, HashSet<StringName>> &E : breakpoints) {
print_line("\t" + String(*E.value.begin()) + ":" + itos(E.key));
}
} else {
Pair<String, int> breakpoint = to_breakpoint(line);
String source = breakpoint.first;
int linenr = breakpoint.second;
if (source.is_empty()) {
continue;
}
script_debugger->insert_breakpoint(linenr, source);
print_line("Added breakpoint at " + source + ":" + itos(linenr));
}
} else if (line == "q" || line == "quit" ||
(line.is_empty() && feof(stdin))) {
// Do not stop again on quit
script_debugger->clear_breakpoints();
script_debugger->set_depth(-1);
script_debugger->set_lines_left(-1);
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
if (main_loop->get_class() == "SceneTree") {
main_loop->call("quit");
}
break;
} else if (line.begins_with("delete")) {
if (line.get_slice_count(" ") <= 1) {
script_debugger->clear_breakpoints();
} else {
Pair<String, int> breakpoint = to_breakpoint(line);
String source = breakpoint.first;
int linenr = breakpoint.second;
if (source.is_empty()) {
continue;
}
script_debugger->remove_breakpoint(linenr, source);
print_line("Removed breakpoint at " + source + ":" + itos(linenr));
}
} else if (line == "h" || line == "help") {
print_line("Built-In Debugger command list:\n");
print_line("\tc,continue\t\t Continue execution.");
print_line("\tbt,backtrace\t\t Show stack trace (frames).");
print_line("\tfr,frame <frame>:\t Change current frame.");
print_line("\tlv,locals\t\t Show local variables for current frame.");
print_line("\tmv,members\t\t Show member variables for \"this\" in frame.");
print_line("\tgv,globals\t\t Show global variables.");
print_line("\tp,print <expr>\t\t Execute and print variable in expression.");
print_line("\ts,step\t\t\t Step to next line.");
print_line("\tn,next\t\t\t Next line.");
print_line("\tfin,finish\t\t Step out of current frame.");
print_line("\tbr,break [source:line]\t List all breakpoints or place a breakpoint.");
print_line("\tdelete [source:line]:\t Delete one/all breakpoints.");
print_line("\tset [key=value]:\t List all options, or set one.");
print_line("\tq,quit\t\t\t Quit application.");
} else {
print_line("Error: Invalid command, enter \"help\" for assistance.");
}
}
}
void LocalDebugger::print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix) {
String value;
Vector<String> value_lines;
const List<Variant>::Element *V = values.front();
for (const String &E : names) {
value = String(V->get());
if (variable_prefix.is_empty()) {
print_line(E + ": " + String(V->get()));
} else {
print_line(E + ":");
value_lines = value.split("\n");
for (int i = 0; i < value_lines.size(); ++i) {
print_line(variable_prefix + value_lines[i]);
}
}
V = V->next();
}
}
Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
String breakpoint_part = p_line.get_slicec(' ', 1);
Pair<String, int> breakpoint;
int last_colon = breakpoint_part.rfind_char(':');
if (last_colon < 0) {
print_line("Error: Invalid breakpoint format. Expected [source:line]");
return breakpoint;
}
breakpoint.first = script_debugger->breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges());
breakpoint.second = breakpoint_part.substr(last_colon).strip_edges().to_int();
return breakpoint;
}
void LocalDebugger::send_message(const String &p_message, const Array &p_args) {
// This needs to be cleaned up entirely.
// print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args)));
}
void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'");
}
LocalDebugger::LocalDebugger() {
options["variable_prefix"] = "";
// Bind scripts profiler.
scripts_profiler = memnew(ScriptsProfiler);
Profiler scr_prof(
scripts_profiler,
[](void *p_user, bool p_enable, const Array &p_opts) {
static_cast<ScriptsProfiler *>(p_user)->toggle(p_enable, p_opts);
},
nullptr,
[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
static_cast<ScriptsProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
});
register_profiler("scripts", scr_prof);
}
LocalDebugger::~LocalDebugger() {
unregister_profiler("scripts");
if (scripts_profiler) {
memdelete(scripts_profiler);
}
}

View file

@ -1,59 +0,0 @@
/**************************************************************************/
/* local_debugger.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef LOCAL_DEBUGGER_H
#define LOCAL_DEBUGGER_H
#include "core/debugger/engine_debugger.h"
#include "core/object/script_language.h"
#include "core/templates/list.h"
class LocalDebugger : public EngineDebugger {
private:
struct ScriptsProfiler;
ScriptsProfiler *scripts_profiler = nullptr;
String target_function;
HashMap<String, String> options;
Pair<String, int> to_breakpoint(const String &p_line);
void print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix);
public:
void debug(bool p_can_continue, bool p_is_error_breakpoint);
void send_message(const String &p_message, const Array &p_args);
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
LocalDebugger();
~LocalDebugger();
};
#endif // LOCAL_DEBUGGER_H

View file

@ -1,736 +0,0 @@
/**************************************************************************/
/* remote_debugger.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "remote_debugger.h"
#include "core/config/project_settings.h"
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/engine_profiler.h"
#include "core/debugger/script_debugger.h"
#include "core/input/input.h"
#include "core/io/resource_loader.h"
#include "core/math/expression.h"
#include "core/object/script_language.h"
#include "core/os/os.h"
#include "servers/display_server.h"
class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
Object *performance = nullptr;
int last_perf_time = 0;
uint64_t last_monitor_modification_time = 0;
public:
void toggle(bool p_enable, const Array &p_opts) {}
void add(const Array &p_data) {}
void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
if (!performance) {
return;
}
uint64_t pt = OS::get_singleton()->get_ticks_msec();
if (pt - last_perf_time < 1000) {
return;
}
last_perf_time = pt;
Array custom_monitor_names = performance->call("get_custom_monitor_names");
uint64_t monitor_modification_time = performance->call("get_monitor_modification_time");
if (monitor_modification_time > last_monitor_modification_time) {
last_monitor_modification_time = monitor_modification_time;
EngineDebugger::get_singleton()->send_message("performance:profile_names", custom_monitor_names);
}
int max = performance->get("MONITOR_MAX");
Array arr;
arr.resize(max + custom_monitor_names.size());
for (int i = 0; i < max; i++) {
arr[i] = performance->call("get_monitor", i);
}
for (int i = 0; i < custom_monitor_names.size(); i++) {
Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]);
if (!monitor_value.is_num()) {
ERR_PRINT(vformat("Value of custom monitor '%s' is not a number.", String(custom_monitor_names[i])));
arr[i + max] = Variant();
} else {
arr[i + max] = monitor_value;
}
}
EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr);
}
explicit PerformanceProfiler(Object *p_performance) {
performance = p_performance;
}
};
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);
Error err = peer->put_message(msg);
if (err != OK) {
n_messages_dropped++;
}
return err;
}
void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
if (p_type == ERR_HANDLER_SCRIPT) {
return; //ignore script errors, those go through debugger
}
RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive errors during flush.
return;
}
Vector<ScriptLanguage::StackInfo> si;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
si = ScriptServer::get_language(i)->debug_get_current_stack_info();
if (si.size()) {
break;
}
}
// send_error will lock internally.
rd->script_debugger->send_error(String::utf8(p_func), String::utf8(p_file), p_line, String::utf8(p_err), String::utf8(p_descr), p_editor_notify, p_type, si);
}
void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich) {
RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush.
return;
}
String s = p_string;
int allowed_chars = MIN(MAX(rd->max_chars_per_second - rd->char_count, 0), s.length());
if (allowed_chars == 0 && s.length() > 0) {
return;
}
if (allowed_chars < s.length()) {
s = s.substr(0, allowed_chars);
}
MutexLock lock(rd->mutex);
rd->char_count += allowed_chars;
bool overflowed = rd->char_count >= rd->max_chars_per_second;
if (rd->is_peer_connected()) {
if (overflowed) {
s += "[...]";
}
OutputString output_string;
output_string.message = s;
if (p_error) {
output_string.type = MESSAGE_TYPE_ERROR;
} else if (p_rich) {
output_string.type = MESSAGE_TYPE_LOG_RICH;
} else {
output_string.type = MESSAGE_TYPE_LOG;
}
rd->output_strings.push_back(output_string);
if (overflowed) {
output_string.message = "[output overflow, print less text!]";
output_string.type = MESSAGE_TYPE_ERROR;
rd->output_strings.push_back(output_string);
}
}
}
RemoteDebugger::ErrorMessage RemoteDebugger::_create_overflow_error(const String &p_what, const String &p_descr) {
ErrorMessage oe;
oe.error = p_what;
oe.error_descr = p_descr;
oe.warning = false;
uint64_t time = OS::get_singleton()->get_ticks_msec();
oe.hr = time / 3600000;
oe.min = (time / 60000) % 60;
oe.sec = (time / 1000) % 60;
oe.msec = time % 1000;
return oe;
}
void RemoteDebugger::flush_output() {
MutexLock lock(mutex);
flush_thread = Thread::get_caller_id();
flushing = true;
if (!is_peer_connected()) {
return;
}
if (n_messages_dropped > 0) {
ErrorMessage err_msg = _create_overflow_error("TOO_MANY_MESSAGES", "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped. Profiling might misbheave, try raising 'network/limits/debugger/max_queued_messages' in project setting.");
if (_put_msg("error", err_msg.serialize()) == OK) {
n_messages_dropped = 0;
}
}
if (output_strings.size()) {
// Join output strings so we generate less messages.
Vector<String> joined_log_strings;
Vector<String> strings;
Vector<int> types;
for (const OutputString &output_string : output_strings) {
if (output_string.type == MESSAGE_TYPE_ERROR) {
if (!joined_log_strings.is_empty()) {
strings.push_back(String("\n").join(joined_log_strings));
types.push_back(MESSAGE_TYPE_LOG);
joined_log_strings.clear();
}
strings.push_back(output_string.message);
types.push_back(MESSAGE_TYPE_ERROR);
} else if (output_string.type == MESSAGE_TYPE_LOG_RICH) {
if (!joined_log_strings.is_empty()) {
strings.push_back(String("\n").join(joined_log_strings));
types.push_back(MESSAGE_TYPE_LOG_RICH);
joined_log_strings.clear();
}
strings.push_back(output_string.message);
types.push_back(MESSAGE_TYPE_LOG_RICH);
} else {
joined_log_strings.push_back(output_string.message);
}
}
if (!joined_log_strings.is_empty()) {
strings.push_back(String("\n").join(joined_log_strings));
types.push_back(MESSAGE_TYPE_LOG);
}
Array arr;
arr.push_back(strings);
arr.push_back(types);
_put_msg("output", arr);
output_strings.clear();
}
while (errors.size()) {
ErrorMessage oe = errors.front()->get();
_put_msg("error", oe.serialize());
errors.pop_front();
}
// Update limits
uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000;
if (ticks - last_reset > 1000) {
last_reset = ticks;
char_count = 0;
err_count = 0;
n_errors_dropped = 0;
warn_count = 0;
n_warnings_dropped = 0;
}
flushing = false;
}
void RemoteDebugger::send_message(const String &p_message, const Array &p_args) {
MutexLock lock(mutex);
if (is_peer_connected()) {
_put_msg(p_message, p_args);
}
}
void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
ErrorMessage oe;
oe.error = p_err;
oe.error_descr = p_descr;
oe.source_file = p_file;
oe.source_line = p_line;
oe.source_func = p_func;
oe.warning = p_type == ERR_HANDLER_WARNING;
uint64_t time = OS::get_singleton()->get_ticks_msec();
oe.hr = time / 3600000;
oe.min = (time / 60000) % 60;
oe.sec = (time / 1000) % 60;
oe.msec = time % 1000;
oe.callstack.append_array(script_debugger->get_error_stack_info());
if (flushing && Thread::get_caller_id() == flush_thread) { // Can't handle recursive errors during flush.
return;
}
MutexLock lock(mutex);
if (oe.warning) {
warn_count++;
} else {
err_count++;
}
if (is_peer_connected()) {
if (oe.warning) {
if (warn_count > max_warnings_per_second) {
n_warnings_dropped++;
if (n_warnings_dropped == 1) {
// Only print one message about dropping per second
ErrorMessage overflow = _create_overflow_error("TOO_MANY_WARNINGS", "Too many warnings! Ignoring warnings for up to 1 second.");
errors.push_back(overflow);
}
} else {
errors.push_back(oe);
}
} else {
if (err_count > max_errors_per_second) {
n_errors_dropped++;
if (n_errors_dropped == 1) {
// Only print one message about dropping per second
ErrorMessage overflow = _create_overflow_error("TOO_MANY_ERRORS", "Too many errors! Ignoring errors for up to 1 second.");
errors.push_back(overflow);
}
} else {
errors.push_back(oe);
}
}
}
}
void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type) {
DebuggerMarshalls::ScriptStackVariable stvar;
List<String>::Element *E = p_names.front();
List<Variant>::Element *F = p_vals.front();
while (E) {
stvar.name = E->get();
stvar.value = F->get();
stvar.type = p_type;
send_message("stack_frame_var", stvar.serialize());
E = E->next();
F = F->next();
}
}
Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
const int idx = p_msg.find_char(':');
r_captured = false;
if (idx < 0) { // No prefix, unknown message.
return OK;
}
const String cap = p_msg.substr(0, idx);
if (!has_capture(cap)) {
return ERR_UNAVAILABLE; // Unknown message...
}
const String msg = p_msg.substr(idx + 1);
return capture_parse(cap, msg, p_data, r_captured);
}
void RemoteDebugger::_poll_messages() {
MutexLock mutex_lock(mutex);
peer->poll();
while (peer->has_message()) {
Array cmd = peer->get_message();
ERR_CONTINUE(cmd.size() != 3);
ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
ERR_CONTINUE(cmd[1].get_type() != Variant::INT);
ERR_CONTINUE(cmd[2].get_type() != Variant::ARRAY);
Thread::ID thread = cmd[1];
if (!messages.has(thread)) {
continue; // This thread is not around to receive the messages
}
Message msg;
msg.message = cmd[0];
msg.data = cmd[2];
messages[thread].push_back(msg);
}
}
bool RemoteDebugger::_has_messages() {
MutexLock mutex_lock(mutex);
return messages.has(Thread::get_caller_id()) && !messages[Thread::get_caller_id()].is_empty();
}
Array RemoteDebugger::_get_message() {
MutexLock mutex_lock(mutex);
ERR_FAIL_COND_V(!messages.has(Thread::get_caller_id()), Array());
List<Message> &message_list = messages[Thread::get_caller_id()];
ERR_FAIL_COND_V(message_list.is_empty(), Array());
Array msg;
msg.resize(2);
msg[0] = message_list.front()->get().message;
msg[1] = message_list.front()->get().data;
message_list.pop_front();
return msg;
}
void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
//this function is called when there is a debugger break (bug on script)
//or when execution is paused from editor
{
MutexLock lock(mutex);
// Tests that require mutex.
if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) {
return;
}
ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
if (!peer->can_block()) {
return; // Peer does not support blocking IO. We could at least send the error though.
}
}
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();
}
send_message("debug_enter", msg);
Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
if (Thread::get_caller_id() == Thread::get_main_id()) {
mouse_mode = Input::get_singleton()->get_mouse_mode();
if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
}
} else {
MutexLock mutex_lock(mutex);
messages.insert(Thread::get_caller_id(), List<Message>());
}
while (is_peer_connected()) {
flush_output();
_poll_messages();
if (_has_messages()) {
Array cmd = _get_message();
ERR_CONTINUE(cmd.size() != 2);
ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
ERR_CONTINUE(cmd[1].get_type() != Variant::ARRAY);
String command = cmd[0];
Array data = cmd[1];
if (command == "step") {
script_debugger->set_depth(-1);
script_debugger->set_lines_left(1);
break;
} else if (command == "next") {
script_debugger->set_depth(0);
script_debugger->set_lines_left(1);
break;
} else if (command == "continue") {
script_debugger->set_depth(-1);
script_debugger->set_lines_left(-1);
break;
} else if (command == "break") {
ERR_PRINT("Got break when already broke!");
break;
} else if (command == "get_stack_dump") {
DebuggerMarshalls::ScriptStackDump dump;
int slc = script_lang->debug_get_stack_level_count();
for (int i = 0; i < slc; i++) {
ScriptLanguage::StackInfo frame;
frame.file = script_lang->debug_get_stack_level_source(i);
frame.line = script_lang->debug_get_stack_level_line(i);
frame.func = script_lang->debug_get_stack_level_function(i);
dump.frames.push_back(frame);
}
send_message("stack_dump", dump.serialize());
} else if (command == "get_stack_frame_vars") {
ERR_FAIL_COND(data.size() != 1);
ERR_FAIL_NULL(script_lang);
int lv = data[0];
List<String> members;
List<Variant> member_vals;
if (ScriptInstance *inst = script_lang->debug_get_stack_level_instance(lv)) {
members.push_back("self");
member_vals.push_back(inst->get_owner());
}
script_lang->debug_get_stack_level_members(lv, &members, &member_vals);
ERR_FAIL_COND(members.size() != member_vals.size());
List<String> locals;
List<Variant> local_vals;
script_lang->debug_get_stack_level_locals(lv, &locals, &local_vals);
ERR_FAIL_COND(locals.size() != local_vals.size());
List<String> globals;
List<Variant> globals_vals;
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());
send_message("stack_frame_vars", var_size);
_send_stack_vars(locals, local_vals, 0);
_send_stack_vars(members, member_vals, 1);
_send_stack_vars(globals, globals_vals, 2);
} else if (command == "reload_scripts") {
script_paths_to_reload = data;
} else if (command == "reload_all_scripts") {
reload_all_scripts = true;
} else if (command == "breakpoint") {
ERR_FAIL_COND(data.size() < 3);
bool set = data[2];
if (set) {
script_debugger->insert_breakpoint(data[1], data[0]);
} else {
script_debugger->remove_breakpoint(data[1], data[0]);
}
} else if (command == "set_skip_breakpoints") {
ERR_FAIL_COND(data.is_empty());
script_debugger->set_skip_breakpoints(data[0]);
} else if (command == "evaluate") {
String expression_str = data[0];
int frame = data[1];
ScriptInstance *breaked_instance = script_debugger->get_break_language()->debug_get_stack_level_instance(frame);
if (!breaked_instance) {
break;
}
List<String> locals;
List<Variant> local_vals;
script_debugger->get_break_language()->debug_get_stack_level_locals(frame, &locals, &local_vals);
ERR_FAIL_COND(locals.size() != local_vals.size());
PackedStringArray locals_vector;
for (const String &S : locals) {
locals_vector.append(S);
}
Array local_vals_array;
for (const Variant &V : local_vals) {
local_vals_array.append(V);
}
Expression expression;
expression.parse(expression_str, locals_vector);
const Variant return_val = expression.execute(local_vals_array, breaked_instance->get_owner());
DebuggerMarshalls::ScriptStackVariable stvar;
stvar.name = expression_str;
stvar.value = return_val;
stvar.type = 3;
send_message("evaluation_return", stvar.serialize());
} else {
bool captured = false;
ERR_CONTINUE(_try_capture(command, data, captured) != OK);
if (!captured) {
WARN_PRINT(vformat("Unknown message received from debugger: %s.", command));
}
}
} else {
OS::get_singleton()->delay_usec(10000);
if (Thread::get_caller_id() == Thread::get_main_id()) {
// If this is a busy loop on the main thread, events still need to be processed.
DisplayServer::get_singleton()->force_process_and_drop_events();
}
}
}
send_message("debug_exit", Array());
if (Thread::get_caller_id() == Thread::get_main_id()) {
if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
Input::get_singleton()->set_mouse_mode(mouse_mode);
}
} else {
MutexLock mutex_lock(mutex);
messages.erase(Thread::get_caller_id());
}
}
void RemoteDebugger::poll_events(bool p_is_idle) {
if (peer.is_null()) {
return;
}
flush_output();
_poll_messages();
while (_has_messages()) {
Array arr = _get_message();
ERR_CONTINUE(arr.size() != 2);
ERR_CONTINUE(arr[0].get_type() != Variant::STRING);
ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
const String cmd = arr[0];
const int idx = cmd.find_char(':');
bool parsed = false;
if (idx < 0) { // Not prefix, use scripts capture.
capture_parse("core", cmd, arr[1], parsed);
continue;
}
const String cap = cmd.substr(0, idx);
if (!has_capture(cap)) {
continue; // Unknown message...
}
const String msg = cmd.substr(idx + 1);
capture_parse(cap, msg, arr[1], parsed);
}
// Reload scripts during idle poll only.
if (p_is_idle) {
if (reload_all_scripts) {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->reload_all_scripts();
}
reload_all_scripts = false;
} else if (!script_paths_to_reload.is_empty()) {
Array scripts_to_reload;
for (int i = 0; i < script_paths_to_reload.size(); ++i) {
String path = script_paths_to_reload[i];
Error err = OK;
Ref<Script> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
ERR_CONTINUE_MSG(err != OK, vformat("Could not reload script '%s': %s", path, error_names[err]));
ERR_CONTINUE_MSG(script.is_null(), vformat("Could not reload script '%s': Not a script!", path, error_names[err]));
scripts_to_reload.push_back(script);
}
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->reload_scripts(scripts_to_reload, true);
}
}
script_paths_to_reload.clear();
}
}
Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
r_captured = true;
if (p_cmd == "reload_scripts") {
script_paths_to_reload = p_data;
} else if (p_cmd == "reload_all_scripts") {
reload_all_scripts = true;
} else if (p_cmd == "breakpoint") {
ERR_FAIL_COND_V(p_data.size() < 3, ERR_INVALID_DATA);
bool set = p_data[2];
if (set) {
script_debugger->insert_breakpoint(p_data[1], p_data[0]);
} else {
script_debugger->remove_breakpoint(p_data[1], p_data[0]);
}
} 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 == "break") {
script_debugger->debug(script_debugger->get_break_language());
} else {
r_captured = false;
}
return OK;
}
Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
r_captured = false;
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
ERR_FAIL_COND_V(p_data[0].get_type() != Variant::BOOL, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!has_profiler(p_cmd), ERR_UNAVAILABLE);
Array opts;
if (p_data.size() > 1) { // Optional profiler parameters.
ERR_FAIL_COND_V(p_data[1].get_type() != Variant::ARRAY, ERR_INVALID_DATA);
opts = p_data[1];
}
r_captured = true;
profiler_enable(p_cmd, p_data[0], opts);
return OK;
}
RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
peer = p_peer;
max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second");
max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second");
max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second");
// Performance Profiler
Object *perf = Engine::get_singleton()->get_singleton_object("Performance");
if (perf) {
performance_profiler.instantiate(perf);
performance_profiler->bind("performance");
profiler_enable("performance", true);
}
// Core and profiler captures.
Capture core_cap(this,
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
return static_cast<RemoteDebugger *>(p_user)->_core_capture(p_cmd, p_data, r_captured);
});
register_message_capture("core", core_cap);
Capture profiler_cap(this,
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
return static_cast<RemoteDebugger *>(p_user)->_profiler_capture(p_cmd, p_data, r_captured);
});
register_message_capture("profiler", profiler_cap);
// Error handlers
phl.printfunc = _print_handler;
phl.userdata = this;
add_print_handler(&phl);
eh.errfunc = _err_handler;
eh.userdata = this;
add_error_handler(&eh);
messages.insert(Thread::get_main_id(), List<Message>());
}
RemoteDebugger::~RemoteDebugger() {
remove_print_handler(&phl);
remove_error_handler(&eh);
}

View file

@ -1,126 +0,0 @@
/**************************************************************************/
/* remote_debugger.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef REMOTE_DEBUGGER_H
#define REMOTE_DEBUGGER_H
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/remote_debugger_peer.h"
#include "core/object/class_db.h"
#include "core/string/string_name.h"
#include "core/string/ustring.h"
#include "core/variant/array.h"
class RemoteDebugger : public EngineDebugger {
public:
enum MessageType {
MESSAGE_TYPE_LOG,
MESSAGE_TYPE_ERROR,
MESSAGE_TYPE_LOG_RICH,
};
private:
typedef DebuggerMarshalls::OutputError ErrorMessage;
class PerformanceProfiler;
Ref<PerformanceProfiler> performance_profiler;
Ref<RemoteDebuggerPeer> peer;
struct OutputString {
String message;
MessageType type;
};
List<OutputString> output_strings;
List<ErrorMessage> errors;
int n_messages_dropped = 0;
int max_errors_per_second = 0;
int max_chars_per_second = 0;
int max_warnings_per_second = 0;
int n_errors_dropped = 0;
int n_warnings_dropped = 0;
int char_count = 0;
int err_count = 0;
int warn_count = 0;
int last_reset = 0;
bool reload_all_scripts = false;
Array script_paths_to_reload;
// Make handlers and send_message thread safe.
Mutex mutex;
bool flushing = false;
Thread::ID flush_thread = 0;
struct Message {
String message;
Array data;
};
HashMap<Thread::ID, List<Message>> messages;
void _poll_messages();
bool _has_messages();
Array _get_message();
PrintHandlerList phl;
static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich);
ErrorHandlerList eh;
static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type);
ErrorMessage _create_overflow_error(const String &p_what, const String &p_descr);
Error _put_msg(const String &p_message, const Array &p_data);
bool is_peer_connected() { return peer->is_peer_connected(); }
void flush_output();
void _send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type);
Error _profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
Error _core_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
template <typename T>
void _bind_profiler(const String &p_name, T *p_prof);
Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured);
public:
// Overrides
void poll_events(bool p_is_idle);
void send_message(const String &p_message, const Array &p_args);
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
~RemoteDebugger();
};
#endif // REMOTE_DEBUGGER_H

View file

@ -1,243 +0,0 @@
/**************************************************************************/
/* remote_debugger_peer.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "remote_debugger_peer.h"
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
bool RemoteDebuggerPeerTCP::is_peer_connected() {
return connected;
}
bool RemoteDebuggerPeerTCP::has_message() {
return in_queue.size() > 0;
}
Array RemoteDebuggerPeerTCP::get_message() {
MutexLock lock(mutex);
ERR_FAIL_COND_V(!has_message(), Array());
Array out = in_queue.front()->get();
in_queue.pop_front();
return out;
}
Error RemoteDebuggerPeerTCP::put_message(const Array &p_arr) {
MutexLock lock(mutex);
if (out_queue.size() >= max_queued_messages) {
return ERR_OUT_OF_MEMORY;
}
out_queue.push_back(p_arr);
return OK;
}
int RemoteDebuggerPeerTCP::get_max_message_size() const {
return 8 << 20; // 8 MiB
}
void RemoteDebuggerPeerTCP::close() {
running = false;
if (thread.is_started()) {
thread.wait_to_finish();
}
tcp_client->disconnect_from_host();
out_buf.clear();
in_buf.clear();
}
RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
// This means remote debugger takes 16 MiB just because it exists...
in_buf.resize((8 << 20) + 4); // 8 MiB should be way more than enough (need 4 extra bytes for encoding packet size).
out_buf.resize(8 << 20); // 8 MiB should be way more than enough
tcp_client = p_tcp;
if (tcp_client.is_valid()) { // Attaching to an already connected stream.
connected = true;
running = true;
thread.start(_thread_func, this);
} else {
tcp_client.instantiate();
}
}
RemoteDebuggerPeerTCP::~RemoteDebuggerPeerTCP() {
close();
}
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) {
break; // Nothing left to send
}
mutex.lock();
Variant var = out_queue.front()->get();
out_queue.pop_front();
mutex.unlock();
int size = 0;
Error err = encode_variant(var, nullptr, size);
ERR_CONTINUE(err != OK || size > out_buf.size() - 4); // 4 bytes separator.
encode_uint32(size, buf);
encode_variant(var, buf + 4, size);
out_left = size + 4;
out_pos = 0;
}
int sent = 0;
tcp_client->put_partial_data(buf + out_pos, out_left, sent);
out_left -= sent;
out_pos += sent;
}
}
void RemoteDebuggerPeerTCP::_read_in() {
while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_IN) == OK) {
uint8_t *buf = in_buf.ptrw();
if (in_left <= 0) {
if (in_queue.size() > max_queued_messages) {
break; // Too many messages already in queue.
}
if (tcp_client->get_available_bytes() < 4) {
break; // Need 4 more bytes.
}
uint32_t size = 0;
int read = 0;
Error err = tcp_client->get_partial_data((uint8_t *)&size, 4, read);
ERR_CONTINUE(read != 4 || err != OK || size > (uint32_t)in_buf.size());
in_left = size;
in_pos = 0;
}
int read = 0;
tcp_client->get_partial_data(buf + in_pos, in_left, read);
in_left -= read;
in_pos += read;
if (in_left == 0) {
Variant var;
Error err = decode_variant(var, buf, in_pos, &read);
ERR_CONTINUE(read != in_pos || err != OK);
ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
MutexLock lock(mutex);
in_queue.push_back(var);
}
}
}
Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
} else {
ip = IP::get_singleton()->resolve_hostname(p_host);
}
int port = p_port;
const int tries = 6;
const int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
tcp_client->connect_to_host(ip, port);
for (int i = 0; i < tries; i++) {
tcp_client->poll();
if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
print_verbose("Remote Debugger: Connected!");
break;
} else {
const int ms = waits[i];
OS::get_singleton()->delay_usec(ms * 1000);
print_verbose("Remote Debugger: Connection failed with status: '" + String::num_int64(tcp_client->get_status()) + "', retrying in " + String::num_int64(ms) + " msec.");
}
}
if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
ERR_PRINT(vformat("Remote Debugger: Unable to connect. Status: %s.", String::num_int64(tcp_client->get_status())));
return FAILED;
}
connected = true;
running = true;
thread.start(_thread_func, this);
return OK;
}
void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
// Update in time for 144hz monitors
const uint64_t min_tick = 6900;
RemoteDebuggerPeerTCP *peer = static_cast<RemoteDebuggerPeerTCP *>(p_ud);
while (peer->running && peer->is_peer_connected()) {
uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
peer->_poll();
if (!peer->is_peer_connected()) {
break;
}
ticks_usec = OS::get_singleton()->get_ticks_usec() - ticks_usec;
if (ticks_usec < min_tick) {
OS::get_singleton()->delay_usec(min_tick - ticks_usec);
}
}
}
void RemoteDebuggerPeerTCP::poll() {
// Nothing to do, polling is done in thread.
}
void RemoteDebuggerPeerTCP::_poll() {
tcp_client->poll();
if (connected) {
_write_out();
_read_in();
connected = tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED;
}
}
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
String debug_host = p_uri.replace("tcp://", "");
uint16_t debug_port = 6007;
if (debug_host.contains_char(':')) {
int sep_pos = debug_host.rfind_char(':');
debug_port = debug_host.substr(sep_pos + 1).to_int();
debug_host = debug_host.substr(0, sep_pos);
}
RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP);
Error err = peer->connect_to_host(debug_host, debug_port);
if (err != OK) {
memdelete(peer);
return nullptr;
}
return peer;
}
RemoteDebuggerPeer::RemoteDebuggerPeer() {
max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
}

View file

@ -1,96 +0,0 @@
/**************************************************************************/
/* remote_debugger_peer.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef REMOTE_DEBUGGER_PEER_H
#define REMOTE_DEBUGGER_PEER_H
#include "core/io/stream_peer_tcp.h"
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
#include "core/string/ustring.h"
class RemoteDebuggerPeer : public RefCounted {
protected:
int max_queued_messages = 4096;
public:
virtual bool is_peer_connected() = 0;
virtual int get_max_message_size() const = 0;
virtual bool has_message() = 0;
virtual Error put_message(const Array &p_arr) = 0;
virtual Array get_message() = 0;
virtual void close() = 0;
virtual void poll() = 0;
virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug).
RemoteDebuggerPeer();
};
class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
private:
Ref<StreamPeerTCP> tcp_client;
Mutex mutex;
Thread thread;
List<Array> in_queue;
List<Array> out_queue;
int out_left = 0;
int out_pos = 0;
Vector<uint8_t> out_buf;
int in_left = 0;
int in_pos = 0;
Vector<uint8_t> in_buf;
bool connected = false;
bool running = false;
static void _thread_func(void *p_ud);
void _poll();
void _write_out();
void _read_in();
public:
static RemoteDebuggerPeer *create(const String &p_uri);
Error connect_to_host(const String &p_host, uint16_t p_port);
bool is_peer_connected() override;
int get_max_message_size() const override;
bool has_message() override;
Error put_message(const Array &p_arr) override;
Array get_message() override;
void poll() override;
void close() override;
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
~RemoteDebuggerPeerTCP();
};
#endif // REMOTE_DEBUGGER_PEER_H

View file

@ -1,102 +0,0 @@
/**************************************************************************/
/* script_debugger.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "script_debugger.h"
#include "core/debugger/engine_debugger.h"
thread_local int ScriptDebugger::lines_left = -1;
thread_local int ScriptDebugger::depth = -1;
thread_local ScriptLanguage *ScriptDebugger::break_lang = nullptr;
thread_local Vector<ScriptDebugger::StackInfo> ScriptDebugger::error_stack_info;
void ScriptDebugger::set_lines_left(int p_left) {
lines_left = p_left;
}
void ScriptDebugger::set_depth(int p_depth) {
depth = p_depth;
}
void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
if (!breakpoints.has(p_line)) {
breakpoints[p_line] = HashSet<StringName>();
}
breakpoints[p_line].insert(p_source);
}
void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
if (!breakpoints.has(p_line)) {
return;
}
breakpoints[p_line].erase(p_source);
if (breakpoints[p_line].size() == 0) {
breakpoints.erase(p_line);
}
}
String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
return p_source;
}
void ScriptDebugger::clear_breakpoints() {
breakpoints.clear();
}
void ScriptDebugger::set_skip_breakpoints(bool p_skip_breakpoints) {
skip_breakpoints = p_skip_breakpoints;
}
bool ScriptDebugger::is_skipping_breakpoints() {
return skip_breakpoints;
}
void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
ScriptLanguage *prev = break_lang;
break_lang = p_lang;
EngineDebugger::get_singleton()->debug(p_can_continue, p_is_error_breakpoint);
break_lang = prev;
}
void ScriptDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info) {
// Store stack info, this is ugly, but allows us to separate EngineDebugger and ScriptDebugger. There might be a better way.
error_stack_info.append_array(p_stack_info);
EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type);
error_stack_info.clear(); // Clear because this is thread local
}
Vector<ScriptLanguage::StackInfo> ScriptDebugger::get_error_stack_info() const {
return error_stack_info;
}
ScriptLanguage *ScriptDebugger::get_break_language() const {
return break_lang;
}

View file

@ -1,86 +0,0 @@
/**************************************************************************/
/* script_debugger.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCRIPT_DEBUGGER_H
#define SCRIPT_DEBUGGER_H
#include "core/object/script_language.h"
#include "core/string/string_name.h"
#include "core/templates/hash_set.h"
#include "core/templates/vector.h"
class ScriptDebugger {
typedef ScriptLanguage::StackInfo StackInfo;
bool skip_breakpoints = false;
HashMap<int, HashSet<StringName>> breakpoints;
static thread_local int lines_left;
static thread_local int depth;
static thread_local ScriptLanguage *break_lang;
static thread_local Vector<StackInfo> error_stack_info;
public:
void set_lines_left(int p_left);
_ALWAYS_INLINE_ int get_lines_left() const {
return lines_left;
}
void set_depth(int p_depth);
_ALWAYS_INLINE_ int get_depth() const {
return depth;
}
String breakpoint_find_source(const String &p_source) const;
void set_break_language(ScriptLanguage *p_lang) { break_lang = p_lang; }
ScriptLanguage *get_break_language() { return break_lang; }
void set_skip_breakpoints(bool p_skip_breakpoints);
bool is_skipping_breakpoints();
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 {
if (likely(!breakpoints.has(p_line))) {
return false;
}
return breakpoints[p_line].has(p_source);
}
void clear_breakpoints();
const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
ScriptLanguage *get_break_language() const;
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info);
Vector<StackInfo> get_error_stack_info() const;
ScriptDebugger() {}
};
#endif // SCRIPT_DEBUGGER_H

View file

@ -1,150 +0,0 @@
/**************************************************************************/
/* doc_data.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "doc_data.h"
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", " ");
} else if (p_value.get_type() == Variant::DICTIONARY) {
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
} else {
return p_value.get_construct_string().replace("\n", " ");
}
}
void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
if (p_retinfo.type == Variant::INT && p_retinfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
p_method.return_type = p_retinfo.hint_string;
if (p_method.return_type.is_empty()) {
p_method.return_type = "void*";
} else {
p_method.return_type += "*";
}
} 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_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_method.return_type = "int";
} else if (p_retinfo.class_name != StringName()) {
p_method.return_type = p_retinfo.class_name;
} else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
p_method.return_type = p_retinfo.hint_string + "[]";
} else if (p_retinfo.type == Variant::DICTIONARY && p_retinfo.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
p_method.return_type = "Dictionary[" + p_retinfo.hint_string.replace(";", ", ") + "]";
} else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
p_method.return_type = p_retinfo.hint_string;
} else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
p_method.return_type = "Variant";
} else if (p_retinfo.type == Variant::NIL) {
p_method.return_type = "void";
} else {
p_method.return_type = Variant::get_type_name(p_retinfo.type);
}
}
void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) {
p_argument.name = p_arginfo.name;
if (p_arginfo.type == Variant::INT && p_arginfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
p_argument.type = p_arginfo.hint_string;
if (p_argument.type.is_empty()) {
p_argument.type = "void*";
} else {
p_argument.type += "*";
}
} 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.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_argument.type = "int";
} else if (p_arginfo.class_name != StringName()) {
p_argument.type = p_arginfo.class_name;
} else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
p_argument.type = p_arginfo.hint_string + "[]";
} else if (p_arginfo.type == Variant::DICTIONARY && p_arginfo.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
p_argument.type = "Dictionary[" + p_arginfo.hint_string.replace(";", ", ") + "]";
} else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
p_argument.type = p_arginfo.hint_string;
} else if (p_arginfo.type == Variant::NIL) {
// Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary
p_argument.type = "Variant";
} else {
p_argument.type = Variant::get_type_name(p_arginfo.type);
}
}
void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc) {
p_method.name = p_methodinfo.name;
p_method.description = p_desc;
if (p_methodinfo.flags & METHOD_FLAG_VIRTUAL) {
p_method.qualifiers = "virtual";
}
if (p_methodinfo.flags & METHOD_FLAG_CONST) {
if (!p_method.qualifiers.is_empty()) {
p_method.qualifiers += " ";
}
p_method.qualifiers += "const";
}
if (p_methodinfo.flags & METHOD_FLAG_VARARG) {
if (!p_method.qualifiers.is_empty()) {
p_method.qualifiers += " ";
}
p_method.qualifiers += "vararg";
}
if (p_methodinfo.flags & METHOD_FLAG_STATIC) {
if (!p_method.qualifiers.is_empty()) {
p_method.qualifiers += " ";
}
p_method.qualifiers += "static";
}
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) {
DocData::ArgumentDoc argument;
argument_doc_from_arginfo(argument, *itr);
int 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);
}
p_method.arguments.push_back(argument);
}
}

View file

@ -1,984 +0,0 @@
/**************************************************************************/
/* doc_data.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DOC_DATA_H
#define DOC_DATA_H
#include "core/io/xml_parser.h"
#include "core/variant/variant.h"
class DocData {
public:
struct ArgumentDoc {
String name;
String type;
String enumeration;
bool is_bitfield = false;
String default_value;
bool operator<(const ArgumentDoc &p_arg) const {
if (name == p_arg.name) {
return type < p_arg.type;
}
return name < p_arg.name;
}
static ArgumentDoc from_dict(const Dictionary &p_dict) {
ArgumentDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("type")) {
doc.type = p_dict["type"];
}
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
if (p_dict.has("is_bitfield")) {
doc.is_bitfield = p_dict["is_bitfield"];
}
}
if (p_dict.has("default_value")) {
doc.default_value = p_dict["default_value"];
}
return doc;
}
static Dictionary to_dict(const ArgumentDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.type.is_empty()) {
dict["type"] = p_doc.type;
}
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.default_value.is_empty()) {
dict["default_value"] = p_doc.default_value;
}
return dict;
}
};
struct MethodDoc {
String name;
String return_type;
String return_enum;
bool return_is_bitfield = false;
String qualifiers;
String description;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
Vector<ArgumentDoc> arguments;
Vector<int> errors_returned;
String keywords;
bool operator<(const MethodDoc &p_method) const {
if (name == p_method.name) {
// 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) {
return false;
}
return arguments[0].type < p_method.arguments[0].type;
}
return arguments.size() < p_method.arguments.size();
} else {
// Must be a constructor
// We want this arbitrary order for a class "Foo":
// - 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.
return arguments.size() < p_method.arguments.size();
}
if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2.
return (arguments[0].type == return_type) || (p_method.arguments[0].type != p_method.return_type);
}
return arguments[0] < p_method.arguments[0];
}
}
return name.naturalcasecmp_to(p_method.name) < 0;
}
static MethodDoc from_dict(const Dictionary &p_dict) {
MethodDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("return_type")) {
doc.return_type = p_dict["return_type"];
}
if (p_dict.has("return_enum")) {
doc.return_enum = p_dict["return_enum"];
if (p_dict.has("return_is_bitfield")) {
doc.return_is_bitfield = p_dict["return_is_bitfield"];
}
}
if (p_dict.has("qualifiers")) {
doc.qualifiers = p_dict["qualifiers"];
}
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
#ifndef DISABLE_DEPRECATED
if (p_dict.has("is_deprecated")) {
doc.is_deprecated = p_dict["is_deprecated"];
}
if (p_dict.has("is_experimental")) {
doc.is_experimental = p_dict["is_experimental"];
}
#endif
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
Array arguments;
if (p_dict.has("arguments")) {
arguments = p_dict["arguments"];
}
for (int i = 0; i < arguments.size(); i++) {
doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
}
Array errors_returned;
if (p_dict.has("errors_returned")) {
errors_returned = p_dict["errors_returned"];
}
for (int i = 0; i < errors_returned.size(); i++) {
doc.errors_returned.push_back(errors_returned[i]);
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const MethodDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.return_type.is_empty()) {
dict["return_type"] = p_doc.return_type;
}
if (!p_doc.return_enum.is_empty()) {
dict["return_enum"] = p_doc.return_enum;
dict["return_is_bitfield"] = p_doc.return_is_bitfield;
}
if (!p_doc.qualifiers.is_empty()) {
dict["qualifiers"] = p_doc.qualifiers;
}
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
if (!p_doc.arguments.is_empty()) {
Array arguments;
for (int i = 0; i < p_doc.arguments.size(); i++) {
arguments.push_back(ArgumentDoc::to_dict(p_doc.arguments[i]));
}
dict["arguments"] = arguments;
}
if (!p_doc.errors_returned.is_empty()) {
Array errors_returned;
for (int i = 0; i < p_doc.errors_returned.size(); i++) {
errors_returned.push_back(p_doc.errors_returned[i]);
}
dict["errors_returned"] = errors_returned;
}
return dict;
}
};
struct ConstantDoc {
String name;
String value;
bool is_value_valid = false;
String type;
String enumeration;
bool is_bitfield = false;
String description;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
String keywords;
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
static ConstantDoc from_dict(const Dictionary &p_dict) {
ConstantDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("value")) {
doc.value = p_dict["value"];
}
if (p_dict.has("is_value_valid")) {
doc.is_value_valid = p_dict["is_value_valid"];
}
if (p_dict.has("type")) {
doc.type = p_dict["type"];
}
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
if (p_dict.has("is_bitfield")) {
doc.is_bitfield = p_dict["is_bitfield"];
}
}
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
#ifndef DISABLE_DEPRECATED
if (p_dict.has("is_deprecated")) {
doc.is_deprecated = p_dict["is_deprecated"];
}
if (p_dict.has("is_experimental")) {
doc.is_experimental = p_dict["is_experimental"];
}
#endif
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const ConstantDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.value.is_empty()) {
dict["value"] = p_doc.value;
}
dict["is_value_valid"] = p_doc.is_value_valid;
dict["type"] = p_doc.type;
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
struct PropertyDoc {
String name;
String type;
String enumeration;
bool is_bitfield = false;
String description;
String setter, getter;
String default_value;
bool overridden = false;
String overrides;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
String keywords;
bool operator<(const PropertyDoc &p_prop) const {
return name.naturalcasecmp_to(p_prop.name) < 0;
}
static PropertyDoc from_dict(const Dictionary &p_dict) {
PropertyDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("type")) {
doc.type = p_dict["type"];
}
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
if (p_dict.has("is_bitfield")) {
doc.is_bitfield = p_dict["is_bitfield"];
}
}
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
if (p_dict.has("setter")) {
doc.setter = p_dict["setter"];
}
if (p_dict.has("getter")) {
doc.getter = p_dict["getter"];
}
if (p_dict.has("default_value")) {
doc.default_value = p_dict["default_value"];
}
if (p_dict.has("overridden")) {
doc.overridden = p_dict["overridden"];
}
if (p_dict.has("overrides")) {
doc.overrides = p_dict["overrides"];
}
#ifndef DISABLE_DEPRECATED
if (p_dict.has("is_deprecated")) {
doc.is_deprecated = p_dict["is_deprecated"];
}
if (p_dict.has("is_experimental")) {
doc.is_experimental = p_dict["is_experimental"];
}
#endif
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const PropertyDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.type.is_empty()) {
dict["type"] = p_doc.type;
}
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (!p_doc.setter.is_empty()) {
dict["setter"] = p_doc.setter;
}
if (!p_doc.getter.is_empty()) {
dict["getter"] = p_doc.getter;
}
if (!p_doc.default_value.is_empty()) {
dict["default_value"] = p_doc.default_value;
}
dict["overridden"] = p_doc.overridden;
if (!p_doc.overrides.is_empty()) {
dict["overrides"] = p_doc.overrides;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
struct ThemeItemDoc {
String name;
String type;
String data_type;
String description;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
String default_value;
String keywords;
bool operator<(const ThemeItemDoc &p_theme_item) const {
// First sort by the data type, then by name.
if (data_type == p_theme_item.data_type) {
return name.naturalcasecmp_to(p_theme_item.name) < 0;
}
return data_type < p_theme_item.data_type;
}
static ThemeItemDoc from_dict(const Dictionary &p_dict) {
ThemeItemDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("type")) {
doc.type = p_dict["type"];
}
if (p_dict.has("data_type")) {
doc.data_type = p_dict["data_type"];
}
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
if (p_dict.has("default_value")) {
doc.default_value = p_dict["default_value"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const ThemeItemDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.type.is_empty()) {
dict["type"] = p_doc.type;
}
if (!p_doc.data_type.is_empty()) {
dict["data_type"] = p_doc.data_type;
}
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
if (!p_doc.default_value.is_empty()) {
dict["default_value"] = p_doc.default_value;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
struct TutorialDoc {
String link;
String title;
static TutorialDoc from_dict(const Dictionary &p_dict) {
TutorialDoc doc;
if (p_dict.has("link")) {
doc.link = p_dict["link"];
}
if (p_dict.has("title")) {
doc.title = p_dict["title"];
}
return doc;
}
static Dictionary to_dict(const TutorialDoc &p_doc) {
Dictionary dict;
if (!p_doc.link.is_empty()) {
dict["link"] = p_doc.link;
}
if (!p_doc.title.is_empty()) {
dict["title"] = p_doc.title;
}
return dict;
}
};
struct EnumDoc {
String description;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
static EnumDoc from_dict(const Dictionary &p_dict) {
EnumDoc doc;
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
#ifndef DISABLE_DEPRECATED
if (p_dict.has("is_deprecated")) {
doc.is_deprecated = p_dict["is_deprecated"];
}
if (p_dict.has("is_experimental")) {
doc.is_experimental = p_dict["is_experimental"];
}
#endif
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
return doc;
}
static Dictionary to_dict(const EnumDoc &p_doc) {
Dictionary dict;
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
return dict;
}
};
struct ClassDoc {
String name;
String inherits;
String brief_description;
String description;
String keywords;
Vector<TutorialDoc> tutorials;
Vector<MethodDoc> constructors;
Vector<MethodDoc> methods;
Vector<MethodDoc> operators;
Vector<MethodDoc> signals;
Vector<ConstantDoc> constants;
HashMap<String, EnumDoc> enums;
Vector<PropertyDoc> properties;
Vector<MethodDoc> annotations;
Vector<ThemeItemDoc> theme_properties;
bool is_deprecated = false;
String deprecated_message;
bool is_experimental = false;
String experimental_message;
bool is_script_doc = false;
String script_path;
bool operator<(const ClassDoc &p_class) const {
return name < p_class.name;
}
static ClassDoc from_dict(const Dictionary &p_dict) {
ClassDoc doc;
if (p_dict.has("name")) {
doc.name = p_dict["name"];
}
if (p_dict.has("inherits")) {
doc.inherits = p_dict["inherits"];
}
if (p_dict.has("brief_description")) {
doc.brief_description = p_dict["brief_description"];
}
if (p_dict.has("description")) {
doc.description = p_dict["description"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
Array tutorials;
if (p_dict.has("tutorials")) {
tutorials = p_dict["tutorials"];
}
for (int i = 0; i < tutorials.size(); i++) {
doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
}
Array constructors;
if (p_dict.has("constructors")) {
constructors = p_dict["constructors"];
}
for (int i = 0; i < constructors.size(); i++) {
doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
}
Array methods;
if (p_dict.has("methods")) {
methods = p_dict["methods"];
}
for (int i = 0; i < methods.size(); i++) {
doc.methods.push_back(MethodDoc::from_dict(methods[i]));
}
Array operators;
if (p_dict.has("operators")) {
operators = p_dict["operators"];
}
for (int i = 0; i < operators.size(); i++) {
doc.operators.push_back(MethodDoc::from_dict(operators[i]));
}
Array signals;
if (p_dict.has("signals")) {
signals = p_dict["signals"];
}
for (int i = 0; i < signals.size(); i++) {
doc.signals.push_back(MethodDoc::from_dict(signals[i]));
}
Array constants;
if (p_dict.has("constants")) {
constants = p_dict["constants"];
}
for (int i = 0; i < constants.size(); i++) {
doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
}
Dictionary enums;
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));
}
Array properties;
if (p_dict.has("properties")) {
properties = p_dict["properties"];
}
for (int i = 0; i < properties.size(); i++) {
doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
}
Array annotations;
if (p_dict.has("annotations")) {
annotations = p_dict["annotations"];
}
for (int i = 0; i < annotations.size(); i++) {
doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
}
Array theme_properties;
if (p_dict.has("theme_properties")) {
theme_properties = p_dict["theme_properties"];
}
for (int i = 0; i < theme_properties.size(); i++) {
doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
}
#ifndef DISABLE_DEPRECATED
if (p_dict.has("is_deprecated")) {
doc.is_deprecated = p_dict["is_deprecated"];
}
if (p_dict.has("is_experimental")) {
doc.is_experimental = p_dict["is_experimental"];
}
#endif
if (p_dict.has("deprecated")) {
doc.is_deprecated = true;
doc.deprecated_message = p_dict["deprecated"];
}
if (p_dict.has("experimental")) {
doc.is_experimental = true;
doc.experimental_message = p_dict["experimental"];
}
if (p_dict.has("is_script_doc")) {
doc.is_script_doc = p_dict["is_script_doc"];
}
if (p_dict.has("script_path")) {
doc.script_path = p_dict["script_path"];
}
return doc;
}
static Dictionary to_dict(const ClassDoc &p_doc) {
Dictionary dict;
if (!p_doc.name.is_empty()) {
dict["name"] = p_doc.name;
}
if (!p_doc.inherits.is_empty()) {
dict["inherits"] = p_doc.inherits;
}
if (!p_doc.brief_description.is_empty()) {
dict["brief_description"] = p_doc.brief_description;
}
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
if (!p_doc.tutorials.is_empty()) {
Array tutorials;
for (int i = 0; i < p_doc.tutorials.size(); i++) {
tutorials.push_back(TutorialDoc::to_dict(p_doc.tutorials[i]));
}
dict["tutorials"] = tutorials;
}
if (!p_doc.constructors.is_empty()) {
Array constructors;
for (int i = 0; i < p_doc.constructors.size(); i++) {
constructors.push_back(MethodDoc::to_dict(p_doc.constructors[i]));
}
dict["constructors"] = constructors;
}
if (!p_doc.methods.is_empty()) {
Array methods;
for (int i = 0; i < p_doc.methods.size(); i++) {
methods.push_back(MethodDoc::to_dict(p_doc.methods[i]));
}
dict["methods"] = methods;
}
if (!p_doc.operators.is_empty()) {
Array operators;
for (int i = 0; i < p_doc.operators.size(); i++) {
operators.push_back(MethodDoc::to_dict(p_doc.operators[i]));
}
dict["operators"] = operators;
}
if (!p_doc.signals.is_empty()) {
Array signals;
for (int i = 0; i < p_doc.signals.size(); i++) {
signals.push_back(MethodDoc::to_dict(p_doc.signals[i]));
}
dict["signals"] = signals;
}
if (!p_doc.constants.is_empty()) {
Array constants;
for (int i = 0; i < p_doc.constants.size(); i++) {
constants.push_back(ConstantDoc::to_dict(p_doc.constants[i]));
}
dict["constants"] = constants;
}
if (!p_doc.enums.is_empty()) {
Dictionary enums;
for (const KeyValue<String, EnumDoc> &E : p_doc.enums) {
enums[E.key] = EnumDoc::to_dict(E.value);
}
dict["enums"] = enums;
}
if (!p_doc.properties.is_empty()) {
Array properties;
for (int i = 0; i < p_doc.properties.size(); i++) {
properties.push_back(PropertyDoc::to_dict(p_doc.properties[i]));
}
dict["properties"] = properties;
}
if (!p_doc.annotations.is_empty()) {
Array annotations;
for (int i = 0; i < p_doc.annotations.size(); i++) {
annotations.push_back(MethodDoc::to_dict(p_doc.annotations[i]));
}
dict["annotations"] = annotations;
}
if (!p_doc.theme_properties.is_empty()) {
Array theme_properties;
for (int i = 0; i < p_doc.theme_properties.size(); i++) {
theme_properties.push_back(ThemeItemDoc::to_dict(p_doc.theme_properties[i]));
}
dict["theme_properties"] = theme_properties;
}
if (p_doc.is_deprecated) {
dict["deprecated"] = p_doc.deprecated_message;
}
if (p_doc.is_experimental) {
dict["experimental"] = p_doc.experimental_message;
}
dict["is_script_doc"] = p_doc.is_script_doc;
if (!p_doc.script_path.is_empty()) {
dict["script_path"] = p_doc.script_path;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
static String get_default_value_string(const Variant &p_value);
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
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

@ -1,8 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env_error = env.Clone()
env_error.add_source_files(env.core_sources, "*.cpp")

View file

@ -1,85 +0,0 @@
/**************************************************************************/
/* error_list.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "error_list.h"
const char *error_names[] = {
"OK", // OK
"Failed", // FAILED
"Unavailable", // ERR_UNAVAILABLE
"Unconfigured", // ERR_UNCONFIGURED
"Unauthorized", // ERR_UNAUTHORIZED
"Parameter out of range", // ERR_PARAMETER_RANGE_ERROR
"Out of memory", // ERR_OUT_OF_MEMORY
"File not found", // ERR_FILE_NOT_FOUND
"File: Bad drive", // ERR_FILE_BAD_DRIVE
"File: Bad path", // ERR_FILE_BAD_PATH
"File: Permission denied", // ERR_FILE_NO_PERMISSION
"File already in use", // ERR_FILE_ALREADY_IN_USE
"Can't open file", // ERR_FILE_CANT_OPEN
"Can't write file", // ERR_FILE_CANT_WRITE
"Can't read file", // ERR_FILE_CANT_READ
"File unrecognized", // ERR_FILE_UNRECOGNIZED
"File corrupt", // ERR_FILE_CORRUPT
"Missing dependencies for file", // ERR_FILE_MISSING_DEPENDENCIES
"End of file", // ERR_FILE_EOF
"Can't open", // ERR_CANT_OPEN
"Can't create", // ERR_CANT_CREATE
"Query failed", // ERR_QUERY_FAILED
"Already in use", // ERR_ALREADY_IN_USE
"Locked", // ERR_LOCKED
"Timeout", // ERR_TIMEOUT
"Can't connect", // ERR_CANT_CONNECT
"Can't resolve", // ERR_CANT_RESOLVE
"Connection error", // ERR_CONNECTION_ERROR
"Can't acquire resource", // ERR_CANT_ACQUIRE_RESOURCE
"Can't fork", // ERR_CANT_FORK
"Invalid data", // ERR_INVALID_DATA
"Invalid parameter", // ERR_INVALID_PARAMETER
"Already exists", // ERR_ALREADY_EXISTS
"Does not exist", // ERR_DOES_NOT_EXIST
"Can't read database", // ERR_DATABASE_CANT_READ
"Can't write database", // ERR_DATABASE_CANT_WRITE
"Compilation failed", // ERR_COMPILATION_FAILED
"Method not found", // ERR_METHOD_NOT_FOUND
"Link failed", // ERR_LINK_FAILED
"Script failed", // ERR_SCRIPT_FAILED
"Cyclic link detected", // ERR_CYCLIC_LINK
"Invalid declaration", // ERR_INVALID_DECLARATION
"Duplicate symbol", // ERR_DUPLICATE_SYMBOL
"Parse error", // ERR_PARSE_ERROR
"Busy", // ERR_BUSY
"Skip", // ERR_SKIP
"Help", // ERR_HELP
"Bug", // ERR_BUG
"Printer on fire", // ERR_PRINTER_ON_FIRE
};
static_assert(sizeof(error_names) / sizeof(*error_names) == ERR_MAX);

View file

@ -1,102 +0,0 @@
/**************************************************************************/
/* error_list.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ERROR_LIST_H
#define ERROR_LIST_H
/** Error List. Please never compare an error against FAILED
* Either do result != OK , or !result. This way, Error fail
* values can be more detailed in the future.
*
* This is a generic error list, mainly for organizing a language of returning errors.
*
* Errors:
* - Are added to the Error enum in core/error/error_list.h
* - Have a description added to error_names in core/error/error_list.cpp
* - Are bound with BIND_CORE_ENUM_CONSTANT() in core/core_constants.cpp
* - Have a matching Android version in platform/android/java/lib/src/org/godotengine/godot/error/Error.kt
*/
enum Error {
OK, // (0)
FAILED, ///< Generic fail error
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
ERR_OUT_OF_MEMORY, ///< Out of memory
ERR_FILE_NOT_FOUND,
ERR_FILE_BAD_DRIVE,
ERR_FILE_BAD_PATH,
ERR_FILE_NO_PERMISSION, // (10)
ERR_FILE_ALREADY_IN_USE,
ERR_FILE_CANT_OPEN,
ERR_FILE_CANT_WRITE,
ERR_FILE_CANT_READ,
ERR_FILE_UNRECOGNIZED, // (15)
ERR_FILE_CORRUPT,
ERR_FILE_MISSING_DEPENDENCIES,
ERR_FILE_EOF,
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
ERR_CANT_CREATE, // (20)
ERR_QUERY_FAILED,
ERR_ALREADY_IN_USE,
ERR_LOCKED, ///< resource is locked
ERR_TIMEOUT,
ERR_CANT_CONNECT, // (25)
ERR_CANT_RESOLVE,
ERR_CONNECTION_ERROR,
ERR_CANT_ACQUIRE_RESOURCE,
ERR_CANT_FORK,
ERR_INVALID_DATA, ///< Data passed is invalid (30)
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
ERR_ALREADY_EXISTS, ///< When adding, item already exists
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
ERR_DATABASE_CANT_READ, ///< database is full
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
ERR_COMPILATION_FAILED,
ERR_METHOD_NOT_FOUND,
ERR_LINK_FAILED,
ERR_SCRIPT_FAILED,
ERR_CYCLIC_LINK, // (40)
ERR_INVALID_DECLARATION,
ERR_DUPLICATE_SYMBOL,
ERR_PARSE_ERROR,
ERR_BUSY,
ERR_SKIP, // (45)
ERR_HELP, ///< user requested help!!
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
ERR_MAX, // Not being returned, value represents the number of errors
};
extern const char *error_names[];
#endif // ERROR_LIST_H

View file

@ -1,203 +0,0 @@
/**************************************************************************/
/* error_macros.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "error_macros.h"
#include "core/io/logger.h"
#include "core/os/os.h"
#include "core/string/ustring.h"
// Optional physics interpolation warnings try to include the path to the relevant node.
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
#include "core/config/project_settings.h"
#include "scene/main/node.h"
#endif
static ErrorHandlerList *error_handler_list = nullptr;
void add_error_handler(ErrorHandlerList *p_handler) {
// If p_handler is already in error_handler_list
// we'd better remove it first then we can add it.
// This prevent cyclic redundancy.
remove_error_handler(p_handler);
_global_lock();
p_handler->next = error_handler_list;
error_handler_list = p_handler;
_global_unlock();
}
void remove_error_handler(const ErrorHandlerList *p_handler) {
_global_lock();
ErrorHandlerList *prev = nullptr;
ErrorHandlerList *l = error_handler_list;
while (l) {
if (l == p_handler) {
if (prev) {
prev->next = l->next;
} else {
error_handler_list = l->next;
}
break;
}
prev = l;
l = l->next;
}
_global_unlock();
}
// Errors without messages.
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, ErrorHandlerType p_type) {
_err_print_error(p_function, p_file, p_line, p_error, "", p_editor_notify, p_type);
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, ErrorHandlerType p_type) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), "", p_editor_notify, p_type);
}
// Main error printing function.
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
if (OS::get_singleton()) {
OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type);
} else {
// Fallback if errors happen before OS init or after it's destroyed.
const char *err_details = (p_message && *p_message) ? p_message : p_error;
fprintf(stderr, "ERROR: %s\n at: %s (%s:%i)\n", err_details, p_function, p_file, p_line);
}
_global_lock();
ErrorHandlerList *l = error_handler_list;
while (l) {
l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type);
l = l->next;
}
_global_unlock();
}
// For printing errors when we may crash at any point, so we must flush ASAP a lot of lines
// but we don't want to make it noisy by printing lots of file & line info (because it's already
// been printing by a preceding _err_print_error).
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type) {
if (OS::get_singleton()) {
OS::get_singleton()->printerr("ERROR: %s\n", p_error.utf8().get_data());
} else {
// Fallback if errors happen before OS init or after it's destroyed.
const char *err_details = p_error.utf8().get_data();
fprintf(stderr, "ERROR: %s\n", err_details);
}
_global_lock();
ErrorHandlerList *l = error_handler_list;
while (l) {
l->errfunc(l->userdata, "", "", 0, p_error.utf8().get_data(), "", false, p_type);
l = l->next;
}
_global_unlock();
}
// Errors with message. (All combinations of p_error and p_message as String or char*.)
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, ErrorHandlerType p_type) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_type);
}
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, ErrorHandlerType p_type) {
_err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, p_type);
}
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, ErrorHandlerType p_type) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, p_type);
}
// Index errors. (All combinations of p_message as String or char*.)
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, bool p_fatal) {
String fstr(p_fatal ? "FATAL: " : "");
String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
_err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, 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 String &p_message, bool p_editor_notify, bool p_fatal) {
_err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
}
void _err_flush_stdout() {
fflush(stdout);
}
// Prevent error spam by limiting the warnings to a certain frequency.
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string) {
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
const uint32_t warn_max = 2048;
const uint32_t warn_timeout_seconds = 15;
static uint32_t warn_count = warn_max;
static uint32_t warn_timeout = warn_timeout_seconds;
uint32_t time_now = UINT32_MAX;
if (warn_count) {
warn_count--;
}
if (!warn_count) {
time_now = OS::get_singleton()->get_ticks_msec() / 1000;
}
if ((warn_count == 0) && (time_now >= warn_timeout)) {
warn_count = warn_max;
warn_timeout = time_now + warn_timeout_seconds;
if (GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
// UINT64_MAX means unused.
if (p_id.operator uint64_t() == UINT64_MAX) {
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + " (possibly benign).", false, ERR_HANDLER_WARNING);
} else {
String node_name;
if (p_id.is_valid()) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id));
if (node && node->is_inside_tree()) {
node_name = "\"" + String(node->get_path()) + "\"";
} else {
node_name = "\"unknown\"";
}
}
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + ": " + node_name + " (possibly benign).", false, ERR_HANDLER_WARNING);
}
}
}
#endif
}

View file

@ -1,849 +0,0 @@
/**************************************************************************/
/* error_macros.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ERROR_MACROS_H
#define ERROR_MACROS_H
#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.
class String;
enum ErrorHandlerType {
ERR_HANDLER_ERROR,
ERR_HANDLER_WARNING,
ERR_HANDLER_SCRIPT,
ERR_HANDLER_SHADER,
};
// Pointer to the error handler printing function. Reassign to any function to have errors printed.
// Parameters: userdata, function, file, line, error, explanation, type.
typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
struct ErrorHandlerList {
ErrorHandlerFunc errfunc = nullptr;
void *userdata = nullptr;
ErrorHandlerList *next = nullptr;
ErrorHandlerList() {}
};
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);
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();
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string);
#ifdef __GNUC__
//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
#define FUNCTION_STR __FUNCTION__
#else
#define FUNCTION_STR __FUNCTION__
#endif
#ifdef _MSC_VER
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
*/
#define GENERATE_TRAP() __debugbreak()
#else
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
*/
#define GENERATE_TRAP() __builtin_trap()
#endif
/**
* Error macros.
* WARNING: These macros work in the opposite way to assert().
*
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
* running application to fail or crash.
* Always try to return processable data, so the engine can keep running well.
* Use the _MSG versions to print a meaningful message to help with debugging.
*
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
* those macros, making them look like proper statements.
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
*/
// Index out of bounds error macros.
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
// Integer index out of bounds error macros.
/**
* Try using `ERR_FAIL_INDEX_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns.
*/
#define ERR_FAIL_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the application crashes.
*/
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Unsigned integer index out of bounds error macros.
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Null reference error macros.
/**
* Try using `ERR_FAIL_NULL_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns.
*/
#define ERR_FAIL_NULL(m_param) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_NULL_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V(m_param, m_retval) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return m_retval; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`.
* Only use this macro if there is no sensible error message.
* If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns.
*/
#define ERR_FAIL_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
return; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current function returns.
*
* If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*/
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible error message.
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns `m_retval`.
*/
#define ERR_FAIL_COND_V(m_cond, m_retval) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
*
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*/
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_CONTINUE_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop continues.
*/
#define ERR_CONTINUE(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
continue; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop continues.
*/
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
continue; \
} else \
((void)0)
/**
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
continue; \
} else \
((void)0)
/**
* Try using `ERR_BREAK_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop breaks.
*/
#define ERR_BREAK(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
break; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
*/
#define ERR_BREAK_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
break; \
} else \
((void)0)
/**
* Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
break; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the application crashes.
*/
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the application crashes.
*/
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Generic error macros.
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
* Only use this macro if more complex error detection or recovery is required, and
* there is no sensible error message.
*
* The current function returns.
*/
#define ERR_FAIL() \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`.
* Only use this macro if more complex error detection or recovery is required.
*
* Prints `m_msg`, and the current function returns.
*/
#define ERR_FAIL_MSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
* Only use this macro if more complex error detection or recovery is required, and
* there is no sensible error message.
*
* The current function returns `m_retval`.
*/
#define ERR_FAIL_V(m_retval) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG`.
* Only use this macro if more complex error detection or recovery is required.
*
* Prints `m_msg`, and the current function returns `m_retval`.
*/
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
* Only use this macro at the start of a function that has not been implemented yet, or
* if more complex error detection or recovery is required.
*
* Prints `m_msg`.
*/
#define ERR_PRINT(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
* Same as `ERR_PRINT` but also notifies the editor.
*/
#define ERR_PRINT_ED(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/**
* Prints `m_msg` once during the application lifetime.
*/
#define ERR_PRINT_ONCE(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
first_print = false; \
} \
} else \
((void)0)
/**
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
*/
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
first_print = false; \
} \
} else \
((void)0)
// Print warning message macros.
/**
* Prints `m_msg`.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING)
/**
* Same as `WARN_PRINT` but also notifies the editor.
*/
#define WARN_PRINT_ED(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING)
/**
* Prints `m_msg` once during the application lifetime.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \
first_print = false; \
} \
} else \
((void)0)
/**
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \
first_print = false; \
} \
} else \
((void)0)
/**
* Warns about `m_msg` only when verbose mode is enabled.
*/
#define WARN_VERBOSE(m_msg) \
{ \
if (is_print_verbose_enabled()) { \
WARN_PRINT(m_msg); \
} \
}
// Print deprecated warning message macros.
/**
* Warns that the current function is deprecated.
*/
#define WARN_DEPRECATED \
if (true) { \
static std::atomic<bool> warning_shown; \
if (!warning_shown.load()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \
warning_shown.store(true); \
} \
} else \
((void)0)
/**
* Warns that the current function is deprecated and prints `m_msg`.
*/
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
static std::atomic<bool> warning_shown; \
if (!warning_shown.load()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \
warning_shown.store(true); \
} \
} else \
((void)0)
/**
* Do not use.
* If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
*
* The application crashes.
*/
#define CRASH_NOW() \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Only use if the application should never reach this point.
*
* Prints `m_msg`, and then the application crashes.
*/
#define CRASH_NOW_MSG(m_msg) \
if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Note: IN MOST CASES YOU SHOULD NOT USE THIS MACRO.
* Do not use unless you understand the trade-offs.
*
* DEV macros will be compiled out in releases, they are wrapped in DEV_ENABLED.
*
* Prefer WARNINGS / ERR_FAIL macros (which fail without crashing) - ERR_FAIL should be used in most cases.
* Then CRASH_NOW_MSG macros (on rare occasions where error cannot be recovered).
*
* DEV_ASSERT should generally only be used when both of the following conditions are met:
* 1) Bottleneck code where a check in release would be too expensive.
* 2) Situations where the check would fail obviously and straight away during the maintenance of the code
* (i.e. strict conditions that should be true no matter what)
* and that can't fail for other contributors once the code is finished and merged.
*/
#ifdef DEV_ENABLED
#define DEV_ASSERT(m_cond) \
if (unlikely(!(m_cond))) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
#else
#define DEV_ASSERT(m_cond)
#endif
#ifdef DEV_ENABLED
#define DEV_CHECK_ONCE(m_cond) \
if (unlikely(!(m_cond))) { \
ERR_PRINT_ONCE("DEV_CHECK_ONCE failed \"" _STR(m_cond) "\" is false."); \
} else \
((void)0)
#else
#define DEV_CHECK_ONCE(m_cond)
#endif
/**
* Physics Interpolation warnings.
* These are spam protection warnings.
*/
#define PHYSICS_INTERPOLATION_NODE_WARNING(m_object_id, m_string) \
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, m_object_id, m_string)
#define PHYSICS_INTERPOLATION_WARNING(m_string) \
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string)
#endif // ERROR_MACROS_H

View file

@ -1,18 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
import make_interface_dumper
import make_wrappers
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
env.CommandNoCache(
"gdextension_interface_dump.gen.h",
["gdextension_interface.h", "make_interface_dumper.py"],
env.Run(make_interface_dumper.run),
)
env_extension = env.Clone()
env_extension.add_source_files(env.core_sources, "*.cpp")

File diff suppressed because it is too large Load diff

View file

@ -1,46 +0,0 @@
/**************************************************************************/
/* extension_api_dump.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef EXTENSION_API_DUMP_H
#define EXTENSION_API_DUMP_H
#include "core/extension/gdextension.h"
#ifdef TOOLS_ENABLED
class GDExtensionAPIDump {
public:
static Dictionary generate_extension_api(bool p_include_docs = false);
static void generate_extension_json_file(const String &p_path, bool p_include_docs = false);
static Error validate_extension_json_file(const String &p_path);
};
#endif
#endif // EXTENSION_API_DUMP_H

View file

@ -1,49 +0,0 @@
/**************************************************************************/
/* gdextension.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) {
return ERR_UNAVAILABLE;
}
void GDExtension::_close_library_bind_compat_88418() {
}
void GDExtension::_initialize_library_bind_compat_88418(InitializationLevel p_level) {
}
void GDExtension::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88418);
ClassDB::bind_compatibility_method(D_METHOD("close_library"), &GDExtension::_close_library_bind_compat_88418);
ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418);
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,230 +0,0 @@
/**************************************************************************/
/* gdextension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_H
#define GDEXTENSION_H
#include "core/extension/gdextension_interface.h"
#include "core/extension/gdextension_loader.h"
#include "core/io/config_file.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
class GDExtensionMethodBind;
class GDExtension : public Resource {
GDCLASS(GDExtension, Resource)
friend class GDExtensionManager;
Ref<GDExtensionLoader> loader;
bool reloadable = false;
struct Extension {
ObjectGDExtension gdextension;
#ifdef TOOLS_ENABLED
bool is_reloading = false;
HashMap<StringName, GDExtensionMethodBind *> methods;
HashSet<ObjectID> instances;
struct InstanceState {
List<Pair<String, Variant>> properties;
bool is_placeholder = false;
};
HashMap<ObjectID, InstanceState> instance_state;
#endif
};
HashMap<StringName, Extension> extension_classes;
struct ClassCreationDeprecatedInfo {
#ifndef DISABLE_DEPRECATED
GDExtensionClassNotification notification_func = nullptr;
GDExtensionClassFreePropertyList free_property_list_func = nullptr;
GDExtensionClassCreateInstance create_instance_func = nullptr;
GDExtensionClassGetRID get_rid_func = nullptr;
GDExtensionClassGetVirtual get_virtual_func = nullptr;
GDExtensionClassGetVirtualCallData get_virtual_call_data_func = nullptr;
#endif // DISABLE_DEPRECATED
};
#ifndef DISABLE_DEPRECATED
static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs);
static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
static void _register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
#endif // DISABLE_DEPRECATED
static void _register_extension_class4(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr);
static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
static void _register_extension_class_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info);
static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
static void _register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
static void _register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_group_name, GDExtensionConstStringNamePtr p_prefix);
static void _register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_subgroup_name, GDExtensionConstStringNamePtr p_prefix);
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);
GDExtensionInitialization initialization;
int32_t level_initialized = -1;
#ifdef TOOLS_ENABLED
bool is_reloading = false;
Vector<GDExtensionMethodBind *> invalid_methods;
Vector<ObjectID> instance_bindings;
static void _track_instance(void *p_user_data, void *p_instance);
static void _untrack_instance(void *p_user_data, void *p_instance);
void _clear_extension(Extension *p_extension);
// Only called by GDExtensionManager during the reload process.
void prepare_reload();
void finish_reload();
void clear_instance_bindings();
#endif
static HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
protected:
static void _bind_methods();
public:
HashMap<String, String> class_icon_paths;
virtual bool editor_can_reload_from_file() override { return false; } // Reloading is handled in a special way.
static String get_extension_list_config_file();
const Ref<GDExtensionLoader> get_loader() const { return loader; }
Error open_library(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
void close_library();
bool is_library_open() const;
enum InitializationLevel {
INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
};
protected:
#ifndef DISABLE_DEPRECATED
Error _open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol);
void _close_library_bind_compat_88418();
void _initialize_library_bind_compat_88418(InitializationLevel p_level);
static void _bind_compatibility_methods();
#endif
public:
#ifdef TOOLS_ENABLED
bool is_reloadable() const { return reloadable; }
void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
bool has_library_changed() const;
void track_instance_binding(Object *p_object);
void untrack_instance_binding(Object *p_object);
#endif
InitializationLevel get_minimum_library_initialization_level() const;
void initialize_library(InitializationLevel p_level);
void deinitialize_library(InitializationLevel p_level);
static void register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
static GDExtensionInterfaceFunctionPtr get_interface_function(const StringName &p_function_name);
static void initialize_gdextensions();
static void finalize_gdextensions();
GDExtension();
~GDExtension();
};
VARIANT_ENUM_CAST(GDExtension::InitializationLevel)
class GDExtensionResourceLoader : public ResourceFormatLoader {
public:
static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
virtual bool handles_type(const String &p_type) const override;
virtual String get_resource_type(const String &p_path) const override;
};
#ifdef TOOLS_ENABLED
class GDExtensionEditorPlugins {
private:
static Vector<StringName> extension_classes;
protected:
friend class EditorNode;
// Since this in core, we can't directly reference EditorNode, so it will
// set these function pointers in its constructor.
typedef void (*EditorPluginRegisterFunc)(const StringName &p_class_name);
static EditorPluginRegisterFunc editor_node_add_plugin;
static EditorPluginRegisterFunc editor_node_remove_plugin;
public:
static void add_extension_class(const StringName &p_class_name);
static void remove_extension_class(const StringName &p_class_name);
static const Vector<StringName> &get_extension_classes() {
return extension_classes;
}
};
class GDExtensionEditorHelp {
protected:
friend class EditorHelp;
// Similarly to EditorNode above, we need to be able to ask EditorHelp to parse
// new documentation data. Note though that, differently from EditorHelp, this
// is initialized even _before_ it gets instantiated, as we need to rely on
// this method while initializing the engine.
typedef void (*EditorHelpLoadXmlBufferFunc)(const uint8_t *p_buffer, int p_size);
static EditorHelpLoadXmlBufferFunc editor_help_load_xml_buffer;
typedef void (*EditorHelpRemoveClassFunc)(const String &p_class);
static EditorHelpRemoveClassFunc editor_help_remove_class;
public:
static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
static void remove_class(const String &p_class);
};
#endif // TOOLS_ENABLED
#endif // GDEXTENSION_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,394 +0,0 @@
/**************************************************************************/
/* gdextension_library_loader.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "gdextension_library_loader.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/version.h"
#include "gdextension.h"
Vector<SharedObject> GDExtensionLibraryLoader::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) {
Vector<SharedObject> dependencies_shared_objects;
if (p_config->has_section("dependencies")) {
List<String> config_dependencies;
p_config->get_section_keys("dependencies", &config_dependencies);
for (const String &dependency : config_dependencies) {
Vector<String> dependency_tags = dependency.split(".");
bool all_tags_met = true;
for (int i = 0; i < dependency_tags.size(); i++) {
String tag = dependency_tags[i].strip_edges();
if (!p_has_feature(tag)) {
all_tags_met = false;
break;
}
}
if (all_tags_met) {
Dictionary dependency_value = p_config->get_value("dependencies", dependency);
for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) {
String dependency_path = *key;
String target_path = dependency_value[*key];
if (dependency_path.is_relative_path()) {
dependency_path = p_path.get_base_dir().path_join(dependency_path);
}
dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path));
}
break;
}
}
}
return dependencies_shared_objects;
}
String GDExtensionLibraryLoader::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) {
// First, check the explicit libraries.
if (p_config->has_section("libraries")) {
List<String> libraries;
p_config->get_section_keys("libraries", &libraries);
// Iterate the libraries, finding the best matching tags.
String best_library_path;
Vector<String> best_library_tags;
for (const String &E : libraries) {
Vector<String> tags = E.split(".");
bool all_tags_met = true;
for (int i = 0; i < tags.size(); i++) {
String tag = tags[i].strip_edges();
if (!p_has_feature(tag)) {
all_tags_met = false;
break;
}
}
if (all_tags_met && tags.size() > best_library_tags.size()) {
best_library_path = p_config->get_value("libraries", E);
best_library_tags = tags;
}
}
if (!best_library_path.is_empty()) {
if (best_library_path.is_relative_path()) {
best_library_path = p_path.get_base_dir().path_join(best_library_path);
}
if (r_tags != nullptr) {
r_tags->append_array(best_library_tags);
}
return best_library_path;
}
}
// Second, try to autodetect.
String autodetect_library_prefix;
if (p_config->has_section_key("configuration", "autodetect_library_prefix")) {
autodetect_library_prefix = p_config->get_value("configuration", "autodetect_library_prefix");
}
if (!autodetect_library_prefix.is_empty()) {
String autodetect_path = autodetect_library_prefix;
if (autodetect_path.is_relative_path()) {
autodetect_path = p_path.get_base_dir().path_join(autodetect_path);
}
// Find the folder and file parts of the prefix.
String folder;
String file_prefix;
if (DirAccess::dir_exists_absolute(autodetect_path)) {
folder = autodetect_path;
} else if (DirAccess::dir_exists_absolute(autodetect_path.get_base_dir())) {
folder = autodetect_path.get_base_dir();
file_prefix = autodetect_path.get_file();
} else {
ERR_FAIL_V_MSG(String(), vformat("Error in extension: %s. Could not find folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
}
// Open the folder.
Ref<DirAccess> dir = DirAccess::open(folder);
ERR_FAIL_COND_V_MSG(dir.is_null(), String(), vformat("Error in extension: %s. Could not open folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
// Iterate the files and check the prefixes, finding the best matching file.
String best_file;
Vector<String> best_file_tags;
dir->list_dir_begin();
String file_name = dir->_get_next();
while (file_name != "") {
if (!dir->current_is_dir() && file_name.begins_with(file_prefix)) {
// Check if the files matches all requested feature tags.
String tags_str = file_name.trim_prefix(file_prefix);
tags_str = tags_str.trim_suffix(tags_str.get_extension());
Vector<String> tags = tags_str.split(".", false);
bool all_tags_met = true;
for (int i = 0; i < tags.size(); i++) {
String tag = tags[i].strip_edges();
if (!p_has_feature(tag)) {
all_tags_met = false;
break;
}
}
// If all tags are found in the feature list, and we found more tags than before, use this file.
if (all_tags_met && tags.size() > best_file_tags.size()) {
best_file_tags = tags;
best_file = file_name;
}
}
file_name = dir->_get_next();
}
if (!best_file.is_empty()) {
String library_path = folder.path_join(best_file);
if (r_tags != nullptr) {
r_tags->append_array(best_file_tags);
}
return library_path;
}
}
return String();
}
Error GDExtensionLibraryLoader::open_library(const String &p_path) {
Error err = parse_gdextension_file(p_path);
if (err != OK) {
return err;
}
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
Vector<String> abs_dependencies_paths;
if (!library_dependencies.is_empty()) {
for (const SharedObject &dependency : library_dependencies) {
abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path));
}
}
OS::GDExtensionData data = {
true, // also_set_library_path
&library_path, // r_resolved_path
Engine::get_singleton()->is_editor_hint(), // generate_temp_files
&abs_dependencies_paths, // library_dependencies
};
err = OS::get_singleton()->open_dynamic_library(is_static_library ? String() : abs_path, library, &data);
if (err != OK) {
return err;
}
return OK;
}
Error GDExtensionLibraryLoader::initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) {
#ifdef TOOLS_ENABLED
p_extension->set_reloadable(is_reloadable && Engine::get_singleton()->is_extension_reloading_enabled());
#endif
for (const KeyValue<String, String> &icon : class_icon_paths) {
p_extension->class_icon_paths[icon.key] = icon.value;
}
void *entry_funcptr = nullptr;
Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, entry_symbol, entry_funcptr, false);
if (err != OK) {
ERR_PRINT(vformat("GDExtension entry point '%s' not found in library %s.", entry_symbol, library_path));
return err;
}
GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
GDExtensionBool ret = initialization_function(p_get_proc_address, p_extension.ptr(), r_initialization);
if (ret) {
return OK;
} else {
ERR_PRINT(vformat("GDExtension initialization function '%s' returned an error.", entry_symbol));
return FAILED;
}
}
void GDExtensionLibraryLoader::close_library() {
OS::get_singleton()->close_dynamic_library(library);
library = nullptr;
}
bool GDExtensionLibraryLoader::is_library_open() const {
return library != nullptr;
}
bool GDExtensionLibraryLoader::has_library_changed() const {
#ifdef TOOLS_ENABLED
// Check only that the last modified time is different (rather than checking
// that it's newer) since some OS's (namely Windows) will preserve the modified
// time by default when copying files.
if (FileAccess::get_modified_time(resource_path) != resource_last_modified_time) {
return true;
}
if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
return true;
}
#endif
return false;
}
bool GDExtensionLibraryLoader::library_exists() const {
return FileAccess::exists(resource_path);
}
Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
resource_path = p_path;
Ref<ConfigFile> config;
config.instantiate();
Error err = config->load(p_path);
if (err != OK) {
ERR_PRINT(vformat("Error loading GDExtension configuration file: '%s'.", p_path));
return err;
}
if (!config->has_section_key("configuration", "entry_symbol")) {
ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: '%s'.", p_path));
return ERR_INVALID_DATA;
}
entry_symbol = config->get_value("configuration", "entry_symbol");
uint32_t compatibility_minimum[3] = { 0, 0, 0 };
if (config->has_section_key("configuration", "compatibility_minimum")) {
String compat_string = config->get_value("configuration", "compatibility_minimum");
Vector<int> parts = compat_string.split_ints(".");
for (int i = 0; i < parts.size(); i++) {
if (i >= 3) {
break;
}
if (parts[i] >= 0) {
compatibility_minimum[i] = parts[i];
}
}
} else {
ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: '%s'.", p_path));
return ERR_INVALID_DATA;
}
if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) {
ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
return ERR_INVALID_DATA;
}
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];
} else {
compatible = 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));
return ERR_INVALID_DATA;
}
// Optionally check maximum compatibility.
if (config->has_section_key("configuration", "compatibility_maximum")) {
uint32_t compatibility_maximum[3] = { 0, 0, 0 };
String compat_string = config->get_value("configuration", "compatibility_maximum");
Vector<int> parts = compat_string.split_ints(".");
for (int i = 0; i < 3; i++) {
if (i < parts.size() && parts[i] >= 0) {
compatibility_maximum[i] = parts[i];
} else {
// If a version part is missing, set the maximum to an arbitrary high value.
compatibility_maximum[i] = 9999;
}
}
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 VERSION_PATCH
// #if check to avoid -Wtype-limits warning when 0.
else {
compatible = VERSION_PATCH <= compatibility_maximum[2];
}
#endif
if (!compatible) {
ERR_PRINT(vformat("GDExtension only compatible with Godot version %s or earlier: %s", compat_string, p_path));
return ERR_INVALID_DATA;
}
}
library_path = find_extension_library(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
if (library_path.is_empty()) {
const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
return ERR_FILE_NOT_FOUND;
}
is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework");
if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
library_path = p_path.get_base_dir().path_join(library_path);
}
#ifdef TOOLS_ENABLED
is_reloadable = config->get_value("configuration", "reloadable", false);
update_last_modified_time(
FileAccess::get_modified_time(resource_path),
FileAccess::get_modified_time(library_path));
#endif
library_dependencies = find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
// Handle icons if any are specified.
if (config->has_section("icons")) {
List<String> keys;
config->get_section_keys("icons", &keys);
for (const String &key : keys) {
String icon_path = config->get_value("icons", key);
if (icon_path.is_relative_path()) {
icon_path = p_path.get_base_dir().path_join(icon_path);
}
class_icon_paths[key] = icon_path;
}
}
return OK;
}

View file

@ -1,85 +0,0 @@
/**************************************************************************/
/* gdextension_library_loader.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_LIBRARY_LOADER_H
#define GDEXTENSION_LIBRARY_LOADER_H
#include <functional>
#include "core/extension/gdextension_loader.h"
#include "core/io/config_file.h"
#include "core/os/shared_object.h"
class GDExtensionLibraryLoader : public GDExtensionLoader {
friend class GDExtensionManager;
friend class GDExtension;
private:
String resource_path;
void *library = nullptr; // pointer if valid.
String library_path;
String entry_symbol;
bool is_static_library = false;
#ifdef TOOLS_ENABLED
bool is_reloadable = false;
#endif
Vector<SharedObject> library_dependencies;
HashMap<String, String> class_icon_paths;
#ifdef TOOLS_ENABLED
uint64_t resource_last_modified_time = 0;
uint64_t library_last_modified_time = 0;
void update_last_modified_time(uint64_t p_resource_last_modified_time, uint64_t p_library_last_modified_time) {
resource_last_modified_time = p_resource_last_modified_time;
library_last_modified_time = p_library_last_modified_time;
}
#endif
public:
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature);
virtual Error open_library(const String &p_path) override;
virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) override;
virtual void close_library() override;
virtual bool is_library_open() const override;
virtual bool has_library_changed() const override;
virtual bool library_exists() const override;
Error parse_gdextension_file(const String &p_path);
};
#endif // GDEXTENSION_LIBRARY_LOADER_H

View file

@ -1,48 +0,0 @@
/**************************************************************************/
/* gdextension_loader.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_LOADER_H
#define GDEXTENSION_LOADER_H
#include "core/object/ref_counted.h"
class GDExtension;
class GDExtensionLoader : public RefCounted {
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;
virtual void close_library() = 0;
virtual bool is_library_open() const = 0;
virtual bool has_library_changed() const = 0;
virtual bool library_exists() const = 0;
};
#endif // GDEXTENSION_LOADER_H

View file

@ -1,432 +0,0 @@
/**************************************************************************/
/* gdextension_manager.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "gdextension_manager.h"
#include "core/extension/gdextension_library_loader.h"
#include "core/extension/gdextension_special_compat_hashes.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/object/script_language.h"
GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load) {
if (level >= 0) { // Already initialized up to some level.
int32_t minimum_level = 0;
if (!p_first_load) {
minimum_level = p_extension->get_minimum_library_initialization_level();
if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
}
// Initialize up to current level.
for (int32_t i = minimum_level; i <= level; i++) {
p_extension->initialize_library(GDExtension::InitializationLevel(i));
}
}
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
gdextension_class_icon_paths[kv.key] = kv.value;
}
#ifdef TOOLS_ENABLED
// Signals that a new extension is loaded so GDScript can register new class names.
emit_signal("extension_loaded", p_extension);
#endif
return LOAD_STATUS_OK;
}
GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(const Ref<GDExtension> &p_extension) {
#ifdef TOOLS_ENABLED
// Signals that a new extension is unloading so GDScript can unregister class names.
emit_signal("extension_unloading", p_extension);
#endif
if (level >= 0) { // Already initialized up to some level.
// Deinitialize down from current level.
for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
}
}
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
gdextension_class_icon_paths.erase(kv.key);
}
return LOAD_STATUS_OK;
}
GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return LOAD_STATUS_FAILED;
}
Ref<GDExtensionLibraryLoader> loader;
loader.instantiate();
return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader);
}
GDExtensionManager::LoadStatus GDExtensionManager::load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader) {
DEV_ASSERT(p_loader.is_valid());
if (gdextension_map.has(p_path)) {
return LOAD_STATUS_ALREADY_LOADED;
}
Ref<GDExtension> extension;
extension.instantiate();
Error err = extension->open_library(p_path, p_loader);
if (err != OK) {
return LOAD_STATUS_FAILED;
}
LoadStatus status = _load_extension_internal(extension, true);
if (status != LOAD_STATUS_OK) {
return status;
}
extension->set_path(p_path);
gdextension_map[p_path] = extension;
return LOAD_STATUS_OK;
}
GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String &p_path) {
#ifndef TOOLS_ENABLED
ERR_FAIL_V_MSG(LOAD_STATUS_FAILED, "GDExtensions can only be reloaded in an editor build.");
#else
ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled.");
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return LOAD_STATUS_FAILED;
}
if (!gdextension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
Ref<GDExtension> extension = gdextension_map[p_path];
ERR_FAIL_COND_V_MSG(!extension->is_reloadable(), LOAD_STATUS_FAILED, vformat("This GDExtension is not marked as 'reloadable' or doesn't support reloading: %s.", p_path));
LoadStatus status;
extension->prepare_reload();
// Unload library if it's open. It may not be open if the developer made a
// change that broke loading in a previous hot-reload attempt.
if (extension->is_library_open()) {
status = _unload_extension_internal(extension);
if (status != LOAD_STATUS_OK) {
// We need to clear these no matter what.
extension->clear_instance_bindings();
return status;
}
extension->clear_instance_bindings();
extension->close_library();
}
Error err = extension->open_library(p_path, extension->loader);
if (err != OK) {
return LOAD_STATUS_FAILED;
}
status = _load_extension_internal(extension, false);
if (status != LOAD_STATUS_OK) {
return status;
}
extension->finish_reload();
return LOAD_STATUS_OK;
#endif
}
GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return LOAD_STATUS_FAILED;
}
if (!gdextension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
Ref<GDExtension> extension = gdextension_map[p_path];
LoadStatus status = _unload_extension_internal(extension);
if (status != LOAD_STATUS_OK) {
return status;
}
gdextension_map.erase(p_path);
return LOAD_STATUS_OK;
}
bool GDExtensionManager::is_extension_loaded(const String &p_path) const {
return gdextension_map.has(p_path);
}
Vector<String> GDExtensionManager::get_loaded_extensions() const {
Vector<String> ret;
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
ret.push_back(E.key);
}
return ret;
}
Ref<GDExtension> GDExtensionManager::get_extension(const String &p_path) {
HashMap<String, Ref<GDExtension>>::Iterator E = gdextension_map.find(p_path);
ERR_FAIL_COND_V(!E, Ref<GDExtension>());
return E->value;
}
bool GDExtensionManager::class_has_icon_path(const String &p_class) const {
// TODO: Check that the icon belongs to a registered class somehow.
return gdextension_class_icon_paths.has(p_class);
}
String GDExtensionManager::class_get_icon_path(const String &p_class) const {
// TODO: Check that the icon belongs to a registered class somehow.
if (gdextension_class_icon_paths.has(p_class)) {
return gdextension_class_icon_paths[p_class];
}
return "";
}
void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return;
}
ERR_FAIL_COND(int32_t(p_level) - 1 != level);
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->initialize_library(p_level);
if (p_level == GDExtension::INITIALIZATION_LEVEL_EDITOR) {
for (const KeyValue<String, String> &kv : E.value->class_icon_paths) {
gdextension_class_icon_paths[kv.key] = kv.value;
}
}
}
level = p_level;
}
void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) {
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return;
}
ERR_FAIL_COND(int32_t(p_level) != level);
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->deinitialize_library(p_level);
}
level = int32_t(p_level) - 1;
}
#ifdef TOOLS_ENABLED
void GDExtensionManager::track_instance_binding(void *p_token, Object *p_object) {
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
if (E.value.ptr() == p_token) {
if (E.value->is_reloadable()) {
E.value->track_instance_binding(p_object);
return;
}
}
}
}
void GDExtensionManager::untrack_instance_binding(void *p_token, Object *p_object) {
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
if (E.value.ptr() == p_token) {
if (E.value->is_reloadable()) {
E.value->untrack_instance_binding(p_object);
return;
}
}
}
}
void GDExtensionManager::_reload_all_scripts() {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->reload_all_scripts();
}
}
#endif // TOOLS_ENABLED
void GDExtensionManager::load_extensions() {
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return;
}
Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
while (f.is_valid() && !f->eof_reached()) {
String s = f->get_line().strip_edges();
if (!s.is_empty()) {
LoadStatus err = load_extension(s);
ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, vformat("Error loading extension: '%s'.", s));
}
}
OS::get_singleton()->load_platform_gdextensions();
}
void GDExtensionManager::reload_extensions() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_recovery_mode_hint()) {
return;
}
bool reloaded = false;
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
if (!E.value->is_reloadable()) {
continue;
}
if (E.value->has_library_changed()) {
reloaded = true;
reload_extension(E.value->get_path());
}
}
if (reloaded) {
emit_signal("extensions_reloaded");
// Reload all scripts to clear out old references.
callable_mp_static(&GDExtensionManager::_reload_all_scripts).call_deferred();
}
#endif
}
bool GDExtensionManager::ensure_extensions_loaded(const HashSet<String> &p_extensions) {
Vector<String> extensions_added;
Vector<String> extensions_removed;
for (const String &E : p_extensions) {
if (!is_extension_loaded(E)) {
extensions_added.push_back(E);
}
}
Vector<String> loaded_extensions = get_loaded_extensions();
for (const String &loaded_extension : loaded_extensions) {
if (!p_extensions.has(loaded_extension)) {
// The extension may not have a .gdextension file.
const Ref<GDExtension> extension = GDExtensionManager::get_singleton()->get_extension(loaded_extension);
if (!extension->get_loader()->library_exists()) {
extensions_removed.push_back(loaded_extension);
}
}
}
String extension_list_config_file = GDExtension::get_extension_list_config_file();
if (p_extensions.size()) {
if (extensions_added.size() || extensions_removed.size()) {
// Extensions were added or removed.
Ref<FileAccess> f = FileAccess::open(extension_list_config_file, FileAccess::WRITE);
for (const String &E : p_extensions) {
f->store_line(E);
}
}
} else {
if (loaded_extensions.size() || FileAccess::exists(extension_list_config_file)) {
// Extensions were removed.
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
da->remove(extension_list_config_file);
}
}
bool needs_restart = false;
for (const String &extension : extensions_added) {
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->load_extension(extension);
if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
needs_restart = true;
}
}
for (const String &extension : extensions_removed) {
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->unload_extension(extension);
if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
needs_restart = true;
}
}
#ifdef TOOLS_ENABLED
if (extensions_added.size() || extensions_removed.size()) {
// Emitting extensions_reloaded so EditorNode can reload Inspector and regenerate documentation.
emit_signal("extensions_reloaded");
// Reload all scripts to clear out old references.
callable_mp_static(&GDExtensionManager::_reload_all_scripts).call_deferred();
}
#endif
return needs_restart;
}
GDExtensionManager *GDExtensionManager::get_singleton() {
return singleton;
}
void GDExtensionManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension);
ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension);
ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension);
ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded);
ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &GDExtensionManager::get_loaded_extensions);
ClassDB::bind_method(D_METHOD("get_extension", "path"), &GDExtensionManager::get_extension);
BIND_ENUM_CONSTANT(LOAD_STATUS_OK);
BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED);
BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED);
BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED);
BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
ADD_SIGNAL(MethodInfo("extensions_reloaded"));
ADD_SIGNAL(MethodInfo("extension_loaded", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
ADD_SIGNAL(MethodInfo("extension_unloading", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
}
GDExtensionManager *GDExtensionManager::singleton = nullptr;
GDExtensionManager::GDExtensionManager() {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
#ifndef DISABLE_DEPRECATED
GDExtensionSpecialCompatHashes::initialize();
#endif
}
GDExtensionManager::~GDExtensionManager() {
if (singleton == this) {
singleton = nullptr;
}
#ifndef DISABLE_DEPRECATED
GDExtensionSpecialCompatHashes::finalize();
#endif
}

View file

@ -1,96 +0,0 @@
/**************************************************************************/
/* gdextension_manager.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_MANAGER_H
#define GDEXTENSION_MANAGER_H
#include "core/extension/gdextension.h"
class GDExtensionManager : public Object {
GDCLASS(GDExtensionManager, Object);
int32_t level = -1;
HashMap<String, Ref<GDExtension>> gdextension_map;
HashMap<String, String> gdextension_class_icon_paths;
static void _bind_methods();
static GDExtensionManager *singleton;
public:
enum LoadStatus {
LOAD_STATUS_OK,
LOAD_STATUS_FAILED,
LOAD_STATUS_ALREADY_LOADED,
LOAD_STATUS_NOT_LOADED,
LOAD_STATUS_NEEDS_RESTART,
};
private:
LoadStatus _load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load);
LoadStatus _unload_extension_internal(const Ref<GDExtension> &p_extension);
#ifdef TOOLS_ENABLED
static void _reload_all_scripts();
#endif
public:
LoadStatus load_extension(const String &p_path);
LoadStatus load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
LoadStatus reload_extension(const String &p_path);
LoadStatus unload_extension(const String &p_path);
bool is_extension_loaded(const String &p_path) const;
Vector<String> get_loaded_extensions() const;
Ref<GDExtension> get_extension(const String &p_path);
bool class_has_icon_path(const String &p_class) const;
String class_get_icon_path(const String &p_class) const;
void initialize_extensions(GDExtension::InitializationLevel p_level);
void deinitialize_extensions(GDExtension::InitializationLevel p_level);
#ifdef TOOLS_ENABLED
void track_instance_binding(void *p_token, Object *p_object);
void untrack_instance_binding(void *p_token, Object *p_object);
#endif
static GDExtensionManager *get_singleton();
void load_extensions();
void reload_extensions();
bool ensure_extensions_loaded(const HashSet<String> &p_extensions);
GDExtensionManager();
~GDExtensionManager();
};
VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus)
#endif // GDEXTENSION_MANAGER_H

File diff suppressed because it is too large Load diff

View file

@ -1,62 +0,0 @@
/**************************************************************************/
/* gdextension_special_compat_hashes.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H
#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H
#ifndef DISABLE_DEPRECATED
#include "core/string/string_name.h"
#include "core/templates/hash_map.h"
#include "core/templates/local_vector.h"
// Note: In most situations, compatibility methods should be registered via ClassDB::bind_compatibility_method().
// This class is only meant to be used in exceptional circumstances, for example, when Godot's hashing
// algorithm changes and registering compatibility methods for all affect methods would be onerous.
class GDExtensionSpecialCompatHashes {
struct Mapping {
StringName method;
uint32_t legacy_hash;
uint32_t current_hash;
};
static HashMap<StringName, LocalVector<Mapping>> mappings;
public:
static void initialize();
static void finalize();
static bool lookup_current_hash(const StringName &p_class, const StringName &p_method, uint32_t p_legacy_hash, uint32_t *r_current_hash);
static bool get_legacy_hashes(const StringName &p_class, const StringName &p_method, Array &r_hashes, bool p_check_valid = true);
};
#endif // DISABLE_DEPRECATED
#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H

View file

@ -1,55 +0,0 @@
import zlib
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
#ifdef TOOLS_ENABLED
#include "core/io/compression.h"
#include "core/io/file_access.h"
#include "core/string/ustring.h"
"""
)
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());
};
};
#endif // TOOLS_ENABLED
#endif // GDEXTENSION_INTERFACE_DUMP_H
"""
)

View file

@ -1,144 +0,0 @@
proto_mod = """
#define MODBIND$VER($RETTYPE m_name$ARG) \\
virtual $RETVAL _##m_name($FUNCARGS) $CONST; \\
_FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
$RETX _##m_name($CALLARGS);\\
}
"""
def generate_mod_version(argcount, const=False, returns=False):
s = proto_mod
sproto = str(argcount)
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
s = s.replace("$RETVAL", "m_ret")
s = s.replace("$RETX", "return")
else:
s = s.replace("$RETTYPE", "")
s = s.replace("$RETVAL", "void")
s = s.replace("$RETX", "")
if const:
sproto += "C"
s = s.replace("$CONST", "const")
else:
s = s.replace("$CONST", "")
s = s.replace("$VER", sproto)
argtext = ""
funcargs = ""
callargs = ""
for i in range(argcount):
if i > 0:
funcargs += ", "
callargs += ", "
argtext += ", m_type" + str(i + 1)
funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
callargs += "arg" + str(i + 1)
if argcount:
s = s.replace("$ARG", argtext)
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
else:
s = s.replace("$ARG", "")
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
return s
proto_ex = """
#define EXBIND$VER($RETTYPE m_name$ARG) \\
GDVIRTUAL$VER_REQUIRED($RETTYPE_##m_name$ARG)\\
virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
$RETPRE\\
GDVIRTUAL_CALL(_##m_name$CALLARGS$RETREF);\\
$RETPOST\\
}
"""
def generate_ex_version(argcount, const=False, returns=False):
s = proto_ex
sproto = str(argcount)
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
s = s.replace("$RETVAL", "m_ret")
s = s.replace("$RETPRE", "m_ret ret; ZeroInitializer<m_ret>::initialize(ret);\\\n")
s = s.replace("$RETPOST", "return ret;\\\n")
else:
s = s.replace("$RETTYPE", "")
s = s.replace("$RETVAL", "void")
s = s.replace("$RETPRE", "")
s = s.replace("$RETPOST", "return;")
if const:
sproto += "C"
s = s.replace("$CONST", "const")
else:
s = s.replace("$CONST", "")
s = s.replace("$VER", sproto)
argtext = ""
funcargs = ""
callargs = ""
for i in range(argcount):
if i > 0:
funcargs += ", "
argtext += ", m_type" + str(i + 1)
funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
callargs += ", arg" + str(i + 1)
if argcount:
s = s.replace("$ARG", argtext)
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
else:
s = s.replace("$ARG", "")
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
if returns:
s = s.replace("$RETREF", ", ret")
else:
s = s.replace("$RETREF", "")
return s
def run(target, source, env):
max_versions = 12
txt = """
#ifndef GDEXTENSION_WRAPPERS_GEN_H
#define GDEXTENSION_WRAPPERS_GEN_H
"""
for i in range(max_versions + 1):
txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n"
txt += generate_ex_version(i, False, False)
txt += generate_ex_version(i, False, True)
txt += generate_ex_version(i, True, False)
txt += generate_ex_version(i, True, True)
for i in range(max_versions + 1):
txt += "\n/* Module Wrapper " + str(i) + " Arguments */\n"
txt += generate_mod_version(i, False, False)
txt += generate_mod_version(i, False, True)
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

@ -1,21 +0,0 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
import input_builders
# Order matters here. Higher index controller database files write on top of lower index database files.
controller_databases = [
"gamecontrollerdb.txt",
"godotcontrollerdb.txt",
]
gensource = env.CommandNoCache(
"default_controller_mappings.gen.cpp",
controller_databases,
env.Run(input_builders.make_default_controller_mappings),
)
env.add_source_files(env.core_sources, "*.cpp")
env.add_source_files(env.core_sources, gensource)

View file

@ -1,39 +0,0 @@
/**************************************************************************/
/* default_controller_mappings.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DEFAULT_CONTROLLER_MAPPINGS_H
#define DEFAULT_CONTROLLER_MAPPINGS_H
class DefaultControllerMappings {
public:
static const char *mappings[];
};
#endif // DEFAULT_CONTROLLER_MAPPINGS_H

File diff suppressed because it is too large Load diff

View file

@ -1,35 +0,0 @@
# Game Controller DB for Godot in SDL 2.0.16 format
# Source: https://github.com/godotengine/godot
# Windows
__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
# Android
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
# Web
standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:+a4,righttrigger:+a5,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Web,
Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Web,
MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Web
Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web

View file

@ -1,41 +0,0 @@
/**************************************************************************/
/* input.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
void Input::_vibrate_handheld_bind_compat_91143(int p_duration_ms) {
vibrate_handheld(p_duration_ms, -1.0);
}
void Input::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::_vibrate_handheld_bind_compat_91143, DEFVAL(500));
}
#endif // DISABLE_DEPRECATED

File diff suppressed because it is too large Load diff

View file

@ -1,407 +0,0 @@
/**************************************************************************/
/* input.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INPUT_H
#define INPUT_H
#include "core/input/input_event.h"
#include "core/object/object.h"
#include "core/os/keyboard.h"
#include "core/os/thread_safe.h"
#include "core/templates/rb_set.h"
#include "core/variant/typed_array.h"
class Input : public Object {
GDCLASS(Input, Object);
_THREAD_SAFE_CLASS_
static Input *singleton;
static constexpr uint64_t MAX_EVENT = 32;
public:
// Keep synced with "DisplayServer::MouseMode" enum.
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED,
MOUSE_MODE_CONFINED,
MOUSE_MODE_CONFINED_HIDDEN,
MOUSE_MODE_MAX,
};
#undef CursorShape
enum CursorShape {
CURSOR_ARROW,
CURSOR_IBEAM,
CURSOR_POINTING_HAND,
CURSOR_CROSS,
CURSOR_WAIT,
CURSOR_BUSY,
CURSOR_DRAG,
CURSOR_CAN_DROP,
CURSOR_FORBIDDEN,
CURSOR_VSIZE,
CURSOR_HSIZE,
CURSOR_BDIAGSIZE,
CURSOR_FDIAGSIZE,
CURSOR_MOVE,
CURSOR_VSPLIT,
CURSOR_HSPLIT,
CURSOR_HELP,
CURSOR_MAX
};
enum {
JOYPADS_MAX = 16,
};
typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
private:
BitField<MouseButtonMask> mouse_button_mask;
RBSet<Key> key_label_pressed;
RBSet<Key> physical_keys_pressed;
RBSet<Key> keys_pressed;
RBSet<JoyButton> joy_buttons_pressed;
RBMap<JoyAxis, float> _joy_axis;
//RBMap<StringName,int> custom_action_press;
bool gravity_enabled = false;
Vector3 gravity;
bool accelerometer_enabled = false;
Vector3 accelerometer;
bool magnetometer_enabled = false;
Vector3 magnetometer;
bool gyroscope_enabled = false;
Vector3 gyroscope;
Vector2 mouse_pos;
int64_t mouse_window = 0;
bool legacy_just_pressed_behavior = false;
bool disable_input = false;
struct ActionState {
uint64_t pressed_physics_frame = UINT64_MAX;
uint64_t pressed_process_frame = UINT64_MAX;
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
bool exact = true;
struct DeviceState {
bool pressed[MAX_EVENT] = { false };
float strength[MAX_EVENT] = { 0.0 };
float raw_strength[MAX_EVENT] = { 0.0 };
};
bool api_pressed = false;
float api_strength = 0.0;
HashMap<int, DeviceState> device_states;
// Cache.
struct ActionStateCache {
bool pressed = false;
float strength = false;
float raw_strength = false;
} cache;
};
HashMap<StringName, ActionState> action_states;
bool emulate_touch_from_mouse = false;
bool emulate_mouse_from_touch = false;
bool agile_input_event_flushing = false;
bool use_accumulated_input = true;
int mouse_from_touch_index = -1;
struct VibrationInfo {
float weak_magnitude;
float strong_magnitude;
float duration; // Duration in seconds
uint64_t timestamp;
};
HashMap<int, VibrationInfo> joy_vibration;
struct VelocityTrack {
uint64_t last_tick = 0;
Vector2 velocity;
Vector2 screen_velocity;
Vector2 accum;
Vector2 screen_accum;
float accum_t = 0.0f;
float min_ref_frame;
float max_ref_frame;
void update(const Vector2 &p_delta_p, const Vector2 &p_screen_delta_p);
void reset();
VelocityTrack();
};
struct Joypad {
StringName name;
StringName uid;
bool connected = false;
bool last_buttons[(size_t)JoyButton::MAX] = { false };
float last_axis[(size_t)JoyAxis::MAX] = { 0.0f };
HatMask last_hat = HatMask::CENTER;
int mapping = -1;
int hat_current = 0;
Dictionary info;
};
VelocityTrack mouse_velocity_track;
HashMap<int, VelocityTrack> touch_velocity_track;
HashMap<int, Joypad> joy_names;
HashSet<uint32_t> ignored_device_ids;
int fallback_mapping = -1; // Index of the guid in map_db.
CursorShape default_shape = CURSOR_ARROW;
enum JoyType {
TYPE_BUTTON,
TYPE_AXIS,
TYPE_HAT,
TYPE_MAX,
};
enum JoyAxisRange {
NEGATIVE_HALF_AXIS = -1,
FULL_AXIS = 0,
POSITIVE_HALF_AXIS = 1
};
struct JoyEvent {
int type = TYPE_MAX;
int index = -1; // Can be either JoyAxis or JoyButton.
float value = 0.f;
};
struct JoyBinding {
JoyType inputType;
union {
JoyButton button;
struct {
JoyAxis axis;
JoyAxisRange range;
bool invert;
} axis;
struct {
HatDir hat;
HatMask hat_mask;
} hat;
} input;
JoyType outputType;
union {
JoyButton button;
struct {
JoyAxis axis;
JoyAxisRange range;
} axis;
} output;
};
struct JoyDeviceMapping {
String uid;
String name;
Vector<JoyBinding> bindings;
};
Vector<JoyDeviceMapping> map_db;
void _set_joypad_mapping(Joypad &p_js, int p_map_index);
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
JoyButton _get_output_button(const String &output);
JoyAxis _get_output_axis(const String &output);
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
void _update_action_cache(const StringName &p_action_name, ActionState &r_action_state);
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
List<Ref<InputEvent>> buffered_events;
#ifdef DEBUG_ENABLED
HashSet<Ref<InputEvent>> frame_parsed_events;
uint64_t last_parsed_frame = UINT64_MAX;
#endif
friend class DisplayServer;
static void (*set_mouse_mode_func)(MouseMode);
static MouseMode (*get_mouse_mode_func)();
static void (*set_mouse_mode_override_func)(MouseMode);
static MouseMode (*get_mouse_mode_override_func)();
static void (*set_mouse_mode_override_enabled_func)(bool);
static bool (*is_mouse_mode_override_enabled_func)();
static void (*warp_mouse_func)(const Vector2 &p_position);
static CursorShape (*get_current_cursor_shape_func)();
static void (*set_custom_mouse_cursor_func)(const Ref<Resource> &, CursorShape, const Vector2 &);
EventDispatchFunc event_dispatch_function = nullptr;
#ifndef DISABLE_DEPRECATED
void _vibrate_handheld_bind_compat_91143(int p_duration_ms = 500);
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED
protected:
static void _bind_methods();
public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
void set_mouse_mode_override(MouseMode p_mode);
MouseMode get_mouse_mode_override() const;
void set_mouse_mode_override_enabled(bool p_override_enabled);
bool is_mouse_mode_override_enabled();
#ifdef TOOLS_ENABLED
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
static Input *get_singleton();
bool is_anything_pressed() const;
bool is_anything_pressed_except_mouse() const;
bool is_key_pressed(Key p_keycode) const;
bool is_physical_key_pressed(Key p_keycode) const;
bool is_key_label_pressed(Key p_keycode) const;
bool is_mouse_button_pressed(MouseButton p_button) const;
bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
float get_action_strength(const StringName &p_action, bool p_exact = false) const;
float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
float get_joy_axis(int p_device, JoyAxis p_axis) const;
String get_joy_name(int p_idx);
TypedArray<int> get_connected_joypads();
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
void joy_connection_changed(int p_idx, bool p_connected, const String &p_name, const String &p_guid = "", const Dictionary &p_joypad_info = Dictionary());
Vector3 get_gravity() const;
Vector3 get_accelerometer() const;
Vector3 get_magnetometer() const;
Vector3 get_gyroscope() const;
Point2 get_mouse_position() const;
Vector2 get_last_mouse_velocity();
Vector2 get_last_mouse_screen_velocity();
BitField<MouseButtonMask> get_mouse_button_mask() const;
void warp_mouse(const Vector2 &p_position);
Point2 warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
void parse_input_event(const Ref<InputEvent> &p_event);
void set_gravity(const Vector3 &p_gravity);
void set_accelerometer(const Vector3 &p_accel);
void set_magnetometer(const Vector3 &p_magnetometer);
void set_gyroscope(const Vector3 &p_gyroscope);
void set_joy_axis(int p_device, JoyAxis p_axis, float p_value);
void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
void stop_joy_vibration(int p_device);
void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);
void set_mouse_position(const Point2 &p_posf);
void action_press(const StringName &p_action, float p_strength = 1.f);
void action_release(const StringName &p_action);
void set_emulate_touch_from_mouse(bool p_emulate);
bool is_emulating_touch_from_mouse() const;
void ensure_touch_mouse_raised();
void set_emulate_mouse_from_touch(bool p_emulate);
bool is_emulating_mouse_from_touch() const;
CursorShape get_default_cursor_shape() const;
void set_default_cursor_shape(CursorShape p_shape);
CursorShape get_current_cursor_shape() const;
void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
void parse_mapping(const String &p_mapping);
void joy_button(int p_device, JoyButton p_button, bool p_pressed);
void joy_axis(int p_device, JoyAxis p_axis, float p_value);
void joy_hat(int p_device, BitField<HatMask> p_val);
void add_joy_mapping(const String &p_mapping, bool p_update_existing = false);
void remove_joy_mapping(const String &p_guid);
int get_unused_joy_id();
bool is_joy_known(int p_device);
String get_joy_guid(int p_device) const;
bool should_ignore_device(int p_vendor_id, int p_product_id) const;
Dictionary get_joy_info(int p_device) const;
void set_fallback_mapping(const String &p_guid);
#ifdef DEBUG_ENABLED
void flush_frame_parsed_events();
#endif
void flush_buffered_events();
bool is_agile_input_event_flushing();
void set_agile_input_event_flushing(bool p_enable);
void set_use_accumulated_input(bool p_enable);
bool is_using_accumulated_input();
void release_pressed_events();
void set_event_dispatch_function(EventDispatchFunc p_function);
void set_disable_input(bool p_disable);
bool is_input_disabled() const;
Input();
~Input();
};
VARIANT_ENUM_CAST(Input::MouseMode);
VARIANT_ENUM_CAST(Input::CursorShape);
#endif // INPUT_H

View file

@ -1,59 +0,0 @@
"""Functions used to generate source files during build time"""
from collections import OrderedDict
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')
# 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:
# read mapping file and skip header
mapping_file_lines = f.readlines()[2:]
current_platform = None
for line in mapping_file_lines:
if not line:
continue
line = line.strip()
if len(line) == 0:
continue
if line[0] == "#":
current_platform = line[1:].strip()
if current_platform not in platform_mappings:
platform_mappings[current_platform] = {}
elif current_platform:
line_parts = line.split(",")
guid = line_parts[0]
if guid in platform_mappings[current_platform]:
g.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",
}
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
for platform, mappings in platform_mappings.items():
variable = platform_variables[platform]
g.write("{}\n".format(variable))
for mapping in mappings.values():
g.write('\t"{}",\n'.format(mapping))
g.write("#endif\n")
g.write("\tnullptr\n};\n")

View file

@ -1,141 +0,0 @@
/**************************************************************************/
/* input_enums.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INPUT_ENUMS_H
#define INPUT_ENUMS_H
#include "core/error/error_macros.h"
enum class HatDir {
UP = 0,
RIGHT = 1,
DOWN = 2,
LEFT = 3,
MAX = 4,
};
enum class HatMask {
CENTER = 0,
UP = 1,
RIGHT = 2,
DOWN = 4,
LEFT = 8,
};
enum class JoyAxis {
INVALID = -1,
LEFT_X = 0,
LEFT_Y = 1,
RIGHT_X = 2,
RIGHT_Y = 3,
TRIGGER_LEFT = 4,
TRIGGER_RIGHT = 5,
SDL_MAX = 6,
MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
};
enum class JoyButton {
INVALID = -1,
A = 0,
B = 1,
X = 2,
Y = 3,
BACK = 4,
GUIDE = 5,
START = 6,
LEFT_STICK = 7,
RIGHT_STICK = 8,
LEFT_SHOULDER = 9,
RIGHT_SHOULDER = 10,
DPAD_UP = 11,
DPAD_DOWN = 12,
DPAD_LEFT = 13,
DPAD_RIGHT = 14,
MISC1 = 15,
PADDLE1 = 16,
PADDLE2 = 17,
PADDLE3 = 18,
PADDLE4 = 19,
TOUCHPAD = 20,
SDL_MAX = 21,
MAX = 128, // Android supports up to 36 buttons. DirectInput supports up to 128 buttons.
};
enum class MIDIMessage {
NONE = 0,
NOTE_OFF = 0x8,
NOTE_ON = 0x9,
AFTERTOUCH = 0xA,
CONTROL_CHANGE = 0xB,
PROGRAM_CHANGE = 0xC,
CHANNEL_PRESSURE = 0xD,
PITCH_BEND = 0xE,
SYSTEM_EXCLUSIVE = 0xF0,
QUARTER_FRAME = 0xF1,
SONG_POSITION_POINTER = 0xF2,
SONG_SELECT = 0xF3,
TUNE_REQUEST = 0xF6,
TIMING_CLOCK = 0xF8,
START = 0xFA,
CONTINUE = 0xFB,
STOP = 0xFC,
ACTIVE_SENSING = 0xFE,
SYSTEM_RESET = 0xFF,
};
enum class MouseButton {
NONE = 0,
LEFT = 1,
RIGHT = 2,
MIDDLE = 3,
WHEEL_UP = 4,
WHEEL_DOWN = 5,
WHEEL_LEFT = 6,
WHEEL_RIGHT = 7,
MB_XBUTTON1 = 8, // "XBUTTON1" is a reserved word on Windows.
MB_XBUTTON2 = 9, // "XBUTTON2" is a reserved word on Windows.
};
enum class MouseButtonMask {
NONE = 0,
LEFT = (1 << (int(MouseButton::LEFT) - 1)),
RIGHT = (1 << (int(MouseButton::RIGHT) - 1)),
MIDDLE = (1 << (int(MouseButton::MIDDLE) - 1)),
MB_XBUTTON1 = (1 << (int(MouseButton::MB_XBUTTON1) - 1)),
MB_XBUTTON2 = (1 << (int(MouseButton::MB_XBUTTON2) - 1)),
};
inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
ERR_FAIL_COND_V(button == MouseButton::NONE, MouseButtonMask::NONE);
return MouseButtonMask(1 << ((int)button - 1));
}
#endif // INPUT_ENUMS_H

File diff suppressed because it is too large Load diff

View file

@ -1,599 +0,0 @@
/**************************************************************************/
/* input_event.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INPUT_EVENT_H
#define INPUT_EVENT_H
#include "core/input/input_enums.h"
#include "core/io/resource.h"
#include "core/math/transform_2d.h"
#include "core/os/keyboard.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
/**
* Input Event classes. These are used in the main loop.
* The events are pretty obvious.
*/
class Shortcut;
/**
* Input Modifier Status
* for keyboard/mouse events.
*/
class InputEvent : public Resource {
GDCLASS(InputEvent, Resource);
int device = 0;
protected:
bool canceled = false;
bool pressed = false;
static void _bind_methods();
public:
static const int DEVICE_ID_EMULATION;
static const int DEVICE_ID_INTERNAL;
void set_device(int p_device);
int get_device() const;
bool is_action(const StringName &p_action, bool p_exact_match = false) const;
bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
bool is_canceled() const;
bool is_pressed() const;
bool is_released() const;
virtual bool is_echo() const;
virtual String as_text() const = 0;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const;
virtual bool is_action_type() const;
virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
InputEvent() {}
};
class InputEventFromWindow : public InputEvent {
GDCLASS(InputEventFromWindow, InputEvent);
int64_t window_id = 0;
protected:
static void _bind_methods();
public:
void set_window_id(int64_t p_id);
int64_t get_window_id() const;
InputEventFromWindow() {}
};
class InputEventWithModifiers : public InputEventFromWindow {
GDCLASS(InputEventWithModifiers, InputEventFromWindow);
bool command_or_control_autoremap = false;
bool shift_pressed = false;
bool alt_pressed = false;
bool meta_pressed = false; // "Command" on macOS, "Meta/Win" key on other platforms.
bool ctrl_pressed = false;
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
public:
void set_command_or_control_autoremap(bool p_enabled);
bool is_command_or_control_autoremap() const;
bool is_command_or_control_pressed() const;
void set_shift_pressed(bool p_pressed);
bool is_shift_pressed() const;
void set_alt_pressed(bool p_pressed);
bool is_alt_pressed() const;
void set_ctrl_pressed(bool p_pressed);
bool is_ctrl_pressed() const;
void set_meta_pressed(bool p_pressed);
bool is_meta_pressed() const;
void set_modifiers_from_event(const InputEventWithModifiers *event);
BitField<KeyModifierMask> get_modifiers_mask() const;
virtual String as_text() const override;
virtual String to_string() override;
InputEventWithModifiers() {}
};
class InputEventKey : public InputEventWithModifiers {
GDCLASS(InputEventKey, InputEventWithModifiers);
Key keycode = Key::NONE; // Key enum, without modifier masks.
Key physical_keycode = Key::NONE;
Key key_label = Key::NONE;
uint32_t unicode = 0; ///unicode
KeyLocation location = KeyLocation::UNSPECIFIED;
bool echo = false; /// true if this is an echo key
protected:
static void _bind_methods();
public:
void set_pressed(bool p_pressed);
void set_keycode(Key p_keycode);
Key get_keycode() const;
void set_physical_keycode(Key p_keycode);
Key get_physical_keycode() const;
void set_key_label(Key p_key_label);
Key get_key_label() const;
void set_unicode(char32_t p_unicode);
char32_t get_unicode() const;
void set_location(KeyLocation p_key_location);
KeyLocation get_location() const;
void set_echo(bool p_enable);
virtual bool is_echo() const override;
Key get_keycode_with_modifiers() const;
Key get_physical_keycode_with_modifiers() const;
Key get_key_label_with_modifiers() const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
virtual String as_text_physical_keycode() const;
virtual String as_text_keycode() const;
virtual String as_text_key_label() const;
virtual String as_text_location() const;
virtual String as_text() const override;
virtual String to_string() override;
static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
InputEventKey() {}
};
class InputEventMouse : public InputEventWithModifiers {
GDCLASS(InputEventMouse, InputEventWithModifiers);
BitField<MouseButtonMask> button_mask;
Vector2 pos;
Vector2 global_pos;
protected:
static void _bind_methods();
public:
void set_button_mask(BitField<MouseButtonMask> p_mask);
BitField<MouseButtonMask> get_button_mask() const;
void set_position(const Vector2 &p_pos);
Vector2 get_position() const;
void set_global_position(const Vector2 &p_global_pos);
Vector2 get_global_position() const;
InputEventMouse() {}
};
class InputEventMouseButton : public InputEventMouse {
GDCLASS(InputEventMouseButton, InputEventMouse);
float factor = 1;
MouseButton button_index = MouseButton::NONE;
bool double_click = false; //last even less than double click time
protected:
static void _bind_methods();
public:
void set_factor(float p_factor);
float get_factor() const;
void set_button_index(MouseButton p_index);
MouseButton get_button_index() const;
void set_pressed(bool p_pressed);
void set_canceled(bool p_canceled);
void set_double_click(bool p_double_click);
bool is_double_click() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
virtual String as_text() const override;
virtual String to_string() override;
InputEventMouseButton() {}
};
class InputEventMouseMotion : public InputEventMouse {
GDCLASS(InputEventMouseMotion, InputEventMouse);
Vector2 tilt;
float pressure = 0;
Vector2 relative;
Vector2 screen_relative;
Vector2 velocity;
Vector2 screen_velocity;
bool pen_inverted = false;
protected:
static void _bind_methods();
public:
void set_tilt(const Vector2 &p_tilt);
Vector2 get_tilt() const;
void set_pressure(float p_pressure);
float get_pressure() const;
void set_pen_inverted(bool p_inverted);
bool get_pen_inverted() const;
void set_relative(const Vector2 &p_relative);
Vector2 get_relative() const;
void set_relative_screen_position(const Vector2 &p_relative);
Vector2 get_relative_screen_position() const;
void set_velocity(const Vector2 &p_velocity);
Vector2 get_velocity() const;
void set_screen_velocity(const Vector2 &p_velocity);
Vector2 get_screen_velocity() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
virtual bool accumulate(const Ref<InputEvent> &p_event) override;
InputEventMouseMotion() {}
};
class InputEventJoypadMotion : public InputEvent {
GDCLASS(InputEventJoypadMotion, InputEvent);
JoyAxis axis = (JoyAxis)0; ///< Joypad axis
float axis_value = 0; ///< -1 to 1
protected:
static void _bind_methods();
public:
void set_axis(JoyAxis p_axis);
JoyAxis get_axis() const;
void set_axis_value(float p_value);
float get_axis_value() const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
virtual String as_text() const override;
virtual String to_string() override;
static Ref<InputEventJoypadMotion> create_reference(JoyAxis p_axis, float p_value);
InputEventJoypadMotion() {}
};
class InputEventJoypadButton : public InputEvent {
GDCLASS(InputEventJoypadButton, InputEvent);
JoyButton button_index = (JoyButton)0;
float pressure = 0; //0 to 1
protected:
static void _bind_methods();
public:
void set_button_index(JoyButton p_index);
JoyButton get_button_index() const;
void set_pressed(bool p_pressed);
void set_pressure(float p_pressure);
float get_pressure() const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
virtual String as_text() const override;
virtual String to_string() override;
static Ref<InputEventJoypadButton> create_reference(JoyButton p_btn_index);
InputEventJoypadButton() {}
};
class InputEventScreenTouch : public InputEventFromWindow {
GDCLASS(InputEventScreenTouch, InputEventFromWindow);
int index = 0;
Vector2 pos;
bool double_tap = false;
protected:
static void _bind_methods();
public:
void set_index(int p_index);
int get_index() const;
void set_position(const Vector2 &p_pos);
Vector2 get_position() const;
void set_pressed(bool p_pressed);
void set_canceled(bool p_canceled);
void set_double_tap(bool p_double_tap);
bool is_double_tap() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
InputEventScreenTouch() {}
};
class InputEventScreenDrag : public InputEventFromWindow {
GDCLASS(InputEventScreenDrag, InputEventFromWindow);
int index = 0;
Vector2 pos;
Vector2 relative;
Vector2 screen_relative;
Vector2 velocity;
Vector2 screen_velocity;
Vector2 tilt;
float pressure = 0;
bool pen_inverted = false;
protected:
static void _bind_methods();
public:
void set_index(int p_index);
int get_index() const;
void set_tilt(const Vector2 &p_tilt);
Vector2 get_tilt() const;
void set_pressure(float p_pressure);
float get_pressure() const;
void set_pen_inverted(bool p_inverted);
bool get_pen_inverted() const;
void set_position(const Vector2 &p_pos);
Vector2 get_position() const;
void set_relative(const Vector2 &p_relative);
Vector2 get_relative() const;
void set_relative_screen_position(const Vector2 &p_relative);
Vector2 get_relative_screen_position() const;
void set_velocity(const Vector2 &p_velocity);
Vector2 get_velocity() const;
void set_screen_velocity(const Vector2 &p_velocity);
Vector2 get_screen_velocity() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
virtual bool accumulate(const Ref<InputEvent> &p_event) override;
InputEventScreenDrag() {}
};
class InputEventAction : public InputEvent {
GDCLASS(InputEventAction, InputEvent);
StringName action;
float strength = 1.0f;
int event_index = -1;
protected:
static void _bind_methods();
public:
void set_action(const StringName &p_action);
StringName get_action() const;
void set_pressed(bool p_pressed);
void set_strength(float p_strength);
float get_strength() const;
void set_event_index(int p_index);
int get_event_index() const;
virtual bool is_action(const StringName &p_action) const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
virtual String as_text() const override;
virtual String to_string() override;
InputEventAction() {}
};
class InputEventGesture : public InputEventWithModifiers {
GDCLASS(InputEventGesture, InputEventWithModifiers);
Vector2 pos;
protected:
static void _bind_methods();
public:
void set_position(const Vector2 &p_pos);
Vector2 get_position() const;
};
class InputEventMagnifyGesture : public InputEventGesture {
GDCLASS(InputEventMagnifyGesture, InputEventGesture);
real_t factor = 1.0;
protected:
static void _bind_methods();
public:
void set_factor(real_t p_factor);
real_t get_factor() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
InputEventMagnifyGesture() {}
};
class InputEventPanGesture : public InputEventGesture {
GDCLASS(InputEventPanGesture, InputEventGesture);
Vector2 delta;
protected:
static void _bind_methods();
public:
void set_delta(const Vector2 &p_delta);
Vector2 get_delta() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
InputEventPanGesture() {}
};
class InputEventMIDI : public InputEvent {
GDCLASS(InputEventMIDI, InputEvent);
int channel = 0;
MIDIMessage message = MIDIMessage::NONE;
int pitch = 0;
int velocity = 0;
int instrument = 0;
int pressure = 0;
int controller_number = 0;
int controller_value = 0;
protected:
static void _bind_methods();
public:
void set_channel(const int p_channel);
int get_channel() const;
void set_message(const MIDIMessage p_message);
MIDIMessage get_message() const;
void set_pitch(const int p_pitch);
int get_pitch() const;
void set_velocity(const int p_velocity);
int get_velocity() const;
void set_instrument(const int p_instrument);
int get_instrument() const;
void set_pressure(const int p_pressure);
int get_pressure() const;
void set_controller_number(const int p_controller_number);
int get_controller_number() const;
void set_controller_value(const int p_controller_value);
int get_controller_value() const;
virtual String as_text() const override;
virtual String to_string() override;
InputEventMIDI() {}
};
class InputEventShortcut : public InputEvent {
GDCLASS(InputEventShortcut, InputEvent);
Ref<Shortcut> shortcut;
protected:
static void _bind_methods();
public:
void set_shortcut(Ref<Shortcut> p_shortcut);
Ref<Shortcut> get_shortcut();
virtual String as_text() const override;
virtual String to_string() override;
InputEventShortcut();
};
#endif // INPUT_EVENT_H

View file

@ -1,41 +0,0 @@
/**************************************************************************/
/* input_map.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
void InputMap::_add_action_bind_compat_97281(const StringName &p_action, float p_deadzone) {
add_action(p_action, p_deadzone);
}
void InputMap::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::_add_action_bind_compat_97281, DEFVAL(0.5f));
}
#endif // DISABLE_DEPRECATED

View file

@ -1,868 +0,0 @@
/**************************************************************************/
/* input_map.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "input_map.h"
#include "input_map.compat.inc"
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/variant/typed_array.h"
InputMap *InputMap::singleton = nullptr;
int InputMap::ALL_DEVICES = -1;
void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
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("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);
ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
/**
* Returns an nonexistent action error message with a suggestion of the closest
* matching action name (if possible).
*/
String InputMap::suggest_actions(const StringName &p_action) const {
List<StringName> actions = get_actions();
StringName closest_action;
float closest_similarity = 0.0;
// Find the most action with the most similar name.
for (const StringName &action : actions) {
const float similarity = String(action).similarity(p_action);
if (similarity > closest_similarity) {
closest_action = action;
closest_similarity = similarity;
}
}
String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
if (closest_similarity >= 0.4) {
// Only include a suggestion in the error message if it's similar enough.
error_message += vformat(" Did you mean \"%s\"?", closest_action);
}
return error_message;
}
#ifdef TOOLS_ENABLED
void InputMap::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
const String pf = p_function;
bool first_argument_is_action = false;
if (p_idx == 0) {
first_argument_is_action = (pf == "has_action" || pf == "erase_action" ||
pf == "action_set_deadzone" || pf == "action_get_deadzone" ||
pf == "action_has_event" || pf == "action_add_event" || pf == "action_get_events" ||
pf == "action_erase_event" || pf == "action_erase_events");
}
if (first_argument_is_action || (p_idx == 1 && pf == "event_is_action")) {
// Cannot rely on `get_actions()`, otherwise the actions would be in the context of the Editor (no user-defined actions).
List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
for (const PropertyInfo &pi : pinfo) {
if (!pi.name.begins_with("input/")) {
continue;
}
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
r_options->push_back(name.quote());
}
}
Object::get_argument_options(p_function, p_idx, r_options);
}
#endif
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
ERR_FAIL_COND_MSG(input_map.has(p_action), vformat("InputMap already has action \"%s\".", String(p_action)));
input_map[p_action] = Action();
static int last_id = 1;
input_map[p_action].id = last_id;
input_map[p_action].deadzone = p_deadzone;
last_id++;
}
void InputMap::erase_action(const StringName &p_action) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
input_map.erase(p_action);
}
TypedArray<StringName> InputMap::_get_actions() {
TypedArray<StringName> ret;
List<StringName> actions = get_actions();
if (actions.is_empty()) {
return ret;
}
for (const StringName &E : actions) {
ret.push_back(E);
}
return ret;
}
List<StringName> InputMap::get_actions() const {
List<StringName> actions = List<StringName>();
if (input_map.is_empty()) {
return actions;
}
for (const KeyValue<StringName, Action> &E : input_map) {
actions.push_back(E.key);
}
return actions;
}
List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
ERR_FAIL_COND_V(p_event.is_null(), nullptr);
int i = 0;
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
int device = E->get()->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
if (r_event_index) {
*r_event_index = i;
}
return E;
}
}
i++;
}
return nullptr;
}
bool InputMap::has_action(const StringName &p_action) const {
return input_map.has(p_action);
}
float InputMap::action_get_deadzone(const StringName &p_action) {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action));
return input_map[p_action].deadzone;
}
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
input_map[p_action].deadzone = p_deadzone;
}
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
if (_find_event(input_map[p_action], p_event, true)) {
return; // Already added.
}
input_map[p_action].inputs.push_back(p_event);
}
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, suggest_actions(p_action));
return (_find_event(input_map[p_action], p_event, true) != nullptr);
}
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
if (E) {
input_map[p_action].inputs.erase(E);
if (Input::get_singleton()->is_action_pressed(p_action)) {
Input::get_singleton()->action_release(p_action);
}
}
}
void InputMap::action_erase_events(const StringName &p_action) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
input_map[p_action].inputs.clear();
}
TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) {
TypedArray<InputEvent> ret;
const List<Ref<InputEvent>> *al = action_get_events(p_action);
if (al) {
for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
ret.push_back(E->get());
}
}
return ret;
}
const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
if (!E) {
return nullptr;
}
return &E->value.inputs;
}
bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
return event_get_action_status(p_event, p_action, p_exact_match);
}
int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
int index = -1;
bool valid = event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
return valid ? index : -1;
}
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
Ref<InputEventAction> input_event_action = p_event;
if (input_event_action.is_valid()) {
const bool pressed = input_event_action->is_pressed();
if (r_pressed != nullptr) {
*r_pressed = pressed;
}
const float strength = pressed ? input_event_action->get_strength() : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
if (r_raw_strength != nullptr) {
*r_raw_strength = strength;
}
if (r_event_index) {
if (input_event_action->get_event_index() >= 0) {
*r_event_index = input_event_action->get_event_index();
} else {
*r_event_index = E->value.inputs.size();
}
}
return input_event_action->get_action() == p_action;
}
List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index);
return event != nullptr;
}
const HashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
return input_map;
}
void InputMap::load_from_project_settings() {
input_map.clear();
List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
for (const PropertyInfo &pi : pinfo) {
if (!pi.name.begins_with("input/")) {
continue;
}
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
Array events = action["events"];
add_action(name, deadzone);
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> event = events[i];
if (event.is_null()) {
continue;
}
action_add_event(name, event);
}
}
}
struct _BuiltinActionDisplayName {
const char *name;
const char *display_name;
};
static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
/* clang-format off */
{ "ui_accept", TTRC("Accept") },
{ "ui_select", TTRC("Select") },
{ "ui_cancel", TTRC("Cancel") },
{ "ui_focus_next", TTRC("Focus Next") },
{ "ui_focus_prev", TTRC("Focus Prev") },
{ "ui_left", TTRC("Left") },
{ "ui_right", TTRC("Right") },
{ "ui_up", TTRC("Up") },
{ "ui_down", TTRC("Down") },
{ "ui_page_up", TTRC("Page Up") },
{ "ui_page_down", TTRC("Page Down") },
{ "ui_home", TTRC("Home") },
{ "ui_end", TTRC("End") },
{ "ui_cut", TTRC("Cut") },
{ "ui_copy", TTRC("Copy") },
{ "ui_paste", TTRC("Paste") },
{ "ui_undo", TTRC("Undo") },
{ "ui_redo", TTRC("Redo") },
{ "ui_text_completion_query", TTRC("Completion Query") },
{ "ui_text_newline", TTRC("New Line") },
{ "ui_text_newline_blank", TTRC("New Blank Line") },
{ "ui_text_newline_above", TTRC("New Line Above") },
{ "ui_text_indent", TTRC("Indent") },
{ "ui_text_dedent", TTRC("Dedent") },
{ "ui_text_backspace", TTRC("Backspace") },
{ "ui_text_backspace_word", TTRC("Backspace Word") },
{ "ui_text_backspace_word.macos", TTRC("Backspace Word") },
{ "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
{ "ui_text_backspace_all_to_left.macos", TTRC("Backspace all to Left") },
{ "ui_text_delete", TTRC("Delete") },
{ "ui_text_delete_word", TTRC("Delete Word") },
{ "ui_text_delete_word.macos", TTRC("Delete Word") },
{ "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
{ "ui_text_delete_all_to_right.macos", TTRC("Delete all to Right") },
{ "ui_text_caret_left", TTRC("Caret Left") },
{ "ui_text_caret_word_left", TTRC("Caret Word Left") },
{ "ui_text_caret_word_left.macos", TTRC("Caret Word Left") },
{ "ui_text_caret_right", TTRC("Caret Right") },
{ "ui_text_caret_word_right", TTRC("Caret Word Right") },
{ "ui_text_caret_word_right.macos", TTRC("Caret Word Right") },
{ "ui_text_caret_up", TTRC("Caret Up") },
{ "ui_text_caret_down", TTRC("Caret Down") },
{ "ui_text_caret_line_start", TTRC("Caret Line Start") },
{ "ui_text_caret_line_start.macos", TTRC("Caret Line Start") },
{ "ui_text_caret_line_end", TTRC("Caret Line End") },
{ "ui_text_caret_line_end.macos", TTRC("Caret Line End") },
{ "ui_text_caret_page_up", TTRC("Caret Page Up") },
{ "ui_text_caret_page_down", TTRC("Caret Page Down") },
{ "ui_text_caret_document_start", TTRC("Caret Document Start") },
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
{ "ui_text_caret_add_below", TTRC("Caret Add Below") },
{ "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
{ "ui_text_caret_add_above", TTRC("Caret Add Above") },
{ "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
{ "ui_text_scroll_up", TTRC("Scroll Up") },
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
{ "ui_text_scroll_down", TTRC("Scroll Down") },
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
{ "ui_text_select_all", TTRC("Select All") },
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
{ "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
{ "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") },
{ "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
{ "ui_text_submit", TTRC("Submit Text") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
{ "ui_graph_delete", TTRC("Delete Nodes") },
{ "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") },
{ "", ""}
/* clang-format on */
};
String InputMap::get_builtin_display_name(const String &p_name) const {
int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName);
for (int i = 0; i < len; i++) {
if (_builtin_action_display_names[i].name == p_name) {
return RTR(_builtin_action_display_names[i].display_name);
}
}
return p_name;
}
const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
// Return cache if it has already been built.
if (default_builtin_cache.size()) {
return default_builtin_cache;
}
List<Ref<InputEvent>> inputs;
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
inputs.push_back(InputEventKey::create_reference(Key::SPACE));
default_builtin_cache.insert("ui_accept", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::Y));
inputs.push_back(InputEventKey::create_reference(Key::SPACE));
default_builtin_cache.insert("ui_select", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
default_builtin_cache.insert("ui_cancel", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB));
default_builtin_cache.insert("ui_focus_next", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_focus_prev", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_LEFT));
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, -1.0));
default_builtin_cache.insert("ui_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_RIGHT));
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, 1.0));
default_builtin_cache.insert("ui_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_UP));
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, -1.0));
default_builtin_cache.insert("ui_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_DOWN));
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, 1.0));
default_builtin_cache.insert("ui_down", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
default_builtin_cache.insert("ui_page_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
default_builtin_cache.insert("ui_page_down", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::HOME));
default_builtin_cache.insert("ui_home", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::END));
default_builtin_cache.insert("ui_end", inputs);
// ///// UI basic Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::X | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_cut", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::C | KeyModifierMask::CMD_OR_CTRL));
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::V | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_paste", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_undo", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT));
inputs.push_back(InputEventKey::create_reference(Key::Y | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_redo", inputs);
// ///// UI Text Input Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::SPACE | KeyModifierMask::CTRL));
default_builtin_cache.insert("ui_text_completion_query", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::TAB));
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::ENTER));
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::KP_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB));
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_completion_replace", inputs);
// Newlines
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_newline", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_newline_blank", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_newline_above", inputs);
// Indentation
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB));
default_builtin_cache.insert("ui_text_indent", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_text_dedent", inputs);
// Text Backspace and Delete
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_text_backspace", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_backspace_word", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_backspace_word.macos", inputs);
inputs = List<Ref<InputEvent>>();
default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_backspace_all_to_left.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
default_builtin_cache.insert("ui_text_delete", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_delete_word", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_delete_word.macos", inputs);
inputs = List<Ref<InputEvent>>();
default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_delete_all_to_right.macos", inputs);
// Text Caret Movement Left/Right
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT));
default_builtin_cache.insert("ui_text_caret_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_word_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_caret_word_left.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
default_builtin_cache.insert("ui_text_caret_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_word_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_caret_word_right.macos", inputs);
// Text Caret Movement Up/Down
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP));
default_builtin_cache.insert("ui_text_caret_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN));
default_builtin_cache.insert("ui_text_caret_down", inputs);
// Text Caret Movement Line Start/End
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::HOME));
default_builtin_cache.insert("ui_text_caret_line_start", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CTRL));
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::HOME));
default_builtin_cache.insert("ui_text_caret_line_start.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::END));
default_builtin_cache.insert("ui_text_caret_line_end", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::E | KeyModifierMask::CTRL));
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::END));
default_builtin_cache.insert("ui_text_caret_line_end.macos", inputs);
// Text Caret Movement Page Up/Down
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
default_builtin_cache.insert("ui_text_caret_page_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
default_builtin_cache.insert("ui_text_caret_page_down", inputs);
// Text Caret Movement Document Start/End
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_start", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_start.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
// Text Caret Addition Below/Above
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_add_below", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_add_above", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
// Text Scrolling
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_scroll_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_scroll_up.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_scroll_down", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_scroll_down.macos", inputs);
// Text Misc
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::CTRL | KeyModifierMask::META));
default_builtin_cache.insert("ui_text_select_word_under_caret.macos", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_skip_selection_for_next_occurrence", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::INSERT));
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::MENU));
default_builtin_cache.insert("ui_menu", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_submit", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::U | KeyModifierMask::CTRL | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_unicode_start", inputs);
// ///// UI Graph Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_graph_duplicate", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
default_builtin_cache.insert("ui_graph_delete", inputs);
// ///// UI File Dialog Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::F5));
default_builtin_cache.insert("ui_filedialog_refresh", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::H));
default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_swap_input_direction", inputs);
return default_builtin_cache;
}
const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_feature_overrides_applied() {
if (default_builtin_with_overrides_cache.size() > 0) {
return default_builtin_with_overrides_cache;
}
const HashMap<String, List<Ref<InputEvent>>> &builtins = get_builtins();
// Get a list of all built in inputs which are valid overrides for the OS
// Key = builtin name (e.g. ui_accept)
// Value = override/feature names (e.g. macos, if it was defined as "ui_accept.macos" and the platform supports that feature)
HashMap<String, Vector<String>> builtins_with_overrides;
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
String fullname = E.key;
Vector<String> split = fullname.split(".");
const String &name = split[0];
String override_for = split.size() > 1 ? split[1] : String();
if (!override_for.is_empty() && OS::get_singleton()->has_feature(override_for)) {
builtins_with_overrides[name].push_back(override_for);
}
}
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
String fullname = E.key;
Vector<String> split = fullname.split(".");
const String &name = split[0];
String override_for = split.size() > 1 ? split[1] : String();
if (builtins_with_overrides.has(name) && override_for.is_empty()) {
// Builtin has an override but this particular one is not an override, so skip.
continue;
}
if (!override_for.is_empty() && !OS::get_singleton()->has_feature(override_for)) {
// OS does not support this override - skip.
continue;
}
default_builtin_with_overrides_cache.insert(name, E.value);
}
return default_builtin_with_overrides_cache;
}
void InputMap::load_default() {
HashMap<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
String name = E.key;
add_action(name);
const List<Ref<InputEvent>> &inputs = E.value;
for (const List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
Ref<InputEventKey> iek = I->get();
// For the editor, only add keyboard actions.
if (iek.is_valid()) {
action_add_event(name, I->get());
}
}
}
}
InputMap::InputMap() {
ERR_FAIL_COND_MSG(singleton, "Singleton in InputMap already exist.");
singleton = this;
}
InputMap::~InputMap() {
singleton = nullptr;
}

View file

@ -1,120 +0,0 @@
/**************************************************************************/
/* input_map.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INPUT_MAP_H
#define INPUT_MAP_H
#include "core/input/input_event.h"
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/templates/hash_map.h"
template <typename T>
class TypedArray;
class InputMap : public Object {
GDCLASS(InputMap, Object);
public:
/**
* A special value used to signify that a given Action can be triggered by any device
*/
static int ALL_DEVICES;
struct Action {
int id;
float deadzone;
List<Ref<InputEvent>> inputs;
};
static constexpr float DEFAULT_DEADZONE = 0.2f;
// Keep bigger deadzone for toggle actions (default `ui_*` actions, axis `pressed`) (GH-103360).
static constexpr float DEFAULT_TOGGLE_DEADZONE = 0.5f;
private:
static InputMap *singleton;
mutable HashMap<StringName, Action> input_map;
HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
TypedArray<InputEvent> _action_get_events(const StringName &p_action);
TypedArray<StringName> _get_actions();
protected:
static void _bind_methods();
#ifndef DISABLE_DEPRECATED
void _add_action_bind_compat_97281(const StringName &p_action, float p_deadzone = 0.5);
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED
public:
static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
bool has_action(const StringName &p_action) const;
List<StringName> get_actions() const;
void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE);
void erase_action(const StringName &p_action);
float action_get_deadzone(const StringName &p_action);
void action_set_deadzone(const StringName &p_action, float p_deadzone);
void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
void action_erase_events(const StringName &p_action);
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
const HashMap<StringName, Action> &get_action_map() const;
void load_from_project_settings();
void load_default();
String suggest_actions(const StringName &p_action) const;
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
String get_builtin_display_name(const String &p_name) const;
// Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat.
const HashMap<String, List<Ref<InputEvent>>> &get_builtins();
const HashMap<String, List<Ref<InputEvent>>> &get_builtins_with_feature_overrides_applied();
InputMap();
~InputMap();
};
#endif // INPUT_MAP_H

View file

@ -1,131 +0,0 @@
/**************************************************************************/
/* shortcut.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "shortcut.h"
void Shortcut::set_events(const Array &p_events) {
for (int i = 0; i < p_events.size(); i++) {
Ref<InputEventShortcut> ies = p_events[i];
ERR_FAIL_COND_MSG(ies.is_valid(), "Cannot set a shortcut event to an instance of InputEventShortcut.");
}
events = p_events;
emit_changed();
}
void Shortcut::set_events_list(const List<Ref<InputEvent>> *p_events) {
events.clear();
for (const Ref<InputEvent> &ie : *p_events) {
events.push_back(ie);
}
}
Array Shortcut::get_events() const {
return events;
}
bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
Ref<InputEventShortcut> ies = p_event;
if (ies.is_valid()) {
if (ies->get_shortcut().ptr() == this) {
return true;
}
}
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
bool valid = ie.is_valid() && ie->is_match(p_event);
// Stop on first valid event - don't need to check further.
if (valid) {
return true;
}
}
return false;
}
String Shortcut::get_as_text() const {
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
// Return first shortcut which is valid
if (ie.is_valid()) {
return ie->as_text();
}
}
return "None";
}
bool Shortcut::has_valid_event() const {
// Tests if there is ANY input event which is valid.
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
if (ie.is_valid()) {
return true;
}
}
return false;
}
void Shortcut::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_events", "events"), &Shortcut::set_events);
ClassDB::bind_method(D_METHOD("get_events"), &Shortcut::get_events);
ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event);
ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("InputEvent")), "set_events", "get_events");
}
bool Shortcut::is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2) {
if (p_event_array1.size() != p_event_array2.size()) {
return false;
}
bool is_same = true;
for (int i = 0; i < p_event_array1.size(); i++) {
Ref<InputEvent> ie_1 = p_event_array1[i];
Ref<InputEvent> ie_2 = p_event_array2[i];
is_same = ie_1->is_match(ie_2);
// Break on the first that doesn't match - don't need to check further.
if (!is_same) {
break;
}
}
return is_same;
}

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