forked from hertog/godot-module-template
Compare commits
10 commits
developmen
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d7050a065 | ||
![]() |
49689745db | ||
![]() |
0e78ce5031 | ||
![]() |
31c715db98 | ||
![]() |
202693b275 | ||
![]() |
58690660c4 | ||
|
f0fc98b2b8 | ||
![]() |
c420f4b4a8 | ||
![]() |
c33d2130cc | ||
|
dfb5e645cd |
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -7,3 +7,8 @@ config.log
|
||||||
.sconf_temp
|
.sconf_temp
|
||||||
|
|
||||||
engine/.github
|
engine/.github
|
||||||
|
project/.godot
|
||||||
|
build/PROJECT.pck
|
||||||
|
build/PROJECT.x86_64
|
||||||
|
build/PROJECT.exe
|
||||||
|
build.zip
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "engine"]
|
||||||
|
path = engine
|
||||||
|
url = https://github.com/godotengine/godot.git
|
1
engine
Submodule
1
engine
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 215acd52e82f4c575abb715e25e54558deeef998
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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: "*"
|
|
|
@ -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
|
|
|
@ -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
23
engine/.gitattributes
vendored
|
@ -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
383
engine/.gitignore
vendored
|
@ -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
|
|
195
engine/.mailmap
195
engine/.mailmap
|
@ -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>
|
|
|
@ -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
|
|
|
@ -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)
|
|
2953
engine/CHANGELOG.md
2953
engine/CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
2209
engine/COPYRIGHT.txt
2209
engine/COPYRIGHT.txt
File diff suppressed because it is too large
Load diff
293
engine/DONORS.md
293
engine/DONORS.md
|
@ -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!
|
|
|
@ -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.
|
|
|
@ -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/
|
|
|
@ -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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
[](https://www.codetriage.com/godotengine/godot)
|
|
||||||
[](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
|
|
||||||
[](https://www.tickgit.com/browse?repo=github.com/godotengine/godot)
|
|
1092
engine/SConstruct
1092
engine/SConstruct
File diff suppressed because it is too large
Load diff
|
@ -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)
|
|
|
@ -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")
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
@ -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
|
|
|
@ -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
|
@ -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
|
|
|
@ -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])
|
|
||||||
+ '", '
|
|
||||||
+ "©RIGHT_INFO_DATA["
|
|
||||||
+ str(part["file_index"])
|
|
||||||
+ "], "
|
|
||||||
+ "©RIGHT_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)
|
|
||||||
+ '", '
|
|
||||||
+ "©RIGHT_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")
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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() {
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
from misc.utility.scons_hints import *
|
|
||||||
|
|
||||||
Import("env")
|
|
||||||
|
|
||||||
env.add_source_files(env.core_sources, "*.cpp")
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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")
|
|
|
@ -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);
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
@ -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
|
|
|
@ -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
|
@ -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
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
@ -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
|
|
|
@ -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
|
|
||||||
"""
|
|
||||||
)
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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
|
@ -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
|
|
|
@ -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
|
@ -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
|
|
|
@ -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")
|
|
|
@ -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
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
Loading…
Reference in a new issue