feat: erased accidentally added engine files
This commit is contained in:
		
							parent
							
								
									f0fc98b2b8
								
							
						
					
					
						commit
						202693b275
					
				| 
						 | 
					@ -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,30 +0,0 @@
 | 
				
			||||||
# https://clangd.llvm.org/config
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
# Default conditions, apply everywhere.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Diagnostics:
 | 
					 | 
				
			||||||
  Includes:
 | 
					 | 
				
			||||||
    IgnoreHeader:
 | 
					 | 
				
			||||||
      - \.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,21 +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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[{*.props,*.vcxproj}]
 | 
					 | 
				
			||||||
indent_size = 2
 | 
					 | 
				
			||||||
indent_style = space
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,74 +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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Style: Enforce trailing newlines on svgs
 | 
					 | 
				
			||||||
7e5baa042639ffa835271703c720e2595e90afb8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Style: Replace header guards with `#pragma once`
 | 
					 | 
				
			||||||
324512e11c1b7663c3cf47bec6ddbe65c6b8db2b
 | 
					 | 
				
			||||||
							
								
								
									
										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
 | 
					 | 
				
			||||||
							
								
								
									
										388
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										388
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,388 +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/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
thirdparty/swappy-frame-pacing/arm64-v8a/abi.json
 | 
					 | 
				
			||||||
thirdparty/swappy-frame-pacing/armeabi-v7a/abi.json
 | 
					 | 
				
			||||||
thirdparty/swappy-frame-pacing/x86/abi.json
 | 
					 | 
				
			||||||
thirdparty/swappy-frame-pacing/x86_64/abi.json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Visual Studio 2015/2017 cache/options directory
 | 
					 | 
				
			||||||
.vs/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# 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,195 +0,0 @@
 | 
				
			||||||
default_language_version:
 | 
					 | 
				
			||||||
  python: python3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exclude: |
 | 
					 | 
				
			||||||
  (?x)^(
 | 
					 | 
				
			||||||
    .*thirdparty/.*|
 | 
					 | 
				
			||||||
    .*-(dll|dylib|so)_wrap\.[ch]|
 | 
					 | 
				
			||||||
    platform/android/java/editor/src/main/java/com/android/.*|
 | 
					 | 
				
			||||||
    platform/android/java/lib/src/com/google/.*
 | 
					 | 
				
			||||||
  )$
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
repos:
 | 
					 | 
				
			||||||
  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
					 | 
				
			||||||
    rev: v20.1.0
 | 
					 | 
				
			||||||
    hooks:
 | 
					 | 
				
			||||||
      - id: clang-format
 | 
					 | 
				
			||||||
        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
 | 
					 | 
				
			||||||
        types_or: [text]
 | 
					 | 
				
			||||||
      - id: clang-format
 | 
					 | 
				
			||||||
        name: clang-format-glsl
 | 
					 | 
				
			||||||
        files: \.glsl$
 | 
					 | 
				
			||||||
        types_or: [text]
 | 
					 | 
				
			||||||
        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]
 | 
					 | 
				
			||||||
        additional_dependencies: [clang-tidy==20.1.0]
 | 
					 | 
				
			||||||
        require_serial: true
 | 
					 | 
				
			||||||
        stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
					 | 
				
			||||||
    rev: v0.11.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 # Latest version that supports Python 3.8
 | 
					 | 
				
			||||||
    hooks:
 | 
					 | 
				
			||||||
      - id: mypy
 | 
					 | 
				
			||||||
        files: \.py$
 | 
					 | 
				
			||||||
        types_or: [text]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  - repo: https://github.com/codespell-project/codespell
 | 
					 | 
				
			||||||
    rev: v2.4.1
 | 
					 | 
				
			||||||
    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: validate-builders
 | 
					 | 
				
			||||||
        name: validate-builders
 | 
					 | 
				
			||||||
        language: python
 | 
					 | 
				
			||||||
        entry: python tests/python_build/validate_builders.py
 | 
					 | 
				
			||||||
        pass_filenames: false
 | 
					 | 
				
			||||||
        files: ^(gles3|glsl)_builders\.py$
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - id: eslint
 | 
					 | 
				
			||||||
        name: eslint
 | 
					 | 
				
			||||||
        language: node
 | 
					 | 
				
			||||||
        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)$
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - 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
 | 
					 | 
				
			||||||
							
								
								
									
										2214
									
								
								engine/COPYRIGHT.txt
									
									
									
									
									
								
							
							
						
						
									
										2214
									
								
								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)
 | 
					 | 
				
			||||||
							
								
								
									
										1163
									
								
								engine/SConstruct
									
									
									
									
									
								
							
							
						
						
									
										1163
									
								
								engine/SConstruct
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,293 +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(CPPEXTPATH=[thirdparty_brotli_dir + "include"])
 | 
					 | 
				
			||||||
    env.Prepend(CPPEXTPATH=[thirdparty_brotli_dir + "include"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
 | 
					 | 
				
			||||||
        env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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(CPPEXTPATH=[thirdparty_clipper_dir + "include"])
 | 
					 | 
				
			||||||
    env.Prepend(CPPEXTPATH=[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(CPPEXTPATH=[thirdparty_zlib_dir])
 | 
					 | 
				
			||||||
    # Needs to be available in main env too
 | 
					 | 
				
			||||||
    env.Prepend(CPPEXTPATH=[thirdparty_zlib_dir])
 | 
					 | 
				
			||||||
    if env.dev_build:
 | 
					 | 
				
			||||||
        env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
 | 
					 | 
				
			||||||
        # Affects headers so it should also be defined for Godot code
 | 
					 | 
				
			||||||
        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(CPPEXTPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
 | 
					 | 
				
			||||||
    env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
 | 
					 | 
				
			||||||
    env.Prepend(CPPEXTPATH=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(str(target[0])) as file:
 | 
					 | 
				
			||||||
        for c in source[0].read():
 | 
					 | 
				
			||||||
            if cs := c.strip():
 | 
					 | 
				
			||||||
                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(str(target[0])) as file:
 | 
					 | 
				
			||||||
        file.write(
 | 
					 | 
				
			||||||
            """\
 | 
					 | 
				
			||||||
#define GODOT_VERSION_SHORT_NAME "{short_name}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_NAME "{name}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_MAJOR {major}
 | 
					 | 
				
			||||||
#define GODOT_VERSION_MINOR {minor}
 | 
					 | 
				
			||||||
#define GODOT_VERSION_PATCH {patch}
 | 
					 | 
				
			||||||
#define GODOT_VERSION_STATUS "{status}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_BUILD "{build}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_MODULE_CONFIG "{module_config}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_WEBSITE "{website}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_DOCS_BRANCH "{docs_branch}"
 | 
					 | 
				
			||||||
#define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH
 | 
					 | 
				
			||||||
""".format(**source[0].read())
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
env.CommandNoCache(
 | 
					 | 
				
			||||||
    "version_generated.gen.h",
 | 
					 | 
				
			||||||
    env.Value(methods.get_version_info(env.module_version_string)),
 | 
					 | 
				
			||||||
    env.Run(version_info_builder),
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generate version hash
 | 
					 | 
				
			||||||
def version_hash_builder(target, source, env):
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
        file.write(
 | 
					 | 
				
			||||||
            """\
 | 
					 | 
				
			||||||
#include "core/version.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *const GODOT_VERSION_HASH = "{git_hash}";
 | 
					 | 
				
			||||||
const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
 | 
					 | 
				
			||||||
""".format(**source[0].read())
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder))
 | 
					 | 
				
			||||||
env.add_source_files(env.core_sources, gen_hash)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generate AES256 script encryption key
 | 
					 | 
				
			||||||
def encryption_key_builder(target, source, env):
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) 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.CommandNoCache(
 | 
					 | 
				
			||||||
    "#core/io/certs_compressed.gen.h",
 | 
					 | 
				
			||||||
    ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
 | 
					 | 
				
			||||||
    env.Run(core_builders.make_certs_header),
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Authors
 | 
					 | 
				
			||||||
env.CommandNoCache("#core/authors.gen.h", "#AUTHORS.md", env.Run(core_builders.make_authors_header))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Donors
 | 
					 | 
				
			||||||
env.CommandNoCache("#core/donors.gen.h", "#DONORS.md", env.Run(core_builders.make_donors_header))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# License
 | 
					 | 
				
			||||||
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"] = GODOT_VERSION_MAJOR;
 | 
					 | 
				
			||||||
	dict["minor"] = GODOT_VERSION_MINOR;
 | 
					 | 
				
			||||||
	dict["patch"] = GODOT_VERSION_PATCH;
 | 
					 | 
				
			||||||
	dict["hex"] = GODOT_VERSION_HEX;
 | 
					 | 
				
			||||||
	dict["status"] = GODOT_VERSION_STATUS;
 | 
					 | 
				
			||||||
	dict["build"] = GODOT_VERSION_BUILD;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String hash = String(GODOT_VERSION_HASH);
 | 
					 | 
				
			||||||
	dict["hash"] = hash.is_empty() ? String("unknown") : hash;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dict["timestamp"] = GODOT_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,215 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,245 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
	Variant get_setting_with_override_and_custom_features(const StringName &p_name, const Vector<String> &p_features) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool is_using_datapack() const;
 | 
					 | 
				
			||||||
	bool is_project_loaded() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,64 +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 CoreBind {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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", "buffer_size"), &OS::read_string_from_stdin);
 | 
					 | 
				
			||||||
	ClassDB::bind_compatibility_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
 | 
					 | 
				
			||||||
	ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
 | 
					 | 
				
			||||||
	ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace CoreBind
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,671 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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 CoreBind {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 CoreBind
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::ResourceLoader::ThreadLoadStatus);
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::ResourceLoader::CacheMode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_BITFIELD_CAST(CoreBind::ResourceSaver::SaverFlags);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::OS::RenderingDriver);
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::OS::SystemDir);
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::OS::StdHandleType);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyBooleanOperation);
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyJoinType);
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyEndType);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::Thread::Priority);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIANT_ENUM_CAST(CoreBind::Special::ClassDB::APIType);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,226 +0,0 @@
 | 
				
			||||||
"""Functions used to generate source files during build time"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from collections import OrderedDict
 | 
					 | 
				
			||||||
from io import TextIOWrapper
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import methods
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def make_certs_header(target, source, env):
 | 
					 | 
				
			||||||
    buffer = methods.get_buffer(str(source[0]))
 | 
					 | 
				
			||||||
    decomp_size = len(buffer)
 | 
					 | 
				
			||||||
    buffer = methods.compress_buffer(buffer)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
        # System certs path. Editor will use them if defined. (for package maintainers)
 | 
					 | 
				
			||||||
        file.write('#define _SYSTEM_CERTS_PATH "{}"\n'.format(env["system_certs_path"]))
 | 
					 | 
				
			||||||
        if env["builtin_certs"]:
 | 
					 | 
				
			||||||
            # Defined here and not in env so changing it does not trigger a full rebuild.
 | 
					 | 
				
			||||||
            file.write(f"""\
 | 
					 | 
				
			||||||
#define BUILTIN_CERTS_ENABLED
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline constexpr int _certs_compressed_size = {len(buffer)};
 | 
					 | 
				
			||||||
inline constexpr int _certs_uncompressed_size = {decomp_size};
 | 
					 | 
				
			||||||
inline constexpr unsigned char _certs_compressed[] = {{
 | 
					 | 
				
			||||||
	{methods.format_buffer(buffer, 1)}
 | 
					 | 
				
			||||||
}};
 | 
					 | 
				
			||||||
""")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def make_authors_header(target, source, env):
 | 
					 | 
				
			||||||
    SECTIONS = {
 | 
					 | 
				
			||||||
        "Project Founders": "AUTHORS_FOUNDERS",
 | 
					 | 
				
			||||||
        "Lead Developer": "AUTHORS_LEAD_DEVELOPERS",
 | 
					 | 
				
			||||||
        "Project Manager": "AUTHORS_PROJECT_MANAGERS",
 | 
					 | 
				
			||||||
        "Developers": "AUTHORS_DEVELOPERS",
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    buffer = methods.get_buffer(str(source[0]))
 | 
					 | 
				
			||||||
    reading = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def close_section():
 | 
					 | 
				
			||||||
            file.write("\tnullptr,\n};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for line in buffer.decode().splitlines():
 | 
					 | 
				
			||||||
            if line.startswith("    ") and reading:
 | 
					 | 
				
			||||||
                file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
 | 
					 | 
				
			||||||
            elif line.startswith("## "):
 | 
					 | 
				
			||||||
                if reading:
 | 
					 | 
				
			||||||
                    close_section()
 | 
					 | 
				
			||||||
                    reading = False
 | 
					 | 
				
			||||||
                section = SECTIONS[line[3:].strip()]
 | 
					 | 
				
			||||||
                if section:
 | 
					 | 
				
			||||||
                    file.write(f"inline constexpr const char *{section}[] = {{\n")
 | 
					 | 
				
			||||||
                    reading = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if reading:
 | 
					 | 
				
			||||||
            close_section()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def make_donors_header(target, source, env):
 | 
					 | 
				
			||||||
    SECTIONS = {
 | 
					 | 
				
			||||||
        "Patrons": "DONORS_PATRONS",
 | 
					 | 
				
			||||||
        "Platinum sponsors": "DONORS_SPONSORS_PLATINUM",
 | 
					 | 
				
			||||||
        "Gold sponsors": "DONORS_SPONSORS_GOLD",
 | 
					 | 
				
			||||||
        "Silver sponsors": "DONORS_SPONSORS_SILVER",
 | 
					 | 
				
			||||||
        "Diamond members": "DONORS_MEMBERS_DIAMOND",
 | 
					 | 
				
			||||||
        "Titanium members": "DONORS_MEMBERS_TITANIUM",
 | 
					 | 
				
			||||||
        "Platinum members": "DONORS_MEMBERS_PLATINUM",
 | 
					 | 
				
			||||||
        "Gold members": "DONORS_MEMBERS_GOLD",
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    buffer = methods.get_buffer(str(source[0]))
 | 
					 | 
				
			||||||
    reading = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def close_section():
 | 
					 | 
				
			||||||
            file.write("\tnullptr,\n};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for line in buffer.decode().splitlines():
 | 
					 | 
				
			||||||
            if line.startswith("    ") and reading:
 | 
					 | 
				
			||||||
                file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
 | 
					 | 
				
			||||||
            elif line.startswith("## "):
 | 
					 | 
				
			||||||
                if reading:
 | 
					 | 
				
			||||||
                    close_section()
 | 
					 | 
				
			||||||
                    reading = False
 | 
					 | 
				
			||||||
                section = SECTIONS.get(line[3:].strip())
 | 
					 | 
				
			||||||
                if section:
 | 
					 | 
				
			||||||
                    file.write(f"inline constexpr const char *{section}[] = {{\n")
 | 
					 | 
				
			||||||
                    reading = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if reading:
 | 
					 | 
				
			||||||
            close_section()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def make_license_header(target, source, env):
 | 
					 | 
				
			||||||
    src_copyright = str(source[0])
 | 
					 | 
				
			||||||
    src_license = str(source[1])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class LicenseReader:
 | 
					 | 
				
			||||||
        def __init__(self, license_file: TextIOWrapper):
 | 
					 | 
				
			||||||
            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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    projects = 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 = []
 | 
					 | 
				
			||||||
    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(src_license, "r", encoding="utf-8") as file:
 | 
					 | 
				
			||||||
        license_text = file.read()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
        file.write(f"""\
 | 
					 | 
				
			||||||
inline constexpr const char *GODOT_LICENSE_TEXT = {{
 | 
					 | 
				
			||||||
{methods.to_raw_cstring(license_text)}
 | 
					 | 
				
			||||||
}};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ComponentCopyrightPart {{
 | 
					 | 
				
			||||||
	const char *license;
 | 
					 | 
				
			||||||
	const char *const *files;
 | 
					 | 
				
			||||||
	const char *const *copyright_statements;
 | 
					 | 
				
			||||||
	int file_count;
 | 
					 | 
				
			||||||
	int copyright_count;
 | 
					 | 
				
			||||||
}};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ComponentCopyright {{
 | 
					 | 
				
			||||||
	const char *name;
 | 
					 | 
				
			||||||
	const ComponentCopyrightPart *parts;
 | 
					 | 
				
			||||||
	int part_count;
 | 
					 | 
				
			||||||
}};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
""")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("inline constexpr const char *COPYRIGHT_INFO_DATA[] = {\n")
 | 
					 | 
				
			||||||
        for line in data_list:
 | 
					 | 
				
			||||||
            file.write(f'\t"{methods.to_escaped_cstring(line)}",\n')
 | 
					 | 
				
			||||||
        file.write("};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("inline constexpr ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
 | 
					 | 
				
			||||||
        part_index = 0
 | 
					 | 
				
			||||||
        part_indexes = {}
 | 
					 | 
				
			||||||
        for project_name, project in iter(projects.items()):
 | 
					 | 
				
			||||||
            part_indexes[project_name] = part_index
 | 
					 | 
				
			||||||
            for part in project:
 | 
					 | 
				
			||||||
                file.write(
 | 
					 | 
				
			||||||
                    f'\t{{ "{methods.to_escaped_cstring(part["License"][0])}", '
 | 
					 | 
				
			||||||
                    + f"©RIGHT_INFO_DATA[{part['file_index']}], "
 | 
					 | 
				
			||||||
                    + f"©RIGHT_INFO_DATA[{part['copyright_index']}], "
 | 
					 | 
				
			||||||
                    + f"{len(part['Files'])}, {len(part['Copyright'])} }},\n"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                part_index += 1
 | 
					 | 
				
			||||||
        file.write("};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write(f"inline constexpr int COPYRIGHT_INFO_COUNT = {len(projects)};\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("inline constexpr ComponentCopyright COPYRIGHT_INFO[] = {\n")
 | 
					 | 
				
			||||||
        for project_name, project in iter(projects.items()):
 | 
					 | 
				
			||||||
            file.write(
 | 
					 | 
				
			||||||
                f'\t{{ "{methods.to_escaped_cstring(project_name)}", '
 | 
					 | 
				
			||||||
                + f"©RIGHT_PROJECT_PARTS[{part_indexes[project_name]}], "
 | 
					 | 
				
			||||||
                + f"{len(project)} }},\n"
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        file.write("};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write(f"inline constexpr int LICENSE_COUNT = {len(license_list)};\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("inline constexpr const char *LICENSE_NAMES[] = {\n")
 | 
					 | 
				
			||||||
        for license in license_list:
 | 
					 | 
				
			||||||
            file.write(f'\t"{methods.to_escaped_cstring(license[0])}",\n')
 | 
					 | 
				
			||||||
        file.write("};\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("inline constexpr const char *LICENSE_BODIES[] = {\n\n")
 | 
					 | 
				
			||||||
        for license in license_list:
 | 
					 | 
				
			||||||
            to_raw = []
 | 
					 | 
				
			||||||
            for line in license[1:]:
 | 
					 | 
				
			||||||
                if line == ".":
 | 
					 | 
				
			||||||
                    to_raw += [""]
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    to_raw += [line]
 | 
					 | 
				
			||||||
            file.write(f"{methods.to_raw_cstring(to_raw)},\n\n")
 | 
					 | 
				
			||||||
        file.write("};\n\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,48 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,41 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,88 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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(CPPEXTPATH=["#thirdparty/mbedtls/include"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# MbedTLS core functions (for CryptoCore).
 | 
					 | 
				
			||||||
# If the mbedtls module is compiled we don't need to add the .c files with our
 | 
					 | 
				
			||||||
# 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,65 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,168 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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, size_t p_src_len) {
 | 
					 | 
				
			||||||
	size_t b64len = p_src_len / 3 * 4 + 4 + 1;
 | 
					 | 
				
			||||||
	Vector<uint8_t> b64buff;
 | 
					 | 
				
			||||||
	b64buff.resize(b64len);
 | 
					 | 
				
			||||||
	uint8_t *w64 = b64buff.ptrw();
 | 
					 | 
				
			||||||
	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, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len) {
 | 
					 | 
				
			||||||
	int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len);
 | 
					 | 
				
			||||||
	return ret ? FAILED : OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error CryptoCore::b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len) {
 | 
					 | 
				
			||||||
	int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len);
 | 
					 | 
				
			||||||
	return ret ? FAILED : OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error CryptoCore::md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]) {
 | 
					 | 
				
			||||||
	int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash);
 | 
					 | 
				
			||||||
	return ret ? FAILED : OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error CryptoCore::sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]) {
 | 
					 | 
				
			||||||
	int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash);
 | 
					 | 
				
			||||||
	return ret ? FAILED : OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error CryptoCore::sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]) {
 | 
					 | 
				
			||||||
	int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
 | 
					 | 
				
			||||||
	return ret ? FAILED : OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,116 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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, size_t p_src_len);
 | 
					 | 
				
			||||||
	static Error b64_encode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
 | 
					 | 
				
			||||||
	static Error b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static Error md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]);
 | 
					 | 
				
			||||||
	static Error sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]);
 | 
					 | 
				
			||||||
	static Error sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,63 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,179 +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 = { 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 = { name, type, 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() {
 | 
					 | 
				
			||||||
	unsigned int size = callstack.size();
 | 
					 | 
				
			||||||
	Array arr = {
 | 
					 | 
				
			||||||
		hr,
 | 
					 | 
				
			||||||
		min,
 | 
					 | 
				
			||||||
		sec, msec,
 | 
					 | 
				
			||||||
		source_file,
 | 
					 | 
				
			||||||
		source_func,
 | 
					 | 
				
			||||||
		source_line,
 | 
					 | 
				
			||||||
		error,
 | 
					 | 
				
			||||||
		error_descr,
 | 
					 | 
				
			||||||
		warning,
 | 
					 | 
				
			||||||
		size * 3
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	const ScriptLanguage::StackInfo *r = callstack.ptr();
 | 
					 | 
				
			||||||
	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,74 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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, bool p_ignore_error_breaks, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) {
 | 
					 | 
				
			||||||
	register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
 | 
					 | 
				
			||||||
	if (p_uri.is_empty()) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	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 = { 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);
 | 
					 | 
				
			||||||
	singleton_script_debugger->set_ignore_error_breaks(p_ignore_error_breaks);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < p_breakpoints.size(); i++) {
 | 
					 | 
				
			||||||
		const String &bp = p_breakpoints[i];
 | 
					 | 
				
			||||||
		int sp = bp.rfind_char(':');
 | 
					 | 
				
			||||||
		ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1).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,141 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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, bool p_ignore_error_breaks, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
 | 
					 | 
				
			||||||
	static void deinitialize();
 | 
					 | 
				
			||||||
	static void register_profiler(const StringName &p_name, const Profiler &p_profiler);
 | 
					 | 
				
			||||||
	static void unregister_profiler(const StringName &p_name);
 | 
					 | 
				
			||||||
	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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,60 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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.is_empty()) {
 | 
					 | 
				
			||||||
					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,56 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,744 +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 = { p_message, Thread::get_caller_id(), 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 = { strings, 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();
 | 
					 | 
				
			||||||
	ERR_FAIL_NULL(script_lang);
 | 
					 | 
				
			||||||
	const bool can_break = !(p_is_error_breakpoint && script_debugger->is_ignoring_error_breaks());
 | 
					 | 
				
			||||||
	const String error_str = script_lang ? script_lang->debug_get_error() : "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (can_break) {
 | 
					 | 
				
			||||||
		Array msg = {
 | 
					 | 
				
			||||||
			p_can_continue,
 | 
					 | 
				
			||||||
			error_str,
 | 
					 | 
				
			||||||
			script_lang->debug_get_stack_level_count() > 0,
 | 
					 | 
				
			||||||
			Thread::get_caller_id()
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		if (allow_focus_steal_fn) {
 | 
					 | 
				
			||||||
			allow_focus_steal_fn();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		send_message("debug_enter", msg);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ERR_PRINT(error_str);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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 = { 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 == "set_ignore_error_breaks") {
 | 
					 | 
				
			||||||
				ERR_FAIL_COND(data.is_empty());
 | 
					 | 
				
			||||||
				script_debugger->set_ignore_error_breaks(data[0]);
 | 
					 | 
				
			||||||
			} else if (command == "evaluate") {
 | 
					 | 
				
			||||||
				String expression_str = data[0];
 | 
					 | 
				
			||||||
				int frame = data[1];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				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 == "set_ignore_error_breaks") {
 | 
					 | 
				
			||||||
		ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
 | 
					 | 
				
			||||||
		script_debugger->set_ignore_error_breaks(p_data[0]);
 | 
					 | 
				
			||||||
	} else if (p_cmd == "break") {
 | 
					 | 
				
			||||||
		script_debugger->debug(script_debugger->get_break_language());
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		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,123 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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.is_empty()) {
 | 
					 | 
				
			||||||
				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,93 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,110 +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].is_empty()) {
 | 
					 | 
				
			||||||
		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::set_ignore_error_breaks(bool p_ignore) {
 | 
					 | 
				
			||||||
	ignore_error_breaks = p_ignore;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool ScriptDebugger::is_ignoring_error_breaks() {
 | 
					 | 
				
			||||||
	return ignore_error_breaks;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
 | 
					 | 
				
			||||||
	ScriptLanguage *prev = break_lang;
 | 
					 | 
				
			||||||
	break_lang = p_lang;
 | 
					 | 
				
			||||||
	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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
	bool ignore_error_breaks = 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 set_ignore_error_breaks(bool p_ignore);
 | 
					 | 
				
			||||||
	bool is_ignoring_error_breaks();
 | 
					 | 
				
			||||||
	void insert_breakpoint(int p_line, const StringName &p_source);
 | 
					 | 
				
			||||||
	void remove_breakpoint(int p_line, const StringName &p_source);
 | 
					 | 
				
			||||||
	_ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const {
 | 
					 | 
				
			||||||
		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() {}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,149 +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_char('\n', ' ');
 | 
					 | 
				
			||||||
	} else if (p_value.get_type() == Variant::DICTIONARY) {
 | 
					 | 
				
			||||||
		return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' ');
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return p_value.get_construct_string().replace_char('\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_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.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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int64_t i = 0; i < p_methodinfo.arguments.size(); ++i) {
 | 
					 | 
				
			||||||
		DocData::ArgumentDoc argument;
 | 
					 | 
				
			||||||
		argument_doc_from_arginfo(argument, p_methodinfo.arguments[i]);
 | 
					 | 
				
			||||||
		int64_t default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
 | 
					 | 
				
			||||||
		if (default_arg_index >= 0) {
 | 
					 | 
				
			||||||
			Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
 | 
					 | 
				
			||||||
			argument.default_value = get_default_value_string(default_arg);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		p_method.arguments.push_back(argument);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,981 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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.is_empty()) {
 | 
					 | 
				
			||||||
							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.is_empty() || p_method.arguments.is_empty()) { // 1.
 | 
					 | 
				
			||||||
						return arguments.size() < p_method.arguments.size();
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2.
 | 
					 | 
				
			||||||
						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 (const KeyValue<Variant, Variant> &kv : enums) {
 | 
					 | 
				
			||||||
				doc.enums[kv.key] = EnumDoc::from_dict(kv.value);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			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);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,87 +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"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <iterator>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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(std::size(error_names) == ERR_MAX);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,99 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** 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[];
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,204 +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/object/object_id.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 = ObjectDB::get_instance<Node>(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,846 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/typedefs.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <atomic> // IWYU pragma: keep // Used in macro. We'd normally use `safe_refcount.h`, but that would cause circular includes.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class String;
 | 
					 | 
				
			||||||
class ObjectID;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum ErrorHandlerType {
 | 
					 | 
				
			||||||
	ERR_HANDLER_ERROR,
 | 
					 | 
				
			||||||
	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.
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
 | 
					 | 
				
			||||||
_NO_INLINE_ void _err_flush_stdout();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,43 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,231 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
	static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	GDExtensionInitialization initialization;
 | 
					 | 
				
			||||||
	int32_t level_initialized = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					 | 
				
			||||||
	bool is_reloading = false;
 | 
					 | 
				
			||||||
	Vector<GDExtensionMethodBind *> invalid_methods;
 | 
					 | 
				
			||||||
	Vector<ObjectID> instance_bindings;
 | 
					 | 
				
			||||||
	GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void _track_instance(void *p_user_data, void *p_instance);
 | 
					 | 
				
			||||||
	static void _untrack_instance(void *p_user_data, void *p_instance);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PackedStringArray get_classes_used() const;
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
										
											
												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 (GODOT_VERSION_MAJOR != compatibility_minimum[0]) {
 | 
					 | 
				
			||||||
		compatible = GODOT_VERSION_MAJOR > compatibility_minimum[0];
 | 
					 | 
				
			||||||
	} else if (GODOT_VERSION_MINOR != compatibility_minimum[1]) {
 | 
					 | 
				
			||||||
		compatible = GODOT_VERSION_MINOR > compatibility_minimum[1];
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		compatible = GODOT_VERSION_PATCH >= compatibility_minimum[2];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compatible) {
 | 
					 | 
				
			||||||
		ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
 | 
					 | 
				
			||||||
		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 (GODOT_VERSION_MAJOR != compatibility_maximum[0]) {
 | 
					 | 
				
			||||||
			compatible = GODOT_VERSION_MAJOR < compatibility_maximum[0];
 | 
					 | 
				
			||||||
		} else if (GODOT_VERSION_MINOR != compatibility_maximum[1]) {
 | 
					 | 
				
			||||||
			compatible = GODOT_VERSION_MINOR < compatibility_maximum[1];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#if GODOT_VERSION_PATCH
 | 
					 | 
				
			||||||
		// #if check to avoid -Wtype-limits warning when 0.
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			compatible = GODOT_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,84 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/extension/gdextension_loader.h"
 | 
					 | 
				
			||||||
#include "core/io/config_file.h"
 | 
					 | 
				
			||||||
#include "core/os/shared_object.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GDExtensionLibraryLoader : public GDExtensionLoader {
 | 
					 | 
				
			||||||
	GDSOFTCLASS(GDExtensionLibraryLoader, 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);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,47 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/object/ref_counted.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GDExtension;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GDExtensionLoader : public RefCounted {
 | 
					 | 
				
			||||||
	GDSOFTCLASS(GDExtensionLoader, GDExtensionLoader);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	virtual Error open_library(const String &p_path) = 0;
 | 
					 | 
				
			||||||
	virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) = 0;
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,93 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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)
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,59 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,37 +0,0 @@
 | 
				
			||||||
import methods
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def run(target, source, env):
 | 
					 | 
				
			||||||
    buffer = methods.get_buffer(str(source[0]))
 | 
					 | 
				
			||||||
    decomp_size = len(buffer)
 | 
					 | 
				
			||||||
    buffer = methods.compress_buffer(buffer)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
        file.write(f"""\
 | 
					 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/io/compression.h"
 | 
					 | 
				
			||||||
#include "core/io/file_access.h"
 | 
					 | 
				
			||||||
#include "core/string/ustring.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline constexpr int _gdextension_interface_data_compressed_size = {len(buffer)};
 | 
					 | 
				
			||||||
inline constexpr int _gdextension_interface_data_uncompressed_size = {decomp_size};
 | 
					 | 
				
			||||||
inline constexpr unsigned char _gdextension_interface_data_compressed[] = {{
 | 
					 | 
				
			||||||
	{methods.format_buffer(buffer, 1)}
 | 
					 | 
				
			||||||
}};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
""")
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,139 +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 = "#pragma once"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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,36 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DefaultControllerMappings {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static const char *mappings[];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
										
											
												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,404 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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 = MouseButtonMask::NONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
"""Functions used to generate source files during build time"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from collections import OrderedDict
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import methods
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def make_default_controller_mappings(target, source, env):
 | 
					 | 
				
			||||||
    with methods.generated_wrapper(str(target[0])) as file:
 | 
					 | 
				
			||||||
        file.write("""\
 | 
					 | 
				
			||||||
#include "core/input/default_controller_mappings.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/typedefs.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
""")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # ensure mappings have a consistent order
 | 
					 | 
				
			||||||
        platform_mappings = OrderedDict()
 | 
					 | 
				
			||||||
        for src_path in map(str, source):
 | 
					 | 
				
			||||||
            with open(src_path, "r", encoding="utf-8") as f:
 | 
					 | 
				
			||||||
                # read mapping file and skip header
 | 
					 | 
				
			||||||
                mapping_file_lines = f.readlines()[2:]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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]:
 | 
					 | 
				
			||||||
                        file.write(
 | 
					 | 
				
			||||||
                            "// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
 | 
					 | 
				
			||||||
                                src_path, current_platform, platform_mappings[current_platform][guid]
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                    platform_mappings[current_platform][guid] = line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PLATFORM_VARIABLES = {
 | 
					 | 
				
			||||||
            "Linux": "LINUXBSD",
 | 
					 | 
				
			||||||
            "Windows": "WINDOWS",
 | 
					 | 
				
			||||||
            "Mac OS X": "MACOS",
 | 
					 | 
				
			||||||
            "Android": "ANDROID",
 | 
					 | 
				
			||||||
            "iOS": "IOS",
 | 
					 | 
				
			||||||
            "Web": "WEB",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("const char *DefaultControllerMappings::mappings[] = {\n")
 | 
					 | 
				
			||||||
        for platform, mappings in platform_mappings.items():
 | 
					 | 
				
			||||||
            variable = PLATFORM_VARIABLES[platform]
 | 
					 | 
				
			||||||
            file.write(f"#ifdef {variable}_ENABLED\n")
 | 
					 | 
				
			||||||
            for mapping in mappings.values():
 | 
					 | 
				
			||||||
                file.write(f'\t"{mapping}",\n')
 | 
					 | 
				
			||||||
            file.write(f"#endif // {variable}_ENABLED\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.write("\tnullptr\n};\n")
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,146 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
constexpr MouseButtonMask operator|(MouseButtonMask p_a, MouseButtonMask p_b) {
 | 
					 | 
				
			||||||
	return static_cast<MouseButtonMask>(static_cast<int>(p_a) | static_cast<int>(p_b));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
constexpr MouseButtonMask &operator|=(MouseButtonMask &p_a, MouseButtonMask p_b) {
 | 
					 | 
				
			||||||
	return p_a = p_a | p_b;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,596 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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 = MouseButtonMask::NONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,923 +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("get_action_description", "action"), &InputMap::get_action_description);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
 | 
					 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone);
 | 
					 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
			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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
String InputMap::get_action_description(const StringName &p_action) const {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!input_map.has(p_action), String(), suggest_actions(p_action));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String ret;
 | 
					 | 
				
			||||||
	const List<Ref<InputEvent>> &inputs = input_map[p_action].inputs;
 | 
					 | 
				
			||||||
	for (Ref<InputEventKey> iek : inputs) {
 | 
					 | 
				
			||||||
		if (iek.is_valid()) {
 | 
					 | 
				
			||||||
			if (!ret.is_empty()) {
 | 
					 | 
				
			||||||
				ret += RTR(" or ");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			ret += iek->as_text();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ret.is_empty()) {
 | 
					 | 
				
			||||||
		ret = RTR("Action has no bound inputs");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
float InputMap::action_get_deadzone(const StringName &p_action) {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		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_focus_mode",                                 TTRC("Toggle Tab Focus Mode") },
 | 
					 | 
				
			||||||
    { "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_graph_follow_left",                          TTRC("Follow Input Port Connection") },
 | 
					 | 
				
			||||||
	{ "ui_graph_follow_right",                         TTRC("Follow Output Port Connection") },
 | 
					 | 
				
			||||||
    { "ui_filedialog_up_one_level",                    TTRC("Go Up One Level") },
 | 
					 | 
				
			||||||
    { "ui_filedialog_refresh",                         TTRC("Refresh") },
 | 
					 | 
				
			||||||
    { "ui_filedialog_show_hidden",                     TTRC("Show Hidden") },
 | 
					 | 
				
			||||||
    { "ui_swap_input_direction ",                      TTRC("Swap Input Direction") },
 | 
					 | 
				
			||||||
    { "ui_unicode_start",                              TTRC("Start Unicode Character Input") },
 | 
					 | 
				
			||||||
    { "ui_colorpicker_delete_preset",                  TTRC("Toggle License Notices") },
 | 
					 | 
				
			||||||
	{ "ui_accessibility_drag_and_drop",                TTRC("Accessibility: Keyboard Drag and Drop") },
 | 
					 | 
				
			||||||
    { "",                                              ""}
 | 
					 | 
				
			||||||
	/* clang-format on */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
String InputMap::get_builtin_display_name(const String &p_name) const {
 | 
					 | 
				
			||||||
	constexpr int len = std::size(_builtin_action_display_names);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < len; i++) {
 | 
					 | 
				
			||||||
		if (_builtin_action_display_names[i].name == p_name) {
 | 
					 | 
				
			||||||
			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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_accessibility_drag_and_drop", 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::M | KeyModifierMask::CTRL));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_focus_mode", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_graph_follow_left", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_graph_follow_left.macos", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_graph_follow_right", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_graph_follow_right.macos", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ///// UI File Dialog Shortcuts /////
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ///// UI ColorPicker Shortcuts /////
 | 
					 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::X));
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
 | 
					 | 
				
			||||||
	default_builtin_cache.insert("ui_colorpicker_delete_preset", inputs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return default_builtin_cache;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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,119 +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.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String get_action_description(const StringName &p_action) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float action_get_deadzone(const StringName &p_action);
 | 
					 | 
				
			||||||
	void action_set_deadzone(const StringName &p_action, float p_deadzone);
 | 
					 | 
				
			||||||
	void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
 | 
					 | 
				
			||||||
	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();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,56 +0,0 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/*  shortcut.h                                                            */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/*                         This file is part of:                          */
 | 
					 | 
				
			||||||
/*                             GODOT ENGINE                               */
 | 
					 | 
				
			||||||
/*                        https://godotengine.org                         */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
					 | 
				
			||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
					 | 
				
			||||||
/* a copy of this software and associated documentation files (the        */
 | 
					 | 
				
			||||||
/* "Software"), to deal in the Software without restriction, including    */
 | 
					 | 
				
			||||||
/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
					 | 
				
			||||||
/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
					 | 
				
			||||||
/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
					 | 
				
			||||||
/* the following conditions:                                              */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* The above copyright notice and this permission notice shall be         */
 | 
					 | 
				
			||||||
/* included in all copies or substantial portions of the Software.        */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
					 | 
				
			||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
					 | 
				
			||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
					 | 
				
			||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
					 | 
				
			||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
					 | 
				
			||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
					 | 
				
			||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/input/input_event.h"
 | 
					 | 
				
			||||||
#include "core/io/resource.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Shortcut : public Resource {
 | 
					 | 
				
			||||||
	GDCLASS(Shortcut, Resource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Array events;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
	static void _bind_methods();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	void set_events(const Array &p_events);
 | 
					 | 
				
			||||||
	Array get_events() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_events_list(const List<Ref<InputEvent>> *p_events);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool matches_event(const Ref<InputEvent> &p_event) const;
 | 
					 | 
				
			||||||
	bool has_valid_event() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String get_as_text() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,373 +0,0 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/*  compression.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 "compression.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					 | 
				
			||||||
#include "core/io/zip_io.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "thirdparty/misc/fastlz.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <zlib.h>
 | 
					 | 
				
			||||||
#include <zstd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef BROTLI_ENABLED
 | 
					 | 
				
			||||||
#include <brotli/decode.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Caches for zstd.
 | 
					 | 
				
			||||||
static BinaryMutex mutex;
 | 
					 | 
				
			||||||
static ZSTD_DCtx *current_zstd_d_ctx = nullptr;
 | 
					 | 
				
			||||||
static bool current_zstd_long_distance_matching;
 | 
					 | 
				
			||||||
static int current_zstd_window_log_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
					 | 
				
			||||||
	switch (p_mode) {
 | 
					 | 
				
			||||||
		case MODE_BROTLI: {
 | 
					 | 
				
			||||||
			ERR_FAIL_V_MSG(-1, "Only brotli decompression is supported.");
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_FASTLZ: {
 | 
					 | 
				
			||||||
			if (p_src_size < 16) {
 | 
					 | 
				
			||||||
				uint8_t src[16];
 | 
					 | 
				
			||||||
				memset(&src[p_src_size], 0, 16 - p_src_size);
 | 
					 | 
				
			||||||
				memcpy(src, p_src, p_src_size);
 | 
					 | 
				
			||||||
				return fastlz_compress(src, 16, p_dst);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				return fastlz_compress(p_src, p_src_size, p_dst);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_DEFLATE:
 | 
					 | 
				
			||||||
		case MODE_GZIP: {
 | 
					 | 
				
			||||||
			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			z_stream strm;
 | 
					 | 
				
			||||||
			strm.zalloc = zipio_alloc;
 | 
					 | 
				
			||||||
			strm.zfree = zipio_free;
 | 
					 | 
				
			||||||
			strm.opaque = Z_NULL;
 | 
					 | 
				
			||||||
			int level = p_mode == MODE_DEFLATE ? zlib_level : gzip_level;
 | 
					 | 
				
			||||||
			int err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
 | 
					 | 
				
			||||||
			if (err != Z_OK) {
 | 
					 | 
				
			||||||
				return -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			strm.avail_in = p_src_size;
 | 
					 | 
				
			||||||
			int aout = deflateBound(&strm, p_src_size);
 | 
					 | 
				
			||||||
			strm.avail_out = aout;
 | 
					 | 
				
			||||||
			strm.next_in = (Bytef *)p_src;
 | 
					 | 
				
			||||||
			strm.next_out = p_dst;
 | 
					 | 
				
			||||||
			deflate(&strm, Z_FINISH);
 | 
					 | 
				
			||||||
			aout = aout - strm.avail_out;
 | 
					 | 
				
			||||||
			deflateEnd(&strm);
 | 
					 | 
				
			||||||
			return aout;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_ZSTD: {
 | 
					 | 
				
			||||||
			ZSTD_CCtx *cctx = ZSTD_createCCtx();
 | 
					 | 
				
			||||||
			ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, zstd_level);
 | 
					 | 
				
			||||||
			if (zstd_long_distance_matching) {
 | 
					 | 
				
			||||||
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_enableLongDistanceMatching, 1);
 | 
					 | 
				
			||||||
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, zstd_window_log_size);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			int max_dst_size = get_max_compressed_buffer_size(p_src_size, MODE_ZSTD);
 | 
					 | 
				
			||||||
			int ret = ZSTD_compressCCtx(cctx, p_dst, max_dst_size, p_src, p_src_size, zstd_level);
 | 
					 | 
				
			||||||
			ZSTD_freeCCtx(cctx);
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ERR_FAIL_V(-1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int Compression::get_max_compressed_buffer_size(int p_src_size, Mode p_mode) {
 | 
					 | 
				
			||||||
	switch (p_mode) {
 | 
					 | 
				
			||||||
		case MODE_BROTLI: {
 | 
					 | 
				
			||||||
			ERR_FAIL_V_MSG(-1, "Only brotli decompression is supported.");
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_FASTLZ: {
 | 
					 | 
				
			||||||
			int ss = p_src_size + p_src_size * 6 / 100;
 | 
					 | 
				
			||||||
			if (ss < 66) {
 | 
					 | 
				
			||||||
				ss = 66;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return ss;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_DEFLATE:
 | 
					 | 
				
			||||||
		case MODE_GZIP: {
 | 
					 | 
				
			||||||
			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			z_stream strm;
 | 
					 | 
				
			||||||
			strm.zalloc = zipio_alloc;
 | 
					 | 
				
			||||||
			strm.zfree = zipio_free;
 | 
					 | 
				
			||||||
			strm.opaque = Z_NULL;
 | 
					 | 
				
			||||||
			int err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
 | 
					 | 
				
			||||||
			if (err != Z_OK) {
 | 
					 | 
				
			||||||
				return -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			int aout = deflateBound(&strm, p_src_size);
 | 
					 | 
				
			||||||
			deflateEnd(&strm);
 | 
					 | 
				
			||||||
			return aout;
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_ZSTD: {
 | 
					 | 
				
			||||||
			return ZSTD_compressBound(p_src_size);
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ERR_FAIL_V(-1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
					 | 
				
			||||||
	switch (p_mode) {
 | 
					 | 
				
			||||||
		case MODE_BROTLI: {
 | 
					 | 
				
			||||||
#ifdef BROTLI_ENABLED
 | 
					 | 
				
			||||||
			size_t ret_size = p_dst_max_size;
 | 
					 | 
				
			||||||
			BrotliDecoderResult res = BrotliDecoderDecompress(p_src_size, p_src, &ret_size, p_dst);
 | 
					 | 
				
			||||||
			ERR_FAIL_COND_V(res != BROTLI_DECODER_RESULT_SUCCESS, -1);
 | 
					 | 
				
			||||||
			return ret_size;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
			ERR_FAIL_V_MSG(-1, "Godot was compiled without brotli support.");
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_FASTLZ: {
 | 
					 | 
				
			||||||
			int ret_size = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (p_dst_max_size < 16) {
 | 
					 | 
				
			||||||
				uint8_t dst[16];
 | 
					 | 
				
			||||||
				fastlz_decompress(p_src, p_src_size, dst, 16);
 | 
					 | 
				
			||||||
				memcpy(p_dst, dst, p_dst_max_size);
 | 
					 | 
				
			||||||
				ret_size = p_dst_max_size;
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return ret_size;
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_DEFLATE:
 | 
					 | 
				
			||||||
		case MODE_GZIP: {
 | 
					 | 
				
			||||||
			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			z_stream strm;
 | 
					 | 
				
			||||||
			strm.zalloc = zipio_alloc;
 | 
					 | 
				
			||||||
			strm.zfree = zipio_free;
 | 
					 | 
				
			||||||
			strm.opaque = Z_NULL;
 | 
					 | 
				
			||||||
			strm.avail_in = 0;
 | 
					 | 
				
			||||||
			strm.next_in = Z_NULL;
 | 
					 | 
				
			||||||
			int err = inflateInit2(&strm, window_bits);
 | 
					 | 
				
			||||||
			ERR_FAIL_COND_V(err != Z_OK, -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			strm.avail_in = p_src_size;
 | 
					 | 
				
			||||||
			strm.avail_out = p_dst_max_size;
 | 
					 | 
				
			||||||
			strm.next_in = (Bytef *)p_src;
 | 
					 | 
				
			||||||
			strm.next_out = p_dst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			err = inflate(&strm, Z_FINISH);
 | 
					 | 
				
			||||||
			int total = strm.total_out;
 | 
					 | 
				
			||||||
			inflateEnd(&strm);
 | 
					 | 
				
			||||||
			ERR_FAIL_COND_V(err != Z_STREAM_END, -1);
 | 
					 | 
				
			||||||
			return total;
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
		case MODE_ZSTD: {
 | 
					 | 
				
			||||||
			MutexLock lock(mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!current_zstd_d_ctx || current_zstd_long_distance_matching != zstd_long_distance_matching || current_zstd_window_log_size != zstd_window_log_size) {
 | 
					 | 
				
			||||||
				if (current_zstd_d_ctx) {
 | 
					 | 
				
			||||||
					ZSTD_freeDCtx(current_zstd_d_ctx);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				current_zstd_d_ctx = ZSTD_createDCtx();
 | 
					 | 
				
			||||||
				if (zstd_long_distance_matching) {
 | 
					 | 
				
			||||||
					ZSTD_DCtx_setParameter(current_zstd_d_ctx, ZSTD_d_windowLogMax, zstd_window_log_size);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				current_zstd_long_distance_matching = zstd_long_distance_matching;
 | 
					 | 
				
			||||||
				current_zstd_window_log_size = zstd_window_log_size;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			int ret = ZSTD_decompressDCtx(current_zstd_d_ctx, p_dst, p_dst_max_size, p_src, p_src_size);
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
		} break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ERR_FAIL_V(-1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
	This will handle both Gzip and Deflate streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
 | 
					 | 
				
			||||||
	This is required for compressed data whose final uncompressed size is unknown, as is the case for HTTP response bodies.
 | 
					 | 
				
			||||||
	This is much slower however than using Compression::decompress because it may result in multiple full copies of the output buffer.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
					 | 
				
			||||||
	uint8_t *dst = nullptr;
 | 
					 | 
				
			||||||
	int out_mark = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V(p_src_size <= 0, Z_DATA_ERROR);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p_mode == MODE_BROTLI) {
 | 
					 | 
				
			||||||
#ifdef BROTLI_ENABLED
 | 
					 | 
				
			||||||
		BrotliDecoderResult ret;
 | 
					 | 
				
			||||||
		BrotliDecoderState *state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
 | 
					 | 
				
			||||||
		ERR_FAIL_NULL_V(state, Z_DATA_ERROR);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Setup the stream inputs.
 | 
					 | 
				
			||||||
		const uint8_t *next_in = p_src;
 | 
					 | 
				
			||||||
		size_t avail_in = p_src_size;
 | 
					 | 
				
			||||||
		uint8_t *next_out = nullptr;
 | 
					 | 
				
			||||||
		size_t avail_out = 0;
 | 
					 | 
				
			||||||
		size_t total_out = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Ensure the destination buffer is empty.
 | 
					 | 
				
			||||||
		p_dst_vect->clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Decompress until stream ends or end of file.
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			// Add another chunk size to the output buffer.
 | 
					 | 
				
			||||||
			// This forces a copy of the whole buffer.
 | 
					 | 
				
			||||||
			p_dst_vect->resize(p_dst_vect->size() + gzip_chunk);
 | 
					 | 
				
			||||||
			// Get pointer to the actual output buffer.
 | 
					 | 
				
			||||||
			dst = p_dst_vect->ptrw();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Set the stream to the new output stream.
 | 
					 | 
				
			||||||
			// Since it was copied, we need to reset the stream to the new buffer.
 | 
					 | 
				
			||||||
			next_out = &(dst[out_mark]);
 | 
					 | 
				
			||||||
			avail_out += gzip_chunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ret = BrotliDecoderDecompressStream(state, &avail_in, &next_in, &avail_out, &next_out, &total_out);
 | 
					 | 
				
			||||||
			if (ret == BROTLI_DECODER_RESULT_ERROR) {
 | 
					 | 
				
			||||||
				WARN_PRINT(BrotliDecoderErrorString(BrotliDecoderGetErrorCode(state)));
 | 
					 | 
				
			||||||
				BrotliDecoderDestroyInstance(state);
 | 
					 | 
				
			||||||
				p_dst_vect->clear();
 | 
					 | 
				
			||||||
				return Z_DATA_ERROR;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			out_mark += gzip_chunk - avail_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Enforce max output size.
 | 
					 | 
				
			||||||
			if (p_max_dst_size > -1 && total_out > (uint64_t)p_max_dst_size) {
 | 
					 | 
				
			||||||
				BrotliDecoderDestroyInstance(state);
 | 
					 | 
				
			||||||
				p_dst_vect->clear();
 | 
					 | 
				
			||||||
				return Z_BUF_ERROR;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} while (ret != BROTLI_DECODER_RESULT_SUCCESS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// If all done successfully, resize the output if it's larger than the actual output.
 | 
					 | 
				
			||||||
		if ((unsigned long)p_dst_vect->size() > total_out) {
 | 
					 | 
				
			||||||
			p_dst_vect->resize(total_out);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Clean up and return.
 | 
					 | 
				
			||||||
		BrotliDecoderDestroyInstance(state);
 | 
					 | 
				
			||||||
		return Z_OK;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
		ERR_FAIL_V_MSG(Z_ERRNO, "Godot was compiled without brotli support.");
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		// This function only supports GZip and Deflate.
 | 
					 | 
				
			||||||
		ERR_FAIL_COND_V(p_mode != MODE_DEFLATE && p_mode != MODE_GZIP, Z_ERRNO);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int ret;
 | 
					 | 
				
			||||||
		z_stream strm;
 | 
					 | 
				
			||||||
		int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Initialize the stream.
 | 
					 | 
				
			||||||
		strm.zalloc = Z_NULL;
 | 
					 | 
				
			||||||
		strm.zfree = Z_NULL;
 | 
					 | 
				
			||||||
		strm.opaque = Z_NULL;
 | 
					 | 
				
			||||||
		strm.avail_in = 0;
 | 
					 | 
				
			||||||
		strm.next_in = Z_NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int err = inflateInit2(&strm, window_bits);
 | 
					 | 
				
			||||||
		ERR_FAIL_COND_V(err != Z_OK, -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Setup the stream inputs.
 | 
					 | 
				
			||||||
		strm.next_in = (Bytef *)p_src;
 | 
					 | 
				
			||||||
		strm.avail_in = p_src_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Ensure the destination buffer is empty.
 | 
					 | 
				
			||||||
		p_dst_vect->clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Decompress until deflate stream ends or end of file.
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			// Add another chunk size to the output buffer.
 | 
					 | 
				
			||||||
			// This forces a copy of the whole buffer.
 | 
					 | 
				
			||||||
			p_dst_vect->resize(p_dst_vect->size() + gzip_chunk);
 | 
					 | 
				
			||||||
			// Get pointer to the actual output buffer.
 | 
					 | 
				
			||||||
			dst = p_dst_vect->ptrw();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Set the stream to the new output stream.
 | 
					 | 
				
			||||||
			// Since it was copied, we need to reset the stream to the new buffer.
 | 
					 | 
				
			||||||
			strm.next_out = &(dst[out_mark]);
 | 
					 | 
				
			||||||
			strm.avail_out = gzip_chunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Run inflate() on input until output buffer is full and needs to be resized or input runs out.
 | 
					 | 
				
			||||||
			do {
 | 
					 | 
				
			||||||
				ret = inflate(&strm, Z_SYNC_FLUSH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				switch (ret) {
 | 
					 | 
				
			||||||
					case Z_NEED_DICT:
 | 
					 | 
				
			||||||
						ret = Z_DATA_ERROR;
 | 
					 | 
				
			||||||
						[[fallthrough]];
 | 
					 | 
				
			||||||
					case Z_DATA_ERROR:
 | 
					 | 
				
			||||||
					case Z_MEM_ERROR:
 | 
					 | 
				
			||||||
					case Z_STREAM_ERROR:
 | 
					 | 
				
			||||||
					case Z_BUF_ERROR:
 | 
					 | 
				
			||||||
						if (strm.msg) {
 | 
					 | 
				
			||||||
							WARN_PRINT(strm.msg);
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						(void)inflateEnd(&strm);
 | 
					 | 
				
			||||||
						p_dst_vect->clear();
 | 
					 | 
				
			||||||
						return ret;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} while (strm.avail_out > 0 && strm.avail_in > 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			out_mark += gzip_chunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Enforce max output size.
 | 
					 | 
				
			||||||
			if (p_max_dst_size > -1 && strm.total_out > (uint64_t)p_max_dst_size) {
 | 
					 | 
				
			||||||
				(void)inflateEnd(&strm);
 | 
					 | 
				
			||||||
				p_dst_vect->clear();
 | 
					 | 
				
			||||||
				return Z_BUF_ERROR;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} while (ret != Z_STREAM_END);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// If all done successfully, resize the output if it's larger than the actual output.
 | 
					 | 
				
			||||||
		if ((unsigned long)p_dst_vect->size() > strm.total_out) {
 | 
					 | 
				
			||||||
			p_dst_vect->resize(strm.total_out);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Clean up and return.
 | 
					 | 
				
			||||||
		(void)inflateEnd(&strm);
 | 
					 | 
				
			||||||
		return Z_OK;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
 | 
					 | 
				
			||||||
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
 | 
					 | 
				
			||||||
int Compression::zstd_level = 3;
 | 
					 | 
				
			||||||
bool Compression::zstd_long_distance_matching = false;
 | 
					 | 
				
			||||||
int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
 | 
					 | 
				
			||||||
int Compression::gzip_chunk = 16384;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,57 +0,0 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/*  compression.h                                                         */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/*                         This file is part of:                          */
 | 
					 | 
				
			||||||
/*                             GODOT ENGINE                               */
 | 
					 | 
				
			||||||
/*                        https://godotengine.org                         */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
					 | 
				
			||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
					 | 
				
			||||||
/* a copy of this software and associated documentation files (the        */
 | 
					 | 
				
			||||||
/* "Software"), to deal in the Software without restriction, including    */
 | 
					 | 
				
			||||||
/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
					 | 
				
			||||||
/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
					 | 
				
			||||||
/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
					 | 
				
			||||||
/* the following conditions:                                              */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* The above copyright notice and this permission notice shall be         */
 | 
					 | 
				
			||||||
/* included in all copies or substantial portions of the Software.        */
 | 
					 | 
				
			||||||
/*                                                                        */
 | 
					 | 
				
			||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
					 | 
				
			||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
					 | 
				
			||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
					 | 
				
			||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
					 | 
				
			||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
					 | 
				
			||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
					 | 
				
			||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
					 | 
				
			||||||
/**************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/templates/vector.h"
 | 
					 | 
				
			||||||
#include "core/typedefs.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Compression {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static int zlib_level;
 | 
					 | 
				
			||||||
	static int gzip_level;
 | 
					 | 
				
			||||||
	static int zstd_level;
 | 
					 | 
				
			||||||
	static bool zstd_long_distance_matching;
 | 
					 | 
				
			||||||
	static int zstd_window_log_size;
 | 
					 | 
				
			||||||
	static int gzip_chunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum Mode : int32_t {
 | 
					 | 
				
			||||||
		MODE_FASTLZ,
 | 
					 | 
				
			||||||
		MODE_DEFLATE,
 | 
					 | 
				
			||||||
		MODE_ZSTD,
 | 
					 | 
				
			||||||
		MODE_GZIP,
 | 
					 | 
				
			||||||
		MODE_BROTLI
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
					 | 
				
			||||||
	static int get_max_compressed_buffer_size(int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
					 | 
				
			||||||
	static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
					 | 
				
			||||||
	static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue