Merge pull request 'Updated to 4.4-rc1 & better justfile' (#1) from Sara/godot-module-template:development into development
Reviewed-on: hertog/godot-module-template#1
This commit is contained in:
		
						commit
						d08586768d
					
				| 
						 | 
					@ -1,27 +1,52 @@
 | 
				
			||||||
# Commented out parameters are those with the same value as base LLVM style.
 | 
					# 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
 | 
					# 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 14.0).
 | 
					# chosen value in case the base style changes (last sync: Clang 17.0.6).
 | 
				
			||||||
---
 | 
					BasedOnStyle: LLVM
 | 
				
			||||||
### General config, applies to all languages ###
 | 
					 | 
				
			||||||
BasedOnStyle:  LLVM
 | 
					 | 
				
			||||||
AccessModifierOffset: -4
 | 
					AccessModifierOffset: -4
 | 
				
			||||||
AlignAfterOpenBracket: DontAlign
 | 
					AlignAfterOpenBracket: DontAlign
 | 
				
			||||||
# AlignArrayOfStructures: None
 | 
					# AlignArrayOfStructures: None
 | 
				
			||||||
# AlignConsecutiveMacros: None
 | 
					# AlignConsecutiveAssignments:
 | 
				
			||||||
# AlignConsecutiveAssignments: None
 | 
					#   Enabled: false
 | 
				
			||||||
# AlignConsecutiveBitFields: None
 | 
					#   AcrossEmptyLines: false
 | 
				
			||||||
# AlignConsecutiveDeclarations: None
 | 
					#   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
 | 
					# AlignEscapedNewlines: Right
 | 
				
			||||||
AlignOperands:   DontAlign
 | 
					AlignOperands: DontAlign
 | 
				
			||||||
AlignTrailingComments: false
 | 
					AlignTrailingComments:
 | 
				
			||||||
 | 
					  Kind: Never
 | 
				
			||||||
 | 
					  OverEmptyLines: 0
 | 
				
			||||||
# AllowAllArgumentsOnNextLine: true
 | 
					# AllowAllArgumentsOnNextLine: true
 | 
				
			||||||
AllowAllParametersOfDeclarationOnNextLine: false
 | 
					AllowAllParametersOfDeclarationOnNextLine: false
 | 
				
			||||||
# AllowShortEnumsOnASingleLine: true
 | 
					 | 
				
			||||||
# AllowShortBlocksOnASingleLine: Never
 | 
					# AllowShortBlocksOnASingleLine: Never
 | 
				
			||||||
# AllowShortCaseLabelsOnASingleLine: false
 | 
					# AllowShortCaseLabelsOnASingleLine: false
 | 
				
			||||||
# AllowShortFunctionsOnASingleLine: All
 | 
					# AllowShortEnumsOnASingleLine: true
 | 
				
			||||||
# AllowShortLambdasOnASingleLine: All
 | 
					AllowShortFunctionsOnASingleLine: Inline
 | 
				
			||||||
# AllowShortIfStatementsOnASingleLine: Never
 | 
					# AllowShortIfStatementsOnASingleLine: Never
 | 
				
			||||||
 | 
					# AllowShortLambdasOnASingleLine: All
 | 
				
			||||||
# AllowShortLoopsOnASingleLine: false
 | 
					# AllowShortLoopsOnASingleLine: false
 | 
				
			||||||
# AlwaysBreakAfterDefinitionReturnType: None
 | 
					# AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
# AlwaysBreakAfterReturnType: None
 | 
					# AlwaysBreakAfterReturnType: None
 | 
				
			||||||
| 
						 | 
					@ -31,50 +56,48 @@ AllowAllParametersOfDeclarationOnNextLine: false
 | 
				
			||||||
#   - __capability
 | 
					#   - __capability
 | 
				
			||||||
# BinPackArguments: true
 | 
					# BinPackArguments: true
 | 
				
			||||||
# BinPackParameters: true
 | 
					# BinPackParameters: true
 | 
				
			||||||
 | 
					# BitFieldColonSpacing: Both
 | 
				
			||||||
# BraceWrapping:
 | 
					# BraceWrapping:
 | 
				
			||||||
#   AfterCaseLabel:  false
 | 
					#   AfterCaseLabel: false
 | 
				
			||||||
#   AfterClass:      false
 | 
					#   AfterClass: false
 | 
				
			||||||
#   AfterControlStatement: Never
 | 
					#   AfterControlStatement: Never
 | 
				
			||||||
#   AfterEnum:       false
 | 
					#   AfterEnum: false
 | 
				
			||||||
#   AfterFunction:   false
 | 
					#   AfterFunction: false
 | 
				
			||||||
#   AfterNamespace:  false
 | 
					#   AfterNamespace: false
 | 
				
			||||||
#   AfterObjCDeclaration: false
 | 
					#   AfterObjCDeclaration: false
 | 
				
			||||||
#   AfterStruct:     false
 | 
					#   AfterStruct: false
 | 
				
			||||||
#   AfterUnion:      false
 | 
					#   AfterUnion: false
 | 
				
			||||||
#   AfterExternBlock: false
 | 
					#   AfterExternBlock: false
 | 
				
			||||||
#   BeforeCatch:     false
 | 
					#   BeforeCatch: false
 | 
				
			||||||
#   BeforeElse:      false
 | 
					#   BeforeElse: false
 | 
				
			||||||
#   BeforeLambdaBody: false
 | 
					#   BeforeLambdaBody: false
 | 
				
			||||||
#   BeforeWhile:     false
 | 
					#   BeforeWhile: false
 | 
				
			||||||
#   IndentBraces:    false
 | 
					#   IndentBraces: false
 | 
				
			||||||
#   SplitEmptyFunction: true
 | 
					#   SplitEmptyFunction: true
 | 
				
			||||||
#   SplitEmptyRecord: true
 | 
					#   SplitEmptyRecord: true
 | 
				
			||||||
#   SplitEmptyNamespace: true
 | 
					#   SplitEmptyNamespace: true
 | 
				
			||||||
 | 
					# BreakAfterAttributes: Never
 | 
				
			||||||
 | 
					# BreakAfterJavaFieldAnnotations: false
 | 
				
			||||||
 | 
					# BreakArrays: true
 | 
				
			||||||
# BreakBeforeBinaryOperators: None
 | 
					# BreakBeforeBinaryOperators: None
 | 
				
			||||||
# BreakBeforeConceptDeclarations: true
 | 
					 | 
				
			||||||
# BreakBeforeBraces: Attach
 | 
					# BreakBeforeBraces: Attach
 | 
				
			||||||
# BreakBeforeInheritanceComma: false
 | 
					# BreakBeforeConceptDeclarations: Always
 | 
				
			||||||
# BreakInheritanceList: BeforeColon
 | 
					# BreakBeforeInlineASMColon: OnlyMultiline
 | 
				
			||||||
# BreakBeforeTernaryOperators: true
 | 
					# BreakBeforeTernaryOperators: true
 | 
				
			||||||
# BreakConstructorInitializersBeforeComma: false
 | 
					 | 
				
			||||||
BreakConstructorInitializers: AfterColon
 | 
					BreakConstructorInitializers: AfterColon
 | 
				
			||||||
 | 
					# BreakInheritanceList: BeforeColon
 | 
				
			||||||
# BreakStringLiterals: true
 | 
					# BreakStringLiterals: true
 | 
				
			||||||
ColumnLimit:     0
 | 
					ColumnLimit: 0
 | 
				
			||||||
# CommentPragmas:  '^ IWYU pragma:'
 | 
					# CommentPragmas: "^ IWYU pragma:"
 | 
				
			||||||
# QualifierAlignment: Leave
 | 
					 | 
				
			||||||
# CompactNamespaces: false
 | 
					# CompactNamespaces: false
 | 
				
			||||||
ConstructorInitializerIndentWidth: 8
 | 
					ConstructorInitializerIndentWidth: 8
 | 
				
			||||||
ContinuationIndentWidth: 8
 | 
					ContinuationIndentWidth: 8
 | 
				
			||||||
Cpp11BracedListStyle: false
 | 
					Cpp11BracedListStyle: false
 | 
				
			||||||
# DeriveLineEnding: true
 | 
					 | 
				
			||||||
# DerivePointerAlignment: false
 | 
					# DerivePointerAlignment: false
 | 
				
			||||||
# DisableFormat:   false
 | 
					# DisableFormat: false
 | 
				
			||||||
# EmptyLineAfterAccessModifier: Never
 | 
					# EmptyLineAfterAccessModifier: Never
 | 
				
			||||||
# EmptyLineBeforeAccessModifier: LogicalBlock
 | 
					# EmptyLineBeforeAccessModifier: LogicalBlock
 | 
				
			||||||
# ExperimentalAutoDetectBinPacking: false
 | 
					# ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
# PackConstructorInitializers: BinPack
 | 
					 | 
				
			||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
					 | 
				
			||||||
# AllowAllConstructorInitializersOnNextLine: true
 | 
					 | 
				
			||||||
# FixNamespaceComments: true
 | 
					# FixNamespaceComments: true
 | 
				
			||||||
# ForEachMacros:
 | 
					# ForEachMacros:
 | 
				
			||||||
#   - foreach
 | 
					#   - foreach
 | 
				
			||||||
| 
						 | 
					@ -82,34 +105,61 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
				
			||||||
#   - BOOST_FOREACH
 | 
					#   - BOOST_FOREACH
 | 
				
			||||||
# IfMacros:
 | 
					# IfMacros:
 | 
				
			||||||
#   - KJ_IF_MAYBE
 | 
					#   - KJ_IF_MAYBE
 | 
				
			||||||
# IncludeBlocks:   Preserve
 | 
					# IncludeBlocks: Preserve
 | 
				
			||||||
IncludeCategories:
 | 
					IncludeCategories:
 | 
				
			||||||
  - Regex:           '".*"'
 | 
					  - Regex: ^".*"$
 | 
				
			||||||
    Priority:        1
 | 
					    Priority: 1
 | 
				
			||||||
  - Regex:           '^<.*\.h>'
 | 
					  - Regex: ^<.*\.h>$
 | 
				
			||||||
    Priority:        2
 | 
					    Priority: 2
 | 
				
			||||||
  - Regex:           '^<.*'
 | 
					  - Regex: ^<.*>$
 | 
				
			||||||
    Priority:        3
 | 
					    Priority: 3
 | 
				
			||||||
# IncludeIsMainRegex: '(Test)?$'
 | 
					# IncludeIsMainRegex: (Test)?$
 | 
				
			||||||
# IncludeIsMainSourceRegex: ''
 | 
					# IncludeIsMainSourceRegex: ""
 | 
				
			||||||
# IndentAccessModifiers: false
 | 
					# IndentAccessModifiers: false
 | 
				
			||||||
IndentCaseLabels: true
 | 
					 | 
				
			||||||
# IndentCaseBlocks: false
 | 
					# IndentCaseBlocks: false
 | 
				
			||||||
 | 
					IndentCaseLabels: true
 | 
				
			||||||
 | 
					# IndentExternBlock: AfterExternBlock
 | 
				
			||||||
# IndentGotoLabels: true
 | 
					# IndentGotoLabels: true
 | 
				
			||||||
# IndentPPDirectives: None
 | 
					# IndentPPDirectives: None
 | 
				
			||||||
# IndentExternBlock: AfterExternBlock
 | 
					# IndentRequiresClause: true
 | 
				
			||||||
# IndentRequires:  false
 | 
					IndentWidth: 4
 | 
				
			||||||
IndentWidth:     4
 | 
					 | 
				
			||||||
# IndentWrappedFunctionNames: false
 | 
					# IndentWrappedFunctionNames: false
 | 
				
			||||||
 | 
					InsertBraces: true
 | 
				
			||||||
 | 
					# InsertNewlineAtEOF: false
 | 
				
			||||||
# InsertTrailingCommas: None
 | 
					# 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
 | 
					# JavaScriptQuotes: Leave
 | 
				
			||||||
# JavaScriptWrapImports: true
 | 
					# JavaScriptWrapImports: true
 | 
				
			||||||
 | 
					# KeepEmptyLinesAtEOF: false
 | 
				
			||||||
KeepEmptyLinesAtTheStartOfBlocks: false
 | 
					KeepEmptyLinesAtTheStartOfBlocks: false
 | 
				
			||||||
# LambdaBodyIndentation: Signature
 | 
					# LambdaBodyIndentation: Signature
 | 
				
			||||||
# MacroBlockBegin: ''
 | 
					# Language: Cpp
 | 
				
			||||||
# MacroBlockEnd:   ''
 | 
					# LineEnding: DeriveLF
 | 
				
			||||||
 | 
					# MacroBlockBegin: ""
 | 
				
			||||||
 | 
					# MacroBlockEnd: ""
 | 
				
			||||||
# MaxEmptyLinesToKeep: 1
 | 
					# MaxEmptyLinesToKeep: 1
 | 
				
			||||||
# NamespaceIndentation: None
 | 
					# NamespaceIndentation: None
 | 
				
			||||||
 | 
					# ObjCBinPackProtocolList: Auto
 | 
				
			||||||
 | 
					ObjCBlockIndentWidth: 4
 | 
				
			||||||
 | 
					# ObjCBreakBeforeNestedBlockParam: true
 | 
				
			||||||
 | 
					# ObjCSpaceAfterProperty: false
 | 
				
			||||||
 | 
					# ObjCSpaceBeforeProtocolList: true
 | 
				
			||||||
 | 
					# PPIndentWidth: -1
 | 
				
			||||||
 | 
					PackConstructorInitializers: NextLine
 | 
				
			||||||
# PenaltyBreakAssignment: 2
 | 
					# PenaltyBreakAssignment: 2
 | 
				
			||||||
# PenaltyBreakBeforeFirstCallParameter: 19
 | 
					# PenaltyBreakBeforeFirstCallParameter: 19
 | 
				
			||||||
# PenaltyBreakComment: 300
 | 
					# PenaltyBreakComment: 300
 | 
				
			||||||
| 
						 | 
					@ -118,82 +168,71 @@ KeepEmptyLinesAtTheStartOfBlocks: false
 | 
				
			||||||
# PenaltyBreakString: 1000
 | 
					# PenaltyBreakString: 1000
 | 
				
			||||||
# PenaltyBreakTemplateDeclaration: 10
 | 
					# PenaltyBreakTemplateDeclaration: 10
 | 
				
			||||||
# PenaltyExcessCharacter: 1000000
 | 
					# PenaltyExcessCharacter: 1000000
 | 
				
			||||||
# PenaltyReturnTypeOnItsOwnLine: 60
 | 
					 | 
				
			||||||
# PenaltyIndentedWhitespace: 0
 | 
					# PenaltyIndentedWhitespace: 0
 | 
				
			||||||
 | 
					# PenaltyReturnTypeOnItsOwnLine: 60
 | 
				
			||||||
# PointerAlignment: Right
 | 
					# PointerAlignment: Right
 | 
				
			||||||
# PPIndentWidth:   -1
 | 
					# QualifierAlignment: Leave
 | 
				
			||||||
# ReferenceAlignment: Pointer
 | 
					# ReferenceAlignment: Pointer
 | 
				
			||||||
# ReflowComments:  true
 | 
					# ReflowComments: true
 | 
				
			||||||
# RemoveBracesLLVM: false
 | 
					# RemoveBracesLLVM: false
 | 
				
			||||||
 | 
					# RemoveParentheses: Leave
 | 
				
			||||||
 | 
					RemoveSemicolon: true
 | 
				
			||||||
 | 
					# RequiresClausePosition: OwnLine
 | 
				
			||||||
 | 
					# RequiresExpressionIndentation: OuterScope
 | 
				
			||||||
# SeparateDefinitionBlocks: Leave
 | 
					# SeparateDefinitionBlocks: Leave
 | 
				
			||||||
# ShortNamespaceLines: 1
 | 
					# ShortNamespaceLines: 1
 | 
				
			||||||
# SortIncludes:    CaseSensitive
 | 
					# SortIncludes: CaseSensitive
 | 
				
			||||||
# SortJavaStaticImport: Before
 | 
					# SortJavaStaticImport: Before
 | 
				
			||||||
# SortUsingDeclarations: true
 | 
					# SortUsingDeclarations: LexicographicNumeric
 | 
				
			||||||
# SpaceAfterCStyleCast: false
 | 
					# SpaceAfterCStyleCast: false
 | 
				
			||||||
# SpaceAfterLogicalNot: false
 | 
					# SpaceAfterLogicalNot: false
 | 
				
			||||||
# SpaceAfterTemplateKeyword: true
 | 
					# SpaceAfterTemplateKeyword: true
 | 
				
			||||||
 | 
					# SpaceAroundPointerQualifiers: Default
 | 
				
			||||||
# SpaceBeforeAssignmentOperators: true
 | 
					# SpaceBeforeAssignmentOperators: true
 | 
				
			||||||
# SpaceBeforeCaseColon: false
 | 
					# SpaceBeforeCaseColon: false
 | 
				
			||||||
# SpaceBeforeCpp11BracedList: false
 | 
					# SpaceBeforeCpp11BracedList: false
 | 
				
			||||||
# SpaceBeforeCtorInitializerColon: true
 | 
					# SpaceBeforeCtorInitializerColon: true
 | 
				
			||||||
# SpaceBeforeInheritanceColon: true
 | 
					# SpaceBeforeInheritanceColon: true
 | 
				
			||||||
 | 
					# SpaceBeforeJsonColon: false
 | 
				
			||||||
# SpaceBeforeParens: ControlStatements
 | 
					# SpaceBeforeParens: ControlStatements
 | 
				
			||||||
# SpaceBeforeParensOptions:
 | 
					# SpaceBeforeParensOptions:
 | 
				
			||||||
#   AfterControlStatements: true
 | 
					#   AfterControlStatements: true
 | 
				
			||||||
#   AfterForeachMacros: true
 | 
					#   AfterForeachMacros: true
 | 
				
			||||||
#   AfterFunctionDefinitionName: false
 | 
					 | 
				
			||||||
#   AfterFunctionDeclarationName: false
 | 
					#   AfterFunctionDeclarationName: false
 | 
				
			||||||
#   AfterIfMacros:   true
 | 
					#   AfterFunctionDefinitionName: false
 | 
				
			||||||
 | 
					#   AfterIfMacros: true
 | 
				
			||||||
#   AfterOverloadedOperator: false
 | 
					#   AfterOverloadedOperator: false
 | 
				
			||||||
 | 
					#   AfterRequiresInClause: false
 | 
				
			||||||
 | 
					#   AfterRequiresInExpression: false
 | 
				
			||||||
#   BeforeNonEmptyParentheses: false
 | 
					#   BeforeNonEmptyParentheses: false
 | 
				
			||||||
# SpaceAroundPointerQualifiers: Default
 | 
					 | 
				
			||||||
# SpaceBeforeRangeBasedForLoopColon: true
 | 
					# SpaceBeforeRangeBasedForLoopColon: true
 | 
				
			||||||
# SpaceInEmptyBlock: false
 | 
					 | 
				
			||||||
# SpaceInEmptyParentheses: false
 | 
					 | 
				
			||||||
# SpacesBeforeTrailingComments: 1
 | 
					 | 
				
			||||||
# SpacesInAngles:  Never
 | 
					 | 
				
			||||||
# SpacesInConditionalStatement: false
 | 
					 | 
				
			||||||
# SpacesInContainerLiterals: true
 | 
					 | 
				
			||||||
# SpacesInCStyleCastParentheses: false
 | 
					 | 
				
			||||||
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
 | 
					 | 
				
			||||||
## our comment capitalization at the same time.
 | 
					 | 
				
			||||||
SpacesInLineCommentPrefix:
 | 
					 | 
				
			||||||
  Minimum:         0
 | 
					 | 
				
			||||||
  Maximum:         -1
 | 
					 | 
				
			||||||
# SpacesInParentheses: false
 | 
					 | 
				
			||||||
# SpacesInSquareBrackets: false
 | 
					 | 
				
			||||||
# SpaceBeforeSquareBrackets: false
 | 
					# SpaceBeforeSquareBrackets: false
 | 
				
			||||||
# BitFieldColonSpacing: Both
 | 
					# 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:
 | 
					# StatementAttributeLikeMacros:
 | 
				
			||||||
#   - Q_EMIT
 | 
					#   - Q_EMIT
 | 
				
			||||||
# StatementMacros:
 | 
					# StatementMacros:
 | 
				
			||||||
#   - Q_UNUSED
 | 
					#   - Q_UNUSED
 | 
				
			||||||
#   - QT_REQUIRE_VERSION
 | 
					#   - QT_REQUIRE_VERSION
 | 
				
			||||||
TabWidth:        4
 | 
					TabWidth: 4
 | 
				
			||||||
# UseCRLF:         false
 | 
					UseTab: Always
 | 
				
			||||||
UseTab:          Always
 | 
					# VerilogBreakBetweenInstancePorts: true
 | 
				
			||||||
# WhitespaceSensitiveMacros:
 | 
					# WhitespaceSensitiveMacros:
 | 
				
			||||||
#   - STRINGIZE
 | 
					 | 
				
			||||||
#   - PP_STRINGIZE
 | 
					 | 
				
			||||||
#   - BOOST_PP_STRINGIZE
 | 
					#   - BOOST_PP_STRINGIZE
 | 
				
			||||||
#   - NS_SWIFT_NAME
 | 
					 | 
				
			||||||
#   - CF_SWIFT_NAME
 | 
					#   - CF_SWIFT_NAME
 | 
				
			||||||
---
 | 
					#   - NS_SWIFT_NAME
 | 
				
			||||||
### C++ specific config ###
 | 
					#   - PP_STRINGIZE
 | 
				
			||||||
Language:        Cpp
 | 
					#   - STRINGIZE
 | 
				
			||||||
Standard:        c++17
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
### ObjC specific config ###
 | 
					 | 
				
			||||||
Language:        ObjC
 | 
					 | 
				
			||||||
# ObjCBinPackProtocolList: Auto
 | 
					 | 
				
			||||||
ObjCBlockIndentWidth: 4
 | 
					 | 
				
			||||||
# ObjCBreakBeforeNestedBlockParam: true
 | 
					 | 
				
			||||||
# ObjCSpaceAfterProperty: false
 | 
					 | 
				
			||||||
# ObjCSpaceBeforeProtocolList: true
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
### Java specific config ###
 | 
					 | 
				
			||||||
Language:        Java
 | 
					 | 
				
			||||||
# BreakAfterJavaFieldAnnotations: false
 | 
					 | 
				
			||||||
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
 | 
					 | 
				
			||||||
...
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,13 @@
 | 
				
			||||||
---
 | 
					Checks:
 | 
				
			||||||
Checks: >-
 | 
					  - -*
 | 
				
			||||||
  -*,
 | 
					  - cppcoreguidelines-pro-type-member-init
 | 
				
			||||||
  cppcoreguidelines-pro-type-member-init,
 | 
					  - modernize-redundant-void-arg
 | 
				
			||||||
  modernize-redundant-void-arg,
 | 
					  - modernize-use-bool-literals
 | 
				
			||||||
  modernize-use-bool-literals,
 | 
					  - modernize-use-default-member-init
 | 
				
			||||||
  modernize-use-default-member-init,
 | 
					  - modernize-use-nullptr
 | 
				
			||||||
  modernize-use-nullptr,
 | 
					  - readability-braces-around-statements
 | 
				
			||||||
  readability-braces-around-statements,
 | 
					  - readability-redundant-member-init
 | 
				
			||||||
  readability-redundant-member-init
 | 
					HeaderFileExtensions: ["", h, hh, hpp, hxx, inc, glsl]
 | 
				
			||||||
WarningsAsErrors: ''
 | 
					 | 
				
			||||||
HeaderFileExtensions: ['', h, hh, hpp, hxx, inc, glsl]
 | 
					 | 
				
			||||||
ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
 | 
					ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
 | 
				
			||||||
HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
 | 
					HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
 | 
				
			||||||
FormatStyle: file
 | 
					FormatStyle: file
 | 
				
			||||||
| 
						 | 
					@ -19,4 +17,3 @@ CheckOptions:
 | 
				
			||||||
  modernize-use-bool-literals.IgnoreMacros: false
 | 
					  modernize-use-bool-literals.IgnoreMacros: false
 | 
				
			||||||
  modernize-use-default-member-init.IgnoreMacros: false
 | 
					  modernize-use-default-member-init.IgnoreMacros: false
 | 
				
			||||||
  modernize-use-default-member-init.UseAssignment: true
 | 
					  modernize-use-default-member-init.UseAssignment: true
 | 
				
			||||||
...
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								engine/.clangd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								engine/.clangd
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					# https://clangd.llvm.org/config
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					# Default conditions, apply everywhere.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Diagnostics:
 | 
				
			||||||
 | 
					  Includes:
 | 
				
			||||||
 | 
					    IgnoreHeader:
 | 
				
			||||||
 | 
					      - core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere.
 | 
				
			||||||
 | 
					      - \.compat\.inc
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					# Header-specific conditions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If:
 | 
				
			||||||
 | 
					  PathMatch: .*\.(h|hh|hpp|hxx|inc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Exclude certain, noisy warnings that lack full context. Replace with lowered severity if/when
 | 
				
			||||||
 | 
					# clangd gets diagnostic severity support. (See: https://github.com/clangd/clangd/issues/1937)
 | 
				
			||||||
 | 
					CompileFlags:
 | 
				
			||||||
 | 
					  Add:
 | 
				
			||||||
 | 
					    - -Wno-unneeded-internal-declaration
 | 
				
			||||||
 | 
					    - -Wno-unused-const-variable
 | 
				
			||||||
 | 
					    - -Wno-unused-function
 | 
				
			||||||
 | 
					    - -Wno-unused-variable
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					# Suppress all third-party warnings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If:
 | 
				
			||||||
 | 
					  PathMatch: thirdparty/.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Diagnostics:
 | 
				
			||||||
 | 
					  Suppress: "*"
 | 
				
			||||||
| 
						 | 
					@ -3,24 +3,18 @@ root = true
 | 
				
			||||||
[*]
 | 
					[*]
 | 
				
			||||||
charset = utf-8
 | 
					charset = utf-8
 | 
				
			||||||
end_of_line = lf
 | 
					end_of_line = lf
 | 
				
			||||||
 | 
					indent_size = 4
 | 
				
			||||||
indent_style = tab
 | 
					indent_style = tab
 | 
				
			||||||
insert_final_newline = true
 | 
					insert_final_newline = true
 | 
				
			||||||
 | 
					max_line_length = 120
 | 
				
			||||||
[*.{cpp,hpp,c,h,mm}]
 | 
					 | 
				
			||||||
trim_trailing_whitespace = true
 | 
					trim_trailing_whitespace = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[{*.gradle,AndroidManifest.xml}]
 | 
					 | 
				
			||||||
indent_style = space
 | 
					 | 
				
			||||||
indent_size = 4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[{*.py,SConstruct,SCsub}]
 | 
					[{*.py,SConstruct,SCsub}]
 | 
				
			||||||
indent_style = space
 | 
					indent_style = space
 | 
				
			||||||
indent_size = 4
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# YAML requires indentation with spaces instead of tabs.
 | 
					[{*.{yml,yaml},.clang{-format,-tidy,d}}]
 | 
				
			||||||
[*.{yml,yaml}]
 | 
					 | 
				
			||||||
indent_style = space
 | 
					 | 
				
			||||||
indent_size = 2
 | 
					indent_size = 2
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[*.svg]
 | 
					[*.svg]
 | 
				
			||||||
insert_final_newline = false
 | 
					insert_final_newline = false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,3 +54,15 @@ df61dc4b2bd54a5a40c515493c76f5a458e5b541
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Enforce template syntax `typename` over `class`
 | 
					# Enforce template syntax `typename` over `class`
 | 
				
			||||||
9903e6779b70fc03aae70a37b9cf053f4f355b91
 | 
					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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								engine/.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								engine/.gitattributes
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# Properly detect languages on Github
 | 
					# Properly detect languages on Github
 | 
				
			||||||
*.h linguist-language=cpp
 | 
					*.h linguist-language=C++
 | 
				
			||||||
*.inc linguist-language=cpp
 | 
					*.inc linguist-language=C++
 | 
				
			||||||
thirdparty/* linguist-vendored
 | 
					thirdparty/* linguist-vendored
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Normalize EOL for all files that Git considers text files
 | 
					# Normalize EOL for all files that Git considers text files
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -36,8 +36,8 @@ compile_commands.json
 | 
				
			||||||
platform/windows/godot_res.res
 | 
					platform/windows/godot_res.res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Ninja build files
 | 
					# Ninja build files
 | 
				
			||||||
build.ninja
 | 
					*.ninja
 | 
				
			||||||
.ninja
 | 
					.ninja/
 | 
				
			||||||
run_ninja_env.bat
 | 
					run_ninja_env.bat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Generated by Godot binary
 | 
					# Generated by Godot binary
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,9 @@ venv
 | 
				
			||||||
__pycache__/
 | 
					__pycache__/
 | 
				
			||||||
*.pyc
 | 
					*.pyc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python modules
 | 
				
			||||||
 | 
					.*_cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Documentation
 | 
					# Documentation
 | 
				
			||||||
doc/_build/
 | 
					doc/_build/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,9 +167,6 @@ gmon.out
 | 
				
			||||||
# Kdevelop
 | 
					# Kdevelop
 | 
				
			||||||
*.kdev4
 | 
					*.kdev4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Mypy
 | 
					 | 
				
			||||||
.mypy_cache
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Qt Creator
 | 
					# Qt Creator
 | 
				
			||||||
*.config
 | 
					*.config
 | 
				
			||||||
*.creator
 | 
					*.creator
 | 
				
			||||||
| 
						 | 
					@ -216,6 +216,7 @@ xcuserdata/
 | 
				
			||||||
*.xcscmblueprint
 | 
					*.xcscmblueprint
 | 
				
			||||||
*.xccheckout
 | 
					*.xccheckout
 | 
				
			||||||
*.xcodeproj/*
 | 
					*.xcodeproj/*
 | 
				
			||||||
 | 
					!misc/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##############################
 | 
					##############################
 | 
				
			||||||
### Visual Studio specific ###
 | 
					### Visual Studio specific ###
 | 
				
			||||||
| 
						 | 
					@ -362,6 +363,7 @@ cpp.hint
 | 
				
			||||||
# macOS
 | 
					# macOS
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
__MACOSX
 | 
					__MACOSX
 | 
				
			||||||
 | 
					Godot.app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Windows
 | 
					# Windows
 | 
				
			||||||
# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
 | 
					# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,7 @@ Jean-Michel Bernard <jmb462@gmail.com>
 | 
				
			||||||
Jérôme Gully <jerome.gully0@gmail.com>
 | 
					Jérôme Gully <jerome.gully0@gmail.com>
 | 
				
			||||||
JFonS <joan.fonssanchez@gmail.com>
 | 
					JFonS <joan.fonssanchez@gmail.com>
 | 
				
			||||||
jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
 | 
					jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
 | 
				
			||||||
 | 
					Johan Aires Rastén <johan@oljud.se>
 | 
				
			||||||
Juan Linietsky <reduzio@gmail.com>
 | 
					Juan Linietsky <reduzio@gmail.com>
 | 
				
			||||||
Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
 | 
					Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
 | 
				
			||||||
Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
 | 
					Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
 | 
				
			||||||
| 
						 | 
					@ -97,6 +98,7 @@ karroffel <therzog@mail.de> <thomas.herzog@simedis.com>
 | 
				
			||||||
Kelly Thomas <kelly.thomas@hotmail.com.au>
 | 
					Kelly Thomas <kelly.thomas@hotmail.com.au>
 | 
				
			||||||
Kongfa Waroros <gongpha@hotmail.com>
 | 
					Kongfa Waroros <gongpha@hotmail.com>
 | 
				
			||||||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.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>
 | 
					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> <eska@eska.me>
 | 
				
			||||||
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
 | 
					Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
 | 
				
			||||||
| 
						 | 
					@ -142,6 +144,7 @@ Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
 | 
				
			||||||
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
 | 
					Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
 | 
				
			||||||
Poommetee Ketson <poommetee@protonmail.com>
 | 
					Poommetee Ketson <poommetee@protonmail.com>
 | 
				
			||||||
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.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>
 | 
				
			||||||
Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.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@posteo.de>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,21 +4,25 @@ default_language_version:
 | 
				
			||||||
exclude: |
 | 
					exclude: |
 | 
				
			||||||
  (?x)^(
 | 
					  (?x)^(
 | 
				
			||||||
    .*thirdparty/.*|
 | 
					    .*thirdparty/.*|
 | 
				
			||||||
    .*-so_wrap\.(h|c)$
 | 
					    .*-so_wrap\.(h|c)|
 | 
				
			||||||
  )
 | 
					    platform/android/java/editor/src/main/java/com/android/.*|
 | 
				
			||||||
 | 
					    platform/android/java/lib/src/com/google/.*
 | 
				
			||||||
 | 
					  )$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repos:
 | 
					repos:
 | 
				
			||||||
  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
					  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
				
			||||||
    rev: v17.0.6
 | 
					    rev: v19.1.3
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: clang-format
 | 
					      - id: clang-format
 | 
				
			||||||
        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
 | 
				
			||||||
        types_or: [text]
 | 
					        types_or: [text]
 | 
				
			||||||
        exclude: |
 | 
					        exclude: ^tests/python_build/.*
 | 
				
			||||||
          (?x)^(
 | 
					      - id: clang-format
 | 
				
			||||||
            tests/python_build/.*|
 | 
					        name: clang-format-glsl
 | 
				
			||||||
            platform/android/java/lib/src/com/.*
 | 
					        files: \.glsl$
 | 
				
			||||||
          )
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					        exclude: ^tests/python_build/.*
 | 
				
			||||||
 | 
					        args: [-style=file:misc/utility/clang_format_glsl.yml]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - repo: https://github.com/pocc/pre-commit-hooks
 | 
					  - repo: https://github.com/pocc/pre-commit-hooks
 | 
				
			||||||
    rev: v1.3.5
 | 
					    rev: v1.3.5
 | 
				
			||||||
| 
						 | 
					@ -27,24 +31,24 @@ repos:
 | 
				
			||||||
        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
 | 
				
			||||||
        args: [--fix, --quiet, --use-color]
 | 
					        args: [--fix, --quiet, --use-color]
 | 
				
			||||||
        types_or: [text]
 | 
					        types_or: [text]
 | 
				
			||||||
        exclude: |
 | 
					        exclude: ^tests/python_build/.*
 | 
				
			||||||
          (?x)^(
 | 
					        additional_dependencies: [clang-tidy==19.1.0]
 | 
				
			||||||
            tests/python_build/.*|
 | 
					 | 
				
			||||||
            platform/android/java/lib/src/com/.*
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        additional_dependencies: [clang-tidy==18.1.1]
 | 
					 | 
				
			||||||
        require_serial: true
 | 
					        require_serial: true
 | 
				
			||||||
        stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
 | 
					        stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
					  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
				
			||||||
    rev: v0.4.4
 | 
					    rev: v0.9.4
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: ruff
 | 
					      - id: ruff
 | 
				
			||||||
        args: [--fix]
 | 
					        args: [--fix]
 | 
				
			||||||
 | 
					        files: (\.py|SConstruct|SCsub)$
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
      - id: ruff-format
 | 
					      - id: ruff-format
 | 
				
			||||||
 | 
					        files: (\.py|SConstruct|SCsub)$
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - repo: https://github.com/pre-commit/mirrors-mypy
 | 
					  - repo: https://github.com/pre-commit/mirrors-mypy
 | 
				
			||||||
    rev: v0.971
 | 
					    rev: v1.14.1
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: mypy
 | 
					      - id: mypy
 | 
				
			||||||
        files: \.py$
 | 
					        files: \.py$
 | 
				
			||||||
| 
						 | 
					@ -80,7 +84,7 @@ repos:
 | 
				
			||||||
        name: doc-status
 | 
					        name: doc-status
 | 
				
			||||||
        language: python
 | 
					        language: python
 | 
				
			||||||
        entry: python doc/tools/doc_status.py
 | 
					        entry: python doc/tools/doc_status.py
 | 
				
			||||||
        args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes]
 | 
					        args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
 | 
				
			||||||
        pass_filenames: false
 | 
					        pass_filenames: false
 | 
				
			||||||
        files: ^(doc/classes|.*/doc_classes)/.*\.xml$
 | 
					        files: ^(doc/classes|.*/doc_classes)/.*\.xml$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,16 +93,21 @@ repos:
 | 
				
			||||||
        language: node
 | 
					        language: node
 | 
				
			||||||
        entry: eslint
 | 
					        entry: eslint
 | 
				
			||||||
        files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
 | 
					        files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
 | 
				
			||||||
        args: [--fix, --no-warn-ignored, --no-config-lookup, --config, platform/web/eslint.config.cjs]
 | 
					        args:
 | 
				
			||||||
 | 
					          - --fix
 | 
				
			||||||
 | 
					          - --no-warn-ignored
 | 
				
			||||||
 | 
					          - --no-config-lookup
 | 
				
			||||||
 | 
					          - --config
 | 
				
			||||||
 | 
					          - platform/web/eslint.config.cjs
 | 
				
			||||||
        additional_dependencies:
 | 
					        additional_dependencies:
 | 
				
			||||||
          - '@eslint/js@^9.3.0'
 | 
					          - "@eslint/js@^9.3.0"
 | 
				
			||||||
          - '@html-eslint/eslint-plugin@^0.24.1'
 | 
					          - "@html-eslint/eslint-plugin@^0.24.1"
 | 
				
			||||||
          - '@html-eslint/parser@^0.24.1'
 | 
					          - "@html-eslint/parser@^0.24.1"
 | 
				
			||||||
          - '@stylistic/eslint-plugin@^2.1.0'
 | 
					          - "@stylistic/eslint-plugin@^2.1.0"
 | 
				
			||||||
          - 'eslint@^9.3.0'
 | 
					          - eslint@^9.3.0
 | 
				
			||||||
          - 'eslint-plugin-html@^8.1.1'
 | 
					          - eslint-plugin-html@^8.1.1
 | 
				
			||||||
          - 'globals@^15.3.0'
 | 
					          - globals@^15.3.0
 | 
				
			||||||
          - 'espree@^10.0.1'
 | 
					          - espree@^10.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: jsdoc
 | 
					      - id: jsdoc
 | 
				
			||||||
        name: jsdoc
 | 
					        name: jsdoc
 | 
				
			||||||
| 
						 | 
					@ -112,11 +121,11 @@ repos:
 | 
				
			||||||
          - platform/web/js/engine/config.js
 | 
					          - platform/web/js/engine/config.js
 | 
				
			||||||
          - platform/web/js/engine/features.js
 | 
					          - platform/web/js/engine/features.js
 | 
				
			||||||
          - --destination
 | 
					          - --destination
 | 
				
			||||||
          - ''
 | 
					          - ""
 | 
				
			||||||
          - -d
 | 
					          - -d
 | 
				
			||||||
          - dry-run
 | 
					          - dry-run
 | 
				
			||||||
        pass_filenames: false
 | 
					        pass_filenames: false
 | 
				
			||||||
        additional_dependencies: ['jsdoc@^4.0.3']
 | 
					        additional_dependencies: [jsdoc@^4.0.3]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: svgo
 | 
					      - id: svgo
 | 
				
			||||||
        name: svgo
 | 
					        name: svgo
 | 
				
			||||||
| 
						 | 
					@ -124,7 +133,7 @@ repos:
 | 
				
			||||||
        entry: svgo
 | 
					        entry: svgo
 | 
				
			||||||
        files: \.svg$
 | 
					        files: \.svg$
 | 
				
			||||||
        args: [--quiet, --config, misc/utility/svgo.config.mjs]
 | 
					        args: [--quiet, --config, misc/utility/svgo.config.mjs]
 | 
				
			||||||
        additional_dependencies: ["svgo@3.3.2"]
 | 
					        additional_dependencies: [svgo@3.3.2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: copyright-headers
 | 
					      - id: copyright-headers
 | 
				
			||||||
        name: copyright-headers
 | 
					        name: copyright-headers
 | 
				
			||||||
| 
						 | 
					@ -133,20 +142,19 @@ repos:
 | 
				
			||||||
        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
 | 
				
			||||||
        exclude: |
 | 
					        exclude: |
 | 
				
			||||||
          (?x)^(
 | 
					          (?x)^(
 | 
				
			||||||
            core/math/bvh_.*\.inc$|
 | 
					            core/math/bvh_.*\.inc|
 | 
				
			||||||
            platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
 | 
					            platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
 | 
				
			||||||
            platform/android/java/lib/src/com/.*|
 | 
					            platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java|
 | 
				
			||||||
            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/gl/EGLLogWrapper\.java$|
 | 
					            platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java
 | 
				
			||||||
            platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java$
 | 
					          )$
 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: header-guards
 | 
					      - id: header-guards
 | 
				
			||||||
        name: header-guards
 | 
					        name: header-guards
 | 
				
			||||||
        language: python
 | 
					        language: python
 | 
				
			||||||
        entry: python misc/scripts/header_guards.py
 | 
					        entry: python misc/scripts/header_guards.py
 | 
				
			||||||
        files: \.(h|hpp|hh|hxx)$
 | 
					        files: \.(h|hpp|hh|hxx)$
 | 
				
			||||||
        exclude: ^.*/(thread|platform_config|platform_gl)\.h$
 | 
					        exclude: ^.*/(dummy|thread|platform_config|platform_gl)\.h$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: file-format
 | 
					      - id: file-format
 | 
				
			||||||
        name: file-format
 | 
					        name: file-format
 | 
				
			||||||
| 
						 | 
					@ -155,22 +163,22 @@ repos:
 | 
				
			||||||
        types_or: [text]
 | 
					        types_or: [text]
 | 
				
			||||||
        exclude: |
 | 
					        exclude: |
 | 
				
			||||||
          (?x)^(
 | 
					          (?x)^(
 | 
				
			||||||
            .*\.test\.txt$|
 | 
					            .*\.test\.txt|
 | 
				
			||||||
            .*\.svg$|
 | 
					            .*\.svg|
 | 
				
			||||||
            .*\.patch$|
 | 
					            .*\.patch|
 | 
				
			||||||
            .*\.out$|
 | 
					            .*\.out|
 | 
				
			||||||
            modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd$|
 | 
					            modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd|
 | 
				
			||||||
            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
 | 
					            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.norun\.gd|
 | 
				
			||||||
            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
 | 
					            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.norun\.gd|
 | 
				
			||||||
            platform/android/java/lib/src/com/google/.*
 | 
					            tests/data/.*\.bin
 | 
				
			||||||
          )
 | 
					          )$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - id: dotnet-format
 | 
					      - id: dotnet-format
 | 
				
			||||||
        name: dotnet-format
 | 
					        name: dotnet-format
 | 
				
			||||||
        language: python
 | 
					        language: python
 | 
				
			||||||
        entry: python misc/scripts/dotnet_format.py
 | 
					        entry: python misc/scripts/dotnet_format.py
 | 
				
			||||||
        types_or: [c#]
 | 
					        types_or: [c#]
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# End of upstream Godot pre-commit hooks.
 | 
					# End of upstream Godot pre-commit hooks.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Keep this separation to let downstream forks add their own hooks to this file,
 | 
					# Keep this separation to let downstream forks add their own hooks to this file,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,17 @@
 | 
				
			||||||
# Godot Engine authors
 | 
					# Godot Engine authors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Godot Engine is developed by a community of voluntary contributors who
 | 
					Godot Engine is developed by a community of voluntary contributors who
 | 
				
			||||||
contribute code, bug reports, documentation, artwork, support, etc.
 | 
					contribute code, bug reports, documentation, translations, support, etc.,
 | 
				
			||||||
 | 
					across multiple repositories.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
It is impossible to list them all; nevertheless, this file aims at listing
 | 
					It is impossible to list them all; nevertheless, this file aims at listing
 | 
				
			||||||
the developers who contributed significant patches to this MIT licensed
 | 
					the developers who contributed significant improvements to the engine code.
 | 
				
			||||||
source code. "Significant" is arbitrarily decided, but should be fair :)
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					GitHub usernames are indicated in parentheses, or as sole entry when no other
 | 
				
			||||||
name is available.
 | 
					name is available.
 | 
				
			||||||
| 
						 | 
					@ -25,8 +31,6 @@ name is available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Developers
 | 
					## Developers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(in alphabetical order, with over 10 commits excluding merges)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Aaron Franke (aaronfranke)
 | 
					    Aaron Franke (aaronfranke)
 | 
				
			||||||
    Aaron Pagano (aaronp64)
 | 
					    Aaron Pagano (aaronp64)
 | 
				
			||||||
    Aaron Record (LightningAA)
 | 
					    Aaron Record (LightningAA)
 | 
				
			||||||
| 
						 | 
					@ -38,6 +42,7 @@ name is available.
 | 
				
			||||||
    Alfred Reinold Baudisch (alfredbaudisch)
 | 
					    Alfred Reinold Baudisch (alfredbaudisch)
 | 
				
			||||||
    Alistair Leslie-Hughes (alesliehughes)
 | 
					    Alistair Leslie-Hughes (alesliehughes)
 | 
				
			||||||
    Alket Rexhepi (alketii)
 | 
					    Alket Rexhepi (alketii)
 | 
				
			||||||
 | 
					    Alvin Wong (alvinhochun)
 | 
				
			||||||
    Andrea Catania (AndreaCatania)
 | 
					    Andrea Catania (AndreaCatania)
 | 
				
			||||||
    Andreia Gaita (shana)
 | 
					    Andreia Gaita (shana)
 | 
				
			||||||
    Andrii Doroshenko (Xrayez)
 | 
					    Andrii Doroshenko (Xrayez)
 | 
				
			||||||
| 
						 | 
					@ -46,11 +51,13 @@ name is available.
 | 
				
			||||||
    Angad Kambli (angad-k)
 | 
					    Angad Kambli (angad-k)
 | 
				
			||||||
    Anilforextra (AnilBK)
 | 
					    Anilforextra (AnilBK)
 | 
				
			||||||
    Anish Bhobe (KidRigger)
 | 
					    Anish Bhobe (KidRigger)
 | 
				
			||||||
 | 
					    Anni Ryynänen (anniryynanen)
 | 
				
			||||||
    Anton Yabchinskiy (a12n)
 | 
					    Anton Yabchinskiy (a12n)
 | 
				
			||||||
    Anutrix
 | 
					    Anutrix
 | 
				
			||||||
    Aren Villanueva (kurikaesu)
 | 
					    Aren Villanueva (kurikaesu)
 | 
				
			||||||
    Ariel Manzur (punto-)
 | 
					    Ariel Manzur (punto-)
 | 
				
			||||||
    Arman Elgudzhyan (puchik)
 | 
					    Arman Elgudzhyan (puchik)
 | 
				
			||||||
 | 
					    Arseny Kapoulkine (zeux)
 | 
				
			||||||
    AThousandShips
 | 
					    AThousandShips
 | 
				
			||||||
    aXu-AP
 | 
					    aXu-AP
 | 
				
			||||||
    Bartłomiej T. Listwon (Listwon)
 | 
					    Bartłomiej T. Listwon (Listwon)
 | 
				
			||||||
| 
						 | 
					@ -72,6 +79,7 @@ name is available.
 | 
				
			||||||
    Carter Anderson (cart)
 | 
					    Carter Anderson (cart)
 | 
				
			||||||
    ChibiDenDen
 | 
					    ChibiDenDen
 | 
				
			||||||
    Chris Bradfield (cbscribe)
 | 
					    Chris Bradfield (cbscribe)
 | 
				
			||||||
 | 
					    Chris Cranford (Naros)
 | 
				
			||||||
    Christian Kaiser (ckaiser)
 | 
					    Christian Kaiser (ckaiser)
 | 
				
			||||||
    Clay John (clayjohn)
 | 
					    Clay John (clayjohn)
 | 
				
			||||||
    ConteZero
 | 
					    ConteZero
 | 
				
			||||||
| 
						 | 
					@ -86,7 +94,9 @@ name is available.
 | 
				
			||||||
    David Cambré (Gallilus)
 | 
					    David Cambré (Gallilus)
 | 
				
			||||||
    David Sichma (DavidSichma)
 | 
					    David Sichma (DavidSichma)
 | 
				
			||||||
    David Snopek (dsnopek)
 | 
					    David Snopek (dsnopek)
 | 
				
			||||||
 | 
					    derammo
 | 
				
			||||||
    Dharkael (lupoDharkael)
 | 
					    Dharkael (lupoDharkael)
 | 
				
			||||||
 | 
					    Dirk Steinmetz (rsjtdrjgfuzkfg)
 | 
				
			||||||
    Dmitry Koteroff (Krakean)
 | 
					    Dmitry Koteroff (Krakean)
 | 
				
			||||||
    Dmitry Maganov (vonagam)
 | 
					    Dmitry Maganov (vonagam)
 | 
				
			||||||
    Dominik Jasiński (dreamsComeTrue)
 | 
					    Dominik Jasiński (dreamsComeTrue)
 | 
				
			||||||
| 
						 | 
					@ -117,6 +127,7 @@ name is available.
 | 
				
			||||||
    Geequlim
 | 
					    Geequlim
 | 
				
			||||||
    George Marques (vnen)
 | 
					    George Marques (vnen)
 | 
				
			||||||
    Gerrit Großkopf (Grosskopf)
 | 
					    Gerrit Großkopf (Grosskopf)
 | 
				
			||||||
 | 
					    Giganzo
 | 
				
			||||||
    Gilles Roudiere (groud)
 | 
					    Gilles Roudiere (groud)
 | 
				
			||||||
    Gordon MacPherson (RevoluPowered)
 | 
					    Gordon MacPherson (RevoluPowered)
 | 
				
			||||||
    Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
 | 
					    Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
 | 
				
			||||||
| 
						 | 
					@ -126,7 +137,6 @@ name is available.
 | 
				
			||||||
    Hein-Pieter van Braam-Stewart (hpvb)
 | 
					    Hein-Pieter van Braam-Stewart (hpvb)
 | 
				
			||||||
    Hendrik Brucker (Geometror)
 | 
					    Hendrik Brucker (Geometror)
 | 
				
			||||||
    Hilderin
 | 
					    Hilderin
 | 
				
			||||||
    hilfazer
 | 
					 | 
				
			||||||
    Hiroshi Ogawa (hi-ogawa)
 | 
					    Hiroshi Ogawa (hi-ogawa)
 | 
				
			||||||
    HolonProduction
 | 
					    HolonProduction
 | 
				
			||||||
    homer666
 | 
					    homer666
 | 
				
			||||||
| 
						 | 
					@ -151,6 +161,7 @@ name is available.
 | 
				
			||||||
    Jia Jun Chai (SkyLucilfer)
 | 
					    Jia Jun Chai (SkyLucilfer)
 | 
				
			||||||
    jitspoe
 | 
					    jitspoe
 | 
				
			||||||
    Joan Fons Sanchez (JFonS)
 | 
					    Joan Fons Sanchez (JFonS)
 | 
				
			||||||
 | 
					    Johan Aires Rastén (JohanAR)
 | 
				
			||||||
    Johan Manuel (29jm)
 | 
					    Johan Manuel (29jm)
 | 
				
			||||||
    Johannes Witt (HaSa1002)
 | 
					    Johannes Witt (HaSa1002)
 | 
				
			||||||
    Jonathan Nicholl (jtnicholl)
 | 
					    Jonathan Nicholl (jtnicholl)
 | 
				
			||||||
| 
						 | 
					@ -163,11 +174,13 @@ name is available.
 | 
				
			||||||
    Jummit
 | 
					    Jummit
 | 
				
			||||||
    Justo Delgado (mrcdk)
 | 
					    Justo Delgado (mrcdk)
 | 
				
			||||||
    karroffel
 | 
					    karroffel
 | 
				
			||||||
 | 
					    Kassandra Pucher (PucklaJ)
 | 
				
			||||||
    Kelly Thomas (KellyThomas)
 | 
					    Kelly Thomas (KellyThomas)
 | 
				
			||||||
    kleonc
 | 
					    kleonc
 | 
				
			||||||
    Kongfa Waroros (gongpha)
 | 
					    Kongfa Waroros (gongpha)
 | 
				
			||||||
    Kostadin Damyanov (Max-Might)
 | 
					    Kostadin Damyanov (Max-Might)
 | 
				
			||||||
    K. S. Ernest (iFire) Lee (fire)
 | 
					    K. S. Ernest (iFire) Lee (fire)
 | 
				
			||||||
 | 
					    Kyle Eichlin (likeich)
 | 
				
			||||||
    lawnjelly
 | 
					    lawnjelly
 | 
				
			||||||
    Leon Krause (leonkrause)
 | 
					    Leon Krause (leonkrause)
 | 
				
			||||||
    Liz Haas (27thLiz)
 | 
					    Liz Haas (27thLiz)
 | 
				
			||||||
| 
						 | 
					@ -185,6 +198,7 @@ name is available.
 | 
				
			||||||
    Marcus Brummer (mbrlabs)
 | 
					    Marcus Brummer (mbrlabs)
 | 
				
			||||||
    Marcus Elg (MCrafterzz)
 | 
					    Marcus Elg (MCrafterzz)
 | 
				
			||||||
    Mariano Javier Suligoy (MarianoGnu)
 | 
					    Mariano Javier Suligoy (MarianoGnu)
 | 
				
			||||||
 | 
					    Mario Liebisch (MarioLiebisch)
 | 
				
			||||||
    Mario Schlack (hurikhan)
 | 
					    Mario Schlack (hurikhan)
 | 
				
			||||||
    Marios Staikopoulos (marstaik)
 | 
					    Marios Staikopoulos (marstaik)
 | 
				
			||||||
    Marius Hanl (Maran23)
 | 
					    Marius Hanl (Maran23)
 | 
				
			||||||
| 
						 | 
					@ -198,6 +212,7 @@ name is available.
 | 
				
			||||||
    Masoud BH (masoudbh3)
 | 
					    Masoud BH (masoudbh3)
 | 
				
			||||||
    Mateo Kuruk Miccino (kuruk-mm)
 | 
					    Mateo Kuruk Miccino (kuruk-mm)
 | 
				
			||||||
    Matias N. Goldberg (darksylinc)
 | 
					    Matias N. Goldberg (darksylinc)
 | 
				
			||||||
 | 
					    Matthew Murphy (mashumafi)
 | 
				
			||||||
    Matthew (skyace65)
 | 
					    Matthew (skyace65)
 | 
				
			||||||
    Matthias Hölzl (hoelzl)
 | 
					    Matthias Hölzl (hoelzl)
 | 
				
			||||||
    Max Hilbrunner (mhilbrunner)
 | 
					    Max Hilbrunner (mhilbrunner)
 | 
				
			||||||
| 
						 | 
					@ -209,9 +224,10 @@ name is available.
 | 
				
			||||||
    MichiRecRoom (LikeLakers2)
 | 
					    MichiRecRoom (LikeLakers2)
 | 
				
			||||||
    Micky (Mickeon)
 | 
					    Micky (Mickeon)
 | 
				
			||||||
    Mikael Hermansson (mihe)
 | 
					    Mikael Hermansson (mihe)
 | 
				
			||||||
 | 
					    Mika Viskari (miv391)
 | 
				
			||||||
    MinusKube
 | 
					    MinusKube
 | 
				
			||||||
    MJacred
 | 
					    MJacred
 | 
				
			||||||
    Morris "Tabor" Arroad (mortarroad)
 | 
					    Mounir Tohami (WhalesState)
 | 
				
			||||||
    mrezai
 | 
					    mrezai
 | 
				
			||||||
    Muhammad Huri (CakHuri)
 | 
					    Muhammad Huri (CakHuri)
 | 
				
			||||||
    muiroc
 | 
					    muiroc
 | 
				
			||||||
| 
						 | 
					@ -234,6 +250,7 @@ name is available.
 | 
				
			||||||
    Patrick Dawson (pkdawson)
 | 
					    Patrick Dawson (pkdawson)
 | 
				
			||||||
    Patrick Exner (FlameLizard)
 | 
					    Patrick Exner (FlameLizard)
 | 
				
			||||||
    Patrick (firefly2442)
 | 
					    Patrick (firefly2442)
 | 
				
			||||||
 | 
					    patwork
 | 
				
			||||||
    Paul Batty (Paulb23)
 | 
					    Paul Batty (Paulb23)
 | 
				
			||||||
    Paul Joannon (paulloz)
 | 
					    Paul Joannon (paulloz)
 | 
				
			||||||
    Paul Trojahn (ptrojahn)
 | 
					    Paul Trojahn (ptrojahn)
 | 
				
			||||||
| 
						 | 
					@ -245,6 +262,7 @@ name is available.
 | 
				
			||||||
    Pieter-Jan Briers (PJB3005)
 | 
					    Pieter-Jan Briers (PJB3005)
 | 
				
			||||||
    Poommetee Ketson (Noshyaar)
 | 
					    Poommetee Ketson (Noshyaar)
 | 
				
			||||||
    Przemysław Gołąb (n-pigeon)
 | 
					    Przemysław Gołąb (n-pigeon)
 | 
				
			||||||
 | 
					    Radiant (RadiantUwU)
 | 
				
			||||||
    Rafael M. G. (rafallus)
 | 
					    Rafael M. G. (rafallus)
 | 
				
			||||||
    Rafał Mikrut (qarmin)
 | 
					    Rafał Mikrut (qarmin)
 | 
				
			||||||
    Raffaele Picca (RPicster)
 | 
					    Raffaele Picca (RPicster)
 | 
				
			||||||
| 
						 | 
					@ -282,6 +300,7 @@ name is available.
 | 
				
			||||||
    Stanislav Labzyuk (DarkMessiah)
 | 
					    Stanislav Labzyuk (DarkMessiah)
 | 
				
			||||||
    Stijn Hinlopen (hinlopen)
 | 
					    Stijn Hinlopen (hinlopen)
 | 
				
			||||||
    stmSi
 | 
					    stmSi
 | 
				
			||||||
 | 
					    Stuart Carnie (stuartcarnie)
 | 
				
			||||||
    Swarnim Arun (minraws)
 | 
					    Swarnim Arun (minraws)
 | 
				
			||||||
    TC (floppyhammer)
 | 
					    TC (floppyhammer)
 | 
				
			||||||
    TechnoPorg
 | 
					    TechnoPorg
 | 
				
			||||||
| 
						 | 
					@ -289,6 +308,7 @@ name is available.
 | 
				
			||||||
    Thakee Nathees (ThakeeNathees)
 | 
					    Thakee Nathees (ThakeeNathees)
 | 
				
			||||||
    thebestnom
 | 
					    thebestnom
 | 
				
			||||||
    Theo Hallenius (TheoXD)
 | 
					    Theo Hallenius (TheoXD)
 | 
				
			||||||
 | 
					    Thomas ten Cate (ttencate)
 | 
				
			||||||
    Timo Schwarzer (timoschwarzer)
 | 
					    Timo Schwarzer (timoschwarzer)
 | 
				
			||||||
    Timothé Bonhoure (ajreckof)
 | 
					    Timothé Bonhoure (ajreckof)
 | 
				
			||||||
    Timo (toger5)
 | 
					    Timo (toger5)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,42 +1,40 @@
 | 
				
			||||||
# Exhaustive licensing information for files in the Godot Engine repository
 | 
					 | 
				
			||||||
# =========================================================================
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This file aims at documenting the copyright and license for every source
 | 
					 | 
				
			||||||
# file in the Godot Engine repository, and especially outline the files
 | 
					 | 
				
			||||||
# whose license differs from the MIT/Expat license used by Godot Engine.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# It is written as a machine-readable format following the debian/copyright
 | 
					 | 
				
			||||||
# specification. Globbing patterns (e.g. "Files: *") mean that they affect
 | 
					 | 
				
			||||||
# all corresponding files (also recursively in subfolders), apart from those
 | 
					 | 
				
			||||||
# with a more explicit copyright statement.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Licenses are given with their debian/copyright short name (or SPDX identifier
 | 
					 | 
				
			||||||
# if no standard short name exists) and are all included in plain text at the
 | 
					 | 
				
			||||||
# end of this file (in alphabetical order).
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Disclaimer for thirdparty libraries:
 | 
					 | 
				
			||||||
# ------------------------------------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Licensing details for thirdparty libraries in the 'thirdparty/' directory
 | 
					 | 
				
			||||||
# are given in summarized form, i.e. with only the "main" license described
 | 
					 | 
				
			||||||
# in the library's license statement. Different licenses of single files or
 | 
					 | 
				
			||||||
# code snippets in thirdparty libraries are not documented here.
 | 
					 | 
				
			||||||
# For example:
 | 
					 | 
				
			||||||
#   Files: ./thirdparty/zlib/
 | 
					 | 
				
			||||||
#   Copyright: 1995-2017, Jean-loup Gailly and Mark Adler
 | 
					 | 
				
			||||||
#   License: Zlib
 | 
					 | 
				
			||||||
# The exact copyright for each file in that library *may* differ, and some
 | 
					 | 
				
			||||||
# files or code snippets might be distributed under other compatible licenses
 | 
					 | 
				
			||||||
# (e.g. a public domain dedication), but as far as Godot Engine is concerned
 | 
					 | 
				
			||||||
# the library is considered as a whole under the Zlib license.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Note: When linking dynamically against thirdparty libraries instead of
 | 
					 | 
				
			||||||
# building them into the Godot binary, you may remove the corresponding
 | 
					 | 
				
			||||||
# license details from this file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
-----------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
					Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
				
			||||||
 | 
					Comment:
 | 
				
			||||||
 | 
					 Exhaustive licensing information for files in the Godot Engine repository
 | 
				
			||||||
 | 
					 =========================================================================
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 This file aims at documenting the copyright and license for every source
 | 
				
			||||||
 | 
					 file in the Godot Engine repository, and especially outline the files
 | 
				
			||||||
 | 
					 whose license differs from the MIT/Expat license used by Godot Engine.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 It is written as a machine-readable format following the debian/copyright
 | 
				
			||||||
 | 
					 specification. Globbing patterns (e.g. "Files: *") mean that they affect
 | 
				
			||||||
 | 
					 all corresponding files (also recursively in subfolders), apart from those
 | 
				
			||||||
 | 
					 with a more explicit copyright statement.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 Licenses are given with their debian/copyright short name (or SPDX identifier
 | 
				
			||||||
 | 
					 if no standard short name exists) and are all included in plain text at the
 | 
				
			||||||
 | 
					 end of this file (in alphabetical order).
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 Disclaimer for thirdparty libraries:
 | 
				
			||||||
 | 
					 ------------------------------------
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 Licensing details for thirdparty libraries in the 'thirdparty/' directory
 | 
				
			||||||
 | 
					 are given in summarized form, i.e. with only the "main" license described
 | 
				
			||||||
 | 
					 in the library's license statement. Different licenses of single files or
 | 
				
			||||||
 | 
					 code snippets in thirdparty libraries are not documented here.
 | 
				
			||||||
 | 
					 For example:
 | 
				
			||||||
 | 
					   Files: thirdparty/zlib/*
 | 
				
			||||||
 | 
					   Copyright: 1995-2017, Jean-loup Gailly and Mark Adler
 | 
				
			||||||
 | 
					   License: Zlib
 | 
				
			||||||
 | 
					 The exact copyright for each file in that library *may* differ, and some
 | 
				
			||||||
 | 
					 files or code snippets might be distributed under other compatible licenses
 | 
				
			||||||
 | 
					 (e.g. a public domain dedication), but as far as Godot Engine is concerned
 | 
				
			||||||
 | 
					 the library is considered as a whole under the Zlib license.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 Note: When linking dynamically against thirdparty libraries instead of
 | 
				
			||||||
 | 
					 building them into the Godot binary, you may remove the corresponding
 | 
				
			||||||
 | 
					 license details from this file.
 | 
				
			||||||
Upstream-Name: Godot Engine
 | 
					Upstream-Name: Godot Engine
 | 
				
			||||||
Upstream-Contact: Rémi Verschelde <contact@godotengine.org>
 | 
					Upstream-Contact: Rémi Verschelde <contact@godotengine.org>
 | 
				
			||||||
Source: https://github.com/godotengine/godot
 | 
					Source: https://github.com/godotengine/godot
 | 
				
			||||||
| 
						 | 
					@ -47,222 +45,244 @@ Copyright: 2014-present, Godot Engine contributors
 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./icon.png
 | 
					Files: icon.png
 | 
				
			||||||
 ./icon.svg
 | 
					 icon.svg
 | 
				
			||||||
 ./logo.png
 | 
					 logo.png
 | 
				
			||||||
 ./logo.svg
 | 
					 logo.svg
 | 
				
			||||||
Comment: Godot Engine logo
 | 
					Comment: Godot Engine logo
 | 
				
			||||||
Copyright: 2017, Andrea Calabró
 | 
					Copyright: 2017, Andrea Calabró
 | 
				
			||||||
License: CC-BY-4.0
 | 
					License: CC-BY-4.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./core/math/convex_hull.cpp
 | 
					Files: core/math/convex_hull.cpp
 | 
				
			||||||
 ./core/math/convex_hull.h
 | 
					 core/math/convex_hull.h
 | 
				
			||||||
Comment: Bullet Continuous Collision Detection and Physics Library
 | 
					Comment: Bullet Continuous Collision Detection and Physics Library
 | 
				
			||||||
Copyright: 2011, Ole Kniemeyer, MAXON, www.maxon.net
 | 
					Copyright: 2011, Ole Kniemeyer, MAXON, www.maxon.net
 | 
				
			||||||
 2014-present, Godot Engine contributors
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
License: Expat and Zlib
 | 
					License: Expat and Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./modules/lightmapper_rd/lm_compute.glsl
 | 
					Files: modules/betsy/alpha_stitch.glsl
 | 
				
			||||||
Comment: Joint Non-Local Means (JNLM) denoiser
 | 
					 modules/betsy/bc1.glsl
 | 
				
			||||||
Copyright: 2020, Manuel Prandini
 | 
					 modules/betsy/bc4.glsl
 | 
				
			||||||
 2014-present, Godot Engine contributors
 | 
					 modules/betsy/bc6h.glsl
 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 modules/betsy/CrossPlatformSettings_piece_all.glsl
 | 
				
			||||||
 | 
					Comment: Betsy
 | 
				
			||||||
 | 
					Copyright: 2020-2022, Matias N. Goldberg
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./platform/android/java/lib/aidl/com/android/*
 | 
					Files: modules/godot_physics_2d/godot_joints_2d.cpp
 | 
				
			||||||
 ./platform/android/java/lib/res/layout/status_bar_ongoing_event_progress_bar.xml
 | 
					 | 
				
			||||||
 ./platform/android/java/lib/src/com/google/android/*
 | 
					 | 
				
			||||||
 ./platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java
 | 
					 | 
				
			||||||
 ./platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java
 | 
					 | 
				
			||||||
Comment: The Android Open Source Project
 | 
					 | 
				
			||||||
Copyright: 2008-2016, The Android Open Source Project
 | 
					 | 
				
			||||||
 2002, Google, Inc.
 | 
					 | 
				
			||||||
License: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java
 | 
					 | 
				
			||||||
Comment: ProcessPhoenix
 | 
					 | 
				
			||||||
Copyright: 2015, Jake Wharton
 | 
					 | 
				
			||||||
License: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./scene/animation/easing_equations.h
 | 
					 | 
				
			||||||
Comment: Robert Penner's Easing Functions
 | 
					 | 
				
			||||||
Copyright: 2001, Robert Penner
 | 
					 | 
				
			||||||
 2014-present, Godot Engine contributors
 | 
					 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 | 
				
			||||||
License: Expat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./servers/physics_2d/godot_joints_2d.cpp
 | 
					 | 
				
			||||||
Comment: Chipmunk2D Joint Constraints
 | 
					Comment: Chipmunk2D Joint Constraints
 | 
				
			||||||
Copyright: 2007, Scott Lembcke
 | 
					Copyright: 2007, Scott Lembcke
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./servers/physics_3d/collision_solver_3d_sat.cpp
 | 
					Files: modules/godot_physics_3d/gjk_epa.cpp
 | 
				
			||||||
Comment: Open Dynamics Engine
 | 
					 modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.cpp
 | 
				
			||||||
Copyright: 2001-2003, Russell L. Smith, Alen Ladavac, Nguyen Binh
 | 
					 modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.h
 | 
				
			||||||
License: BSD-3-clause
 | 
					 modules/godot_physics_3d/joints/godot_hinge_joint_3d.cpp
 | 
				
			||||||
 | 
					 modules/godot_physics_3d/joints/godot_hinge_joint_3d_sw.h
 | 
				
			||||||
Files: ./servers/physics_3d/gjk_epa.cpp
 | 
					 modules/godot_physics_3d/joints/godot_jacobian_entry_3d_sw.h
 | 
				
			||||||
 ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
 | 
					 modules/godot_physics_3d/joints/godot_pin_joint_3d.cpp
 | 
				
			||||||
 ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
 | 
					 modules/godot_physics_3d/joints/godot_pin_joint_3d.h
 | 
				
			||||||
 ./servers/physics_3d/joints/hinge_joint_3d_sw.cpp
 | 
					 modules/godot_physics_3d/joints/godot_slider_joint_3d.cpp
 | 
				
			||||||
 ./servers/physics_3d/joints/hinge_joint_3d_sw.h
 | 
					 modules/godot_physics_3d/joints/godot_slider_joint_3d.h
 | 
				
			||||||
 ./servers/physics_3d/joints/jacobian_entry_3d_sw.h
 | 
					 modules/godot_physics_3d/godot_soft_body_3d.cpp
 | 
				
			||||||
 ./servers/physics_3d/joints/pin_joint_3d_sw.cpp
 | 
					 modules/godot_physics_3d/godot_soft_body_3d.h
 | 
				
			||||||
 ./servers/physics_3d/joints/pin_joint_3d_sw.h
 | 
					 modules/godot_physics_3d/godot_shape_3d.cpp
 | 
				
			||||||
 ./servers/physics_3d/joints/slider_joint_3d_sw.cpp
 | 
					 modules/godot_physics_3d/godot_shape_3d.h
 | 
				
			||||||
 ./servers/physics_3d/joints/slider_joint_3d_sw.h
 | 
					 | 
				
			||||||
 ./servers/physics_3d/soft_body_3d_sw.cpp
 | 
					 | 
				
			||||||
 ./servers/physics_3d/soft_body_3d_sw.h
 | 
					 | 
				
			||||||
 ./servers/physics_3d/shape_3d_sw.cpp
 | 
					 | 
				
			||||||
 ./servers/physics_3d/shape_3d_sw.h
 | 
					 | 
				
			||||||
Comment: Bullet Continuous Collision Detection and Physics Library
 | 
					Comment: Bullet Continuous Collision Detection and Physics Library
 | 
				
			||||||
Copyright: 2003-2008, Erwin Coumans
 | 
					Copyright: 2003-2008, Erwin Coumans
 | 
				
			||||||
 2014-present, Godot Engine contributors
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
License: Expat and Zlib
 | 
					License: Expat and Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
 | 
					Files: modules/godot_physics_3d/godot_collision_solver_3d_sat.cpp
 | 
				
			||||||
 ./servers/physics_3d/joints/cone_twist_joint_3d_sw.h
 | 
					Comment: Open Dynamics Engine
 | 
				
			||||||
 | 
					Copyright: 2001-2003, Russell L. Smith, Alen Ladavac, Nguyen Binh
 | 
				
			||||||
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.cpp
 | 
				
			||||||
 | 
					 modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.h
 | 
				
			||||||
Comment: Bullet Continuous Collision Detection and Physics Library
 | 
					Comment: Bullet Continuous Collision Detection and Physics Library
 | 
				
			||||||
Copyright: 2007, Starbreeze Studios
 | 
					Copyright: 2007, Starbreeze Studios
 | 
				
			||||||
 2014-present, Godot Engine contributors
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 2007-2014, Juan Linietsky, Ariel Manzur
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
License: Expat and Zlib
 | 
					License: Expat and Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl
 | 
					Files: modules/jolt_physics/spaces/jolt_temp_allocator.cpp
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssao_blur.glsl
 | 
					Comment: Jolt Physics
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
 | 
					Copyright: 2021, Jorrit Rouwe
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssao.glsl
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssil_blur.glsl
 | 
					License: Expat
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl
 | 
					
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssil_interleave.glsl
 | 
					Files: modules/lightmapper_rd/lm_compute.glsl
 | 
				
			||||||
 ./servers/rendering/renderer_rd/shaders/ssil.glsl
 | 
					Comment: Joint Non-Local Means (JNLM) denoiser
 | 
				
			||||||
 | 
					Copyright: 2020, Manuel Prandini
 | 
				
			||||||
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: platform/android/java/editor/src/main/java/com/android/*
 | 
				
			||||||
 | 
					 platform/android/java/lib/aidl/com/android/*
 | 
				
			||||||
 | 
					 platform/android/java/lib/res/layout/status_bar_ongoing_event_progress_bar.xml
 | 
				
			||||||
 | 
					 platform/android/java/lib/src/com/google/android/*
 | 
				
			||||||
 | 
					 platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java
 | 
				
			||||||
 | 
					 platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java
 | 
				
			||||||
 | 
					Comment: The Android Open Source Project
 | 
				
			||||||
 | 
					Copyright: 2008-2016, The Android Open Source Project
 | 
				
			||||||
 | 
					 2002, Google, Inc.
 | 
				
			||||||
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java
 | 
				
			||||||
 | 
					Comment: ProcessPhoenix
 | 
				
			||||||
 | 
					Copyright: 2015, Jake Wharton
 | 
				
			||||||
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: scene/animation/easing_equations.h
 | 
				
			||||||
 | 
					Comment: Robert Penner's Easing Functions
 | 
				
			||||||
 | 
					Copyright: 2001, Robert Penner
 | 
				
			||||||
 | 
					 2014-present, Godot Engine contributors
 | 
				
			||||||
 | 
					 2007-2014, Juan Linietsky, Ariel Manzur
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssao_blur.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssao.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssil_blur.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssil_interleave.glsl
 | 
				
			||||||
 | 
					 servers/rendering/renderer_rd/shaders/ssil.glsl
 | 
				
			||||||
Comment: Intel ASSAO and related files
 | 
					Comment: Intel ASSAO and related files
 | 
				
			||||||
Copyright: 2016, Intel Corporation
 | 
					Copyright: 2016, Intel Corporation
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./servers/rendering/renderer_rd/shaders/taa_resolve.glsl
 | 
					Files: servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
 | 
				
			||||||
Comment: Temporal Anti-Aliasing resolve implementation
 | 
					Comment: Temporal Anti-Aliasing resolve implementation
 | 
				
			||||||
Copyright: 2016, Panos Karabelas
 | 
					Copyright: 2016, Panos Karabelas
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/amd-fsr/
 | 
					Files: thirdparty/amd-fsr/*
 | 
				
			||||||
Comment: AMD FidelityFX Super Resolution
 | 
					Comment: AMD FidelityFX Super Resolution
 | 
				
			||||||
Copyright: 2021, Advanced Micro Devices, Inc.
 | 
					Copyright: 2021, Advanced Micro Devices, Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/amd-fsr2/
 | 
					Files: thirdparty/amd-fsr2/*
 | 
				
			||||||
Comment: AMD FidelityFX Super Resolution 2
 | 
					Comment: AMD FidelityFX Super Resolution 2
 | 
				
			||||||
Copyright: 2022-2023, Advanced Micro Devices, Inc.
 | 
					Copyright: 2022-2023, Advanced Micro Devices, Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/angle/
 | 
					Files: thirdparty/angle/*
 | 
				
			||||||
Comment: ANGLE
 | 
					Comment: ANGLE
 | 
				
			||||||
Copyright: 2018, The ANGLE Project Authors.
 | 
					Copyright: 2018, The ANGLE Project Authors.
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/astcenc/
 | 
					Files: thirdparty/astcenc/*
 | 
				
			||||||
Comment: Arm ASTC Encoder
 | 
					Comment: Arm ASTC Encoder
 | 
				
			||||||
Copyright: 2011-2024, Arm Limited
 | 
					Copyright: 2011-2024, Arm Limited
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/basis_universal/
 | 
					Files: thirdparty/basis_universal/*
 | 
				
			||||||
Comment: Basis Universal
 | 
					Comment: Basis Universal
 | 
				
			||||||
Copyright: 2022, Binomial LLC.
 | 
					Copyright: 2019-2024, Binomial LLC.
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/brotli/
 | 
					Files: thirdparty/brotli/*
 | 
				
			||||||
Comment: Brotli
 | 
					Comment: Brotli
 | 
				
			||||||
Copyright: 2009, 2010, 2013-2016 by the Brotli Authors.
 | 
					Copyright: 2009, 2010, 2013-2016 by the Brotli Authors.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/certs/ca-certificates.crt
 | 
					Files: thirdparty/certs/ca-certificates.crt
 | 
				
			||||||
Comment: CA certificates
 | 
					Comment: CA certificates
 | 
				
			||||||
Copyright: Mozilla Contributors
 | 
					Copyright: Mozilla Contributors
 | 
				
			||||||
License: MPL-2.0
 | 
					License: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/clipper2/
 | 
					Files: thirdparty/clipper2/*
 | 
				
			||||||
Comment: Clipper2
 | 
					Comment: Clipper2
 | 
				
			||||||
Copyright: 2010-2023, Angus Johnson
 | 
					Copyright: 2010-2024, Angus Johnson
 | 
				
			||||||
License: BSL-1.0
 | 
					License: BSL-1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/cvtt/
 | 
					Files: thirdparty/cvtt/*
 | 
				
			||||||
Comment: Convection Texture Tools Stand-Alone Kernels
 | 
					Comment: Convection Texture Tools Stand-Alone Kernels
 | 
				
			||||||
Copyright: 2018, Eric Lasota
 | 
					Copyright: 2018, Eric Lasota
 | 
				
			||||||
 2018, Microsoft Corp.
 | 
					 2018, Microsoft Corp.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/d3d12ma/
 | 
					Files: thirdparty/d3d12ma/*
 | 
				
			||||||
Comment: D3D12 Memory Allocator
 | 
					Comment: D3D12 Memory Allocator
 | 
				
			||||||
Copyright: 2019-2022 Advanced Micro Devices, Inc.
 | 
					Copyright: 2019-2022 Advanced Micro Devices, Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/directx_headers/
 | 
					Files: thirdparty/directx_headers/*
 | 
				
			||||||
Comment: DirectX Headers
 | 
					Comment: DirectX Headers
 | 
				
			||||||
Copyright: Microsoft Corporation
 | 
					Copyright: Microsoft Corporation
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/doctest/
 | 
					Files: thirdparty/doctest/*
 | 
				
			||||||
Comment: doctest
 | 
					Comment: doctest
 | 
				
			||||||
Copyright: 2016-2023, Viktor Kirilov
 | 
					Copyright: 2016-2023, Viktor Kirilov
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/embree/
 | 
					Files: thirdparty/embree/*
 | 
				
			||||||
Comment: Embree
 | 
					Comment: Embree
 | 
				
			||||||
Copyright: 2009-2021 Intel Corporation
 | 
					Copyright: 2009-2021 Intel Corporation
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/enet/
 | 
					Files: thirdparty/enet/*
 | 
				
			||||||
Comment: ENet
 | 
					Comment: ENet
 | 
				
			||||||
Copyright: 2002-2024, Lee Salzman
 | 
					Copyright: 2002-2024, Lee Salzman
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/etcpak/
 | 
					Files: thirdparty/etcpak/*
 | 
				
			||||||
Comment: etcpak
 | 
					Comment: etcpak
 | 
				
			||||||
Copyright: 2013-2022, Bartosz Taudul
 | 
					Copyright: 2013-2022, Bartosz Taudul
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/fonts/DroidSans*.woff2
 | 
					Files: thirdparty/fonts/DroidSans*.woff2
 | 
				
			||||||
Comment: DroidSans font
 | 
					Comment: DroidSans font
 | 
				
			||||||
Copyright: 2008, The Android Open Source Project
 | 
					Copyright: 2008, The Android Open Source Project
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/fonts/JetBrainsMono_Regular.woff2
 | 
					Files: thirdparty/fonts/JetBrainsMono_Regular.woff2
 | 
				
			||||||
Comment: JetBrains Mono font
 | 
					Comment: JetBrains Mono font
 | 
				
			||||||
Copyright: 2020, JetBrains s.r.o.
 | 
					Copyright: 2020, JetBrains s.r.o.
 | 
				
			||||||
License: OFL-1.1
 | 
					License: OFL-1.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/fonts/NotoSans*.woff2
 | 
					Files: thirdparty/fonts/NotoSans*.woff2
 | 
				
			||||||
Comment: Noto Sans font
 | 
					Comment: Noto Sans font
 | 
				
			||||||
Copyright: 2012, Google Inc.
 | 
					Copyright: 2012, Google Inc.
 | 
				
			||||||
License: OFL-1.1
 | 
					License: OFL-1.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/freetype/
 | 
					Files: thirdparty/fonts/Vazirmatn*.woff2
 | 
				
			||||||
 | 
					Comment: Vazirmatn font
 | 
				
			||||||
 | 
					Copyright: 2015, The Vazirmatn Project Authors.
 | 
				
			||||||
 | 
					License: OFL-1.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/freetype/*
 | 
				
			||||||
Comment: The FreeType Project
 | 
					Comment: The FreeType Project
 | 
				
			||||||
Copyright: 1996-2023, David Turner, Robert Wilhelm, and Werner Lemberg.
 | 
					Copyright: 1996-2023, David Turner, Robert Wilhelm, and Werner Lemberg.
 | 
				
			||||||
License: FTL
 | 
					License: FTL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/glad/
 | 
					Files: thirdparty/glad/*
 | 
				
			||||||
Comment: glad
 | 
					Comment: glad
 | 
				
			||||||
Copyright: 2013-2022, David Herberth
 | 
					Copyright: 2013-2022, David Herberth
 | 
				
			||||||
 2013-2020, The Khronos Group Inc.
 | 
					 2013-2020, The Khronos Group Inc.
 | 
				
			||||||
License: CC0-1.0 and Apache-2.0
 | 
					License: CC0-1.0 and Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/glslang/
 | 
					Files: thirdparty/glslang/*
 | 
				
			||||||
Comment: glslang
 | 
					Comment: glslang
 | 
				
			||||||
Copyright: 2015-2020, Google, Inc.
 | 
					Copyright: 2015-2020, Google, Inc.
 | 
				
			||||||
  2014-2020, The Khronos Group Inc
 | 
					  2014-2020, The Khronos Group Inc
 | 
				
			||||||
  2002, NVIDIA Corporation.
 | 
					  2002, NVIDIA Corporation.
 | 
				
			||||||
License: glslang
 | 
					License: glslang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/graphite/
 | 
					Files: thirdparty/graphite/*
 | 
				
			||||||
Comment: Graphite engine
 | 
					Comment: Graphite engine
 | 
				
			||||||
Copyright: 2010, SIL International
 | 
					Copyright: 2010, SIL International
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/harfbuzz/
 | 
					Files: thirdparty/harfbuzz/*
 | 
				
			||||||
Comment: HarfBuzz text shaping library
 | 
					Comment: HarfBuzz text shaping library
 | 
				
			||||||
Copyright: 2010-2022, Google, Inc.
 | 
					Copyright: 2010-2022, Google, Inc.
 | 
				
			||||||
 2015-2020, Ebrahim Byagowi
 | 
					 2015-2020, Ebrahim Byagowi
 | 
				
			||||||
| 
						 | 
					@ -283,248 +303,263 @@ Copyright: 2010-2022, Google, Inc.
 | 
				
			||||||
 2013-2015, Alexei Podtelezhnikov
 | 
					 2013-2015, Alexei Podtelezhnikov
 | 
				
			||||||
License: HarfBuzz
 | 
					License: HarfBuzz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/icu4c/
 | 
					Files: thirdparty/icu4c/*
 | 
				
			||||||
Comment: International Components for Unicode
 | 
					Comment: International Components for Unicode
 | 
				
			||||||
Copyright: 2016-2024, Unicode, Inc.
 | 
					Copyright: 2016-2024, Unicode, Inc.
 | 
				
			||||||
License: Unicode
 | 
					License: Unicode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/jpeg-compressor/
 | 
					Files: thirdparty/jolt_physics/*
 | 
				
			||||||
 | 
					Comment: Jolt Physics
 | 
				
			||||||
 | 
					Copyright: 2021, Jorrit Rouwe
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/jpeg-compressor/*
 | 
				
			||||||
Comment: jpeg-compressor
 | 
					Comment: jpeg-compressor
 | 
				
			||||||
Copyright: 2012, Rich Geldreich
 | 
					Copyright: 2012, Rich Geldreich
 | 
				
			||||||
License: public-domain or Apache-2.0
 | 
					License: public-domain or Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libbacktrace/
 | 
					Files: thirdparty/libbacktrace/*
 | 
				
			||||||
Comment: libbacktrace
 | 
					Comment: libbacktrace
 | 
				
			||||||
Copyright: 2012-2021, Free Software Foundation, Inc.
 | 
					Copyright: 2012-2021, Free Software Foundation, Inc.
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libktx/
 | 
					Files: thirdparty/libktx/*
 | 
				
			||||||
Comment: KTX
 | 
					Comment: KTX
 | 
				
			||||||
Copyright: 2013-2020, Mark Callow
 | 
					Copyright: 2013-2020, Mark Callow
 | 
				
			||||||
 2010-2020 The Khronos Group, Inc.
 | 
					 2010-2020 The Khronos Group, Inc.
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libogg/
 | 
					Files: thirdparty/libogg/*
 | 
				
			||||||
Comment: OggVorbis
 | 
					Comment: OggVorbis
 | 
				
			||||||
Copyright: 2002, Xiph.org Foundation
 | 
					Copyright: 2002, Xiph.org Foundation
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libpng/
 | 
					Files: thirdparty/libpng/*
 | 
				
			||||||
Comment: libpng
 | 
					Comment: libpng
 | 
				
			||||||
Copyright: 1995-2024, The PNG Reference Library Authors.
 | 
					Copyright: 1995-2025, The PNG Reference Library Authors.
 | 
				
			||||||
 2018-2024, Cosmin Truta.
 | 
					 2018-2025, Cosmin Truta.
 | 
				
			||||||
 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
 | 
					 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
 | 
				
			||||||
 1996-1997, Andreas Dilger.
 | 
					 1996-1997, Andreas Dilger.
 | 
				
			||||||
 1995-1996, Guy Eric Schalnat, Group 42, Inc.
 | 
					 1995-1996, Guy Eric Schalnat, Group 42, Inc.
 | 
				
			||||||
License: Zlib
 | 
					License: Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libtheora/
 | 
					Files: thirdparty/libtheora/*
 | 
				
			||||||
Comment: OggTheora
 | 
					Comment: OggTheora
 | 
				
			||||||
Copyright: 2002-2009, Xiph.org Foundation
 | 
					Copyright: 2002-2009, Xiph.org Foundation
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libvorbis/
 | 
					Files: thirdparty/libvorbis/*
 | 
				
			||||||
Comment: OggVorbis
 | 
					Comment: OggVorbis
 | 
				
			||||||
Copyright: 2002-2015, Xiph.org Foundation
 | 
					Copyright: 2002-2015, Xiph.org Foundation
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/libwebp/
 | 
					Files: thirdparty/libwebp/*
 | 
				
			||||||
Comment: WebP codec
 | 
					Comment: WebP codec
 | 
				
			||||||
Copyright: 2010, Google Inc.
 | 
					Copyright: 2010, Google Inc.
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/mbedtls/
 | 
					Files: thirdparty/manifold/*
 | 
				
			||||||
 | 
					Comment: Manifold
 | 
				
			||||||
 | 
					Copyright: 2020-2024, The Manifold Authors
 | 
				
			||||||
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/mbedtls/*
 | 
				
			||||||
Comment: Mbed TLS
 | 
					Comment: Mbed TLS
 | 
				
			||||||
Copyright: The Mbed TLS Contributors
 | 
					Copyright: The Mbed TLS Contributors
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/meshoptimizer/
 | 
					Files: thirdparty/meshoptimizer/*
 | 
				
			||||||
Comment: meshoptimizer
 | 
					Comment: meshoptimizer
 | 
				
			||||||
Copyright: 2016-2023, Arseny Kapoulkine
 | 
					Copyright: 2016-2024, Arseny Kapoulkine
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/mingw-std-threads/
 | 
					Files: thirdparty/mingw-std-threads/*
 | 
				
			||||||
Comment: mingw-std-threads
 | 
					Comment: mingw-std-threads
 | 
				
			||||||
Copyright: 2016, Mega Limited
 | 
					Copyright: 2016, Mega Limited
 | 
				
			||||||
License: BSD-2-clause
 | 
					License: BSD-2-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/minimp3/
 | 
					Files: thirdparty/minimp3/*
 | 
				
			||||||
Comment: MiniMP3
 | 
					Comment: MiniMP3
 | 
				
			||||||
Copyright: lieff
 | 
					Copyright: lieff
 | 
				
			||||||
License: CC0-1.0
 | 
					License: CC0-1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/miniupnpc/
 | 
					Files: thirdparty/miniupnpc/*
 | 
				
			||||||
Comment: MiniUPnP Project
 | 
					Comment: MiniUPnP Project
 | 
				
			||||||
Copyright: 2005-2024, Thomas Bernard
 | 
					Copyright: 2005-2024, Thomas Bernard
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/minizip/
 | 
					Files: thirdparty/minizip/*
 | 
				
			||||||
Comment: MiniZip
 | 
					Comment: MiniZip
 | 
				
			||||||
Copyright: 1998-2010, Gilles Vollant
 | 
					Copyright: 1998-2010, Gilles Vollant
 | 
				
			||||||
 2007-2008, Even Rouault
 | 
					 2007-2008, Even Rouault
 | 
				
			||||||
 2009-2010, Mathias Svensson
 | 
					 2009-2010, Mathias Svensson
 | 
				
			||||||
License: Zlib
 | 
					License: Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/cubemap_coeffs.h
 | 
					Files: thirdparty/misc/bcdec.h
 | 
				
			||||||
 | 
					Comment: bcdec
 | 
				
			||||||
 | 
					Copyright: 2022, Sergii Kudlai
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/misc/cubemap_coeffs.h
 | 
				
			||||||
Comment: Fast Filtering of Reflection Probes
 | 
					Comment: Fast Filtering of Reflection Probes
 | 
				
			||||||
Copyright: 2016, Activision Publishing, Inc.
 | 
					Copyright: 2016, Activision Publishing, Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/fastlz.c
 | 
					Files: thirdparty/misc/fastlz.c
 | 
				
			||||||
 ./thirdparty/misc/fastlz.h
 | 
					 thirdparty/misc/fastlz.h
 | 
				
			||||||
Comment: FastLZ
 | 
					Comment: FastLZ
 | 
				
			||||||
Copyright: 2005-2020, Ariya Hidayat
 | 
					Copyright: 2005-2020, Ariya Hidayat
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/ifaddrs-android.cc
 | 
					Files: thirdparty/misc/FastNoiseLite.h
 | 
				
			||||||
 ./thirdparty/misc/ifaddrs-android.h
 | 
					 | 
				
			||||||
Comment: libjingle
 | 
					 | 
				
			||||||
Copyright: 2012-2013, Google Inc.
 | 
					 | 
				
			||||||
License: BSD-3-clause
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./thirdparty/misc/mikktspace.c
 | 
					 | 
				
			||||||
 ./thirdparty/misc/mikktspace.h
 | 
					 | 
				
			||||||
Comment: Tangent Space Normal Maps implementation
 | 
					 | 
				
			||||||
Copyright: 2011, Morten S. Mikkelsen
 | 
					 | 
				
			||||||
License: Zlib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./thirdparty/misc/ok_color.h
 | 
					 | 
				
			||||||
 ./thirdparty/misc/ok_color_shader.h
 | 
					 | 
				
			||||||
Comment: OK Lab color space
 | 
					 | 
				
			||||||
Copyright: 2021, Björn Ottosson
 | 
					 | 
				
			||||||
License: Expat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./thirdparty/noise/FastNoiseLite.h
 | 
					 | 
				
			||||||
Comment: FastNoise Lite
 | 
					Comment: FastNoise Lite
 | 
				
			||||||
Copyright: 2023, Jordan Peck and contributors
 | 
					Copyright: 2023, Jordan Peck and contributors
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/pcg.cpp
 | 
					Files: thirdparty/misc/ifaddrs-android.cc
 | 
				
			||||||
 ./thirdparty/misc/pcg.h
 | 
					 thirdparty/misc/ifaddrs-android.h
 | 
				
			||||||
 | 
					Comment: libjingle
 | 
				
			||||||
 | 
					Copyright: 2012-2013, Google Inc.
 | 
				
			||||||
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/misc/mikktspace.c
 | 
				
			||||||
 | 
					 thirdparty/misc/mikktspace.h
 | 
				
			||||||
 | 
					Comment: Tangent Space Normal Maps implementation
 | 
				
			||||||
 | 
					Copyright: 2011, Morten S. Mikkelsen
 | 
				
			||||||
 | 
					License: Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/misc/nvapi_minimal.h
 | 
				
			||||||
 | 
					Comment: NVIDIA NVAPI (minimal excerpt)
 | 
				
			||||||
 | 
					Copyright: 2019-2022, NVIDIA Corporation
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/misc/ok_color.h
 | 
				
			||||||
 | 
					 thirdparty/misc/ok_color_shader.h
 | 
				
			||||||
 | 
					Comment: OK Lab color space
 | 
				
			||||||
 | 
					Copyright: 2021, Björn Ottosson
 | 
				
			||||||
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/misc/pcg.cpp
 | 
				
			||||||
 | 
					 thirdparty/misc/pcg.h
 | 
				
			||||||
Comment: Minimal PCG32 implementation
 | 
					Comment: Minimal PCG32 implementation
 | 
				
			||||||
Copyright: 2014, M.E. O'Neill
 | 
					Copyright: 2014, M.E. O'Neill
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/polypartition.cpp
 | 
					Files: thirdparty/misc/polypartition.cpp
 | 
				
			||||||
 ./thirdparty/misc/polypartition.h
 | 
					 thirdparty/misc/polypartition.h
 | 
				
			||||||
Comment: PolyPartition / Triangulator
 | 
					Comment: PolyPartition / Triangulator
 | 
				
			||||||
Copyright: 2011-2021, Ivan Fratric and contributors
 | 
					Copyright: 2011-2021, Ivan Fratric and contributors
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/qoa.h
 | 
					Files: thirdparty/misc/qoa.h
 | 
				
			||||||
Comment: Quite OK Audio Format
 | 
					Comment: Quite OK Audio Format
 | 
				
			||||||
Copyright: 2023, Dominic Szablewski
 | 
					Copyright: 2023, Dominic Szablewski
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/r128.c
 | 
					Files: thirdparty/misc/r128.c
 | 
				
			||||||
 ./thirdparty/misc/r128.h
 | 
					 thirdparty/misc/r128.h
 | 
				
			||||||
Comment: r128 library
 | 
					Comment: r128 library
 | 
				
			||||||
Copyright: Alan Hickman
 | 
					Copyright: Alan Hickman
 | 
				
			||||||
License: public-domain or Unlicense
 | 
					License: public-domain or Unlicense
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/smaz.c
 | 
					Files: thirdparty/misc/smaz.c
 | 
				
			||||||
 ./thirdparty/misc/smaz.h
 | 
					 thirdparty/misc/smaz.h
 | 
				
			||||||
Comment: SMAZ
 | 
					Comment: SMAZ
 | 
				
			||||||
Copyright: 2006-2009, Salvatore Sanfilippo
 | 
					Copyright: 2006-2009, Salvatore Sanfilippo
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/smolv.cpp
 | 
					Files: thirdparty/misc/smolv.cpp
 | 
				
			||||||
 ./thirdparty/misc/smolv.h
 | 
					 thirdparty/misc/smolv.h
 | 
				
			||||||
Comment: SMOL-V
 | 
					Comment: SMOL-V
 | 
				
			||||||
Copyright: 2016-2020, Aras Pranckevicius
 | 
					Copyright: 2016-2024, Aras Pranckevicius
 | 
				
			||||||
License: public-domain or Unlicense or Expat
 | 
					License: public-domain or Unlicense or Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/stb_rect_pack.h
 | 
					Files: thirdparty/misc/stb_rect_pack.h
 | 
				
			||||||
Comment: stb libraries
 | 
					Comment: stb libraries
 | 
				
			||||||
Copyright: Sean Barrett
 | 
					Copyright: Sean Barrett
 | 
				
			||||||
License: public-domain or Unlicense or Expat
 | 
					License: public-domain or Unlicense or Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/misc/yuv2rgb.h
 | 
					Files: thirdparty/misc/yuv2rgb.h
 | 
				
			||||||
Comment: YUV2RGB
 | 
					Comment: YUV2RGB
 | 
				
			||||||
Copyright: 2008-2011, Robin Watts
 | 
					Copyright: 2008-2011, Robin Watts
 | 
				
			||||||
License: BSD-2-clause
 | 
					License: BSD-2-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/msdfgen/
 | 
					Files: thirdparty/msdfgen/*
 | 
				
			||||||
Comment: Multi-channel signed distance field generator
 | 
					Comment: Multi-channel signed distance field generator
 | 
				
			||||||
Copyright: 2016-2022, Viktor Chlumsky
 | 
					Copyright: 2014-2024, Viktor Chlumsky
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/nvapi/nvapi_minimal.h
 | 
					Files: thirdparty/openxr/*
 | 
				
			||||||
Comment: Stripped down version of "nvapi.h" from the NVIDIA NVAPI SDK
 | 
					 | 
				
			||||||
Copyright: 2019-2022, NVIDIA Corporation
 | 
					 | 
				
			||||||
License: Expat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./thirdparty/openxr/
 | 
					 | 
				
			||||||
Comment: OpenXR Loader
 | 
					Comment: OpenXR Loader
 | 
				
			||||||
Copyright: 2020-2023, The Khronos Group Inc.
 | 
					Copyright: 2020-2023, The Khronos Group Inc.
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/pcre2/
 | 
					Files: thirdparty/pcre2/*
 | 
				
			||||||
Comment: PCRE2
 | 
					Comment: PCRE2
 | 
				
			||||||
Copyright: 1997-2024, University of Cambridge
 | 
					Copyright: 1997-2024, University of Cambridge
 | 
				
			||||||
 2009-2024, Zoltan Herczeg
 | 
					 2009-2024, Zoltan Herczeg
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/recastnavigation/
 | 
					Files: thirdparty/recastnavigation/*
 | 
				
			||||||
Comment: Recast
 | 
					Comment: Recast
 | 
				
			||||||
Copyright: 2009, Mikko Mononen
 | 
					Copyright: 2009, Mikko Mononen
 | 
				
			||||||
License: Zlib
 | 
					License: Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/rvo2/
 | 
					Files: thirdparty/rvo2/*
 | 
				
			||||||
Comment: RVO2
 | 
					Comment: RVO2
 | 
				
			||||||
Copyright: 2016, University of North Carolina at Chapel Hill
 | 
					Copyright: 2016, University of North Carolina at Chapel Hill
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/spirv-reflect/
 | 
					Files: thirdparty/spirv-cross/*
 | 
				
			||||||
 | 
					Comment: SPIRV-Cross
 | 
				
			||||||
 | 
					Copyright: 2015-2021, Arm Limited
 | 
				
			||||||
 | 
					License: Apache-2.0 or Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files: thirdparty/spirv-reflect/*
 | 
				
			||||||
Comment: SPIRV-Reflect
 | 
					Comment: SPIRV-Reflect
 | 
				
			||||||
Copyright: 2017-2022, Google Inc.
 | 
					Copyright: 2017-2022, Google Inc.
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/squish/
 | 
					Files: thirdparty/thorvg/*
 | 
				
			||||||
Comment: libSquish
 | 
					 | 
				
			||||||
Copyright: 2006, Simon Brown
 | 
					 | 
				
			||||||
License: Expat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: ./thirdparty/thorvg/
 | 
					 | 
				
			||||||
Comment: ThorVG
 | 
					Comment: ThorVG
 | 
				
			||||||
Copyright: 2020-2024, The ThorVG Project
 | 
					Copyright: 2020-2024, The ThorVG Project
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/tinyexr/
 | 
					Files: thirdparty/tinyexr/*
 | 
				
			||||||
Comment: TinyEXR
 | 
					Comment: TinyEXR
 | 
				
			||||||
Copyright: 2014-2021, Syoyo Fujita
 | 
					Copyright: 2014-2021, Syoyo Fujita
 | 
				
			||||||
  2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
 | 
					  2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/ufbx/
 | 
					Files: thirdparty/ufbx/*
 | 
				
			||||||
Comment: ufbx
 | 
					Comment: ufbx
 | 
				
			||||||
Copyright: 2020, Samuli Raivio
 | 
					Copyright: 2020, Samuli Raivio
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/vhacd/
 | 
					Files: thirdparty/vhacd/*
 | 
				
			||||||
Comment: V-HACD
 | 
					Comment: V-HACD
 | 
				
			||||||
Copyright: 2011, Khaled Mamou
 | 
					Copyright: 2011, Khaled Mamou
 | 
				
			||||||
  2003-2009, Erwin Coumans
 | 
					  2003-2009, Erwin Coumans
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/volk/
 | 
					Files: thirdparty/volk/*
 | 
				
			||||||
Comment: volk
 | 
					Comment: volk
 | 
				
			||||||
Copyright: 2018-2024, Arseny Kapoulkine
 | 
					Copyright: 2018-2024, Arseny Kapoulkine
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/vulkan/
 | 
					Files: thirdparty/vulkan/*
 | 
				
			||||||
Comment: Vulkan Headers
 | 
					Comment: Vulkan Headers
 | 
				
			||||||
Copyright: 2014-2024, The Khronos Group Inc.
 | 
					Copyright: 2014-2024, The Khronos Group Inc.
 | 
				
			||||||
  2014-2024, Valve Corporation
 | 
					  2014-2024, Valve Corporation
 | 
				
			||||||
  2014-2024, LunarG, Inc.
 | 
					  2014-2024, LunarG, Inc.
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/vulkan/vk_mem_alloc.h
 | 
					Files: thirdparty/vulkan/vk_mem_alloc.h
 | 
				
			||||||
Comment: Vulkan Memory Allocator
 | 
					Comment: Vulkan Memory Allocator
 | 
				
			||||||
Copyright: 2017-2024, Advanced Micro Devices, Inc.
 | 
					Copyright: 2017-2024, Advanced Micro Devices, Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/wayland/
 | 
					Files: thirdparty/wayland/*
 | 
				
			||||||
Comment: Wayland core protocol
 | 
					Comment: Wayland core protocol
 | 
				
			||||||
Copyright: 2008-2012, Kristian Høgsberg
 | 
					Copyright: 2008-2012, Kristian Høgsberg
 | 
				
			||||||
  2010-2012, Intel Corporation
 | 
					  2010-2012, Intel Corporation
 | 
				
			||||||
| 
						 | 
					@ -532,7 +567,7 @@ Copyright: 2008-2012, Kristian Høgsberg
 | 
				
			||||||
  2012, Collabora, Ltd.
 | 
					  2012, Collabora, Ltd.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/wayland-protocols/
 | 
					Files: thirdparty/wayland-protocols/*
 | 
				
			||||||
Comment: Wayland protocols that add functionality not available in the core protocol
 | 
					Comment: Wayland protocols that add functionality not available in the core protocol
 | 
				
			||||||
Copyright: 2008-2013, Kristian Høgsberg
 | 
					Copyright: 2008-2013, Kristian Høgsberg
 | 
				
			||||||
  2010-2013, Intel Corporation
 | 
					  2010-2013, Intel Corporation
 | 
				
			||||||
| 
						 | 
					@ -544,24 +579,24 @@ Copyright: 2008-2013, Kristian Høgsberg
 | 
				
			||||||
  2015,      Red Hat Inc.
 | 
					  2015,      Red Hat Inc.
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/wslay/
 | 
					Files: thirdparty/wslay/*
 | 
				
			||||||
Comment: Wslay
 | 
					Comment: Wslay
 | 
				
			||||||
Copyright: 2011, 2012, 2015, Tatsuhiro Tsujikawa
 | 
					Copyright: 2011, 2012, 2015, Tatsuhiro Tsujikawa
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/xatlas/
 | 
					Files: thirdparty/xatlas/*
 | 
				
			||||||
Comment: xatlas
 | 
					Comment: xatlas
 | 
				
			||||||
Copyright: 2018-2020, Jonathan Young
 | 
					Copyright: 2018-2020, Jonathan Young
 | 
				
			||||||
  2013, Thekla, Inc
 | 
					  2013, Thekla, Inc
 | 
				
			||||||
  2006, NVIDIA Corporation, Ignacio Castano
 | 
					  2006, NVIDIA Corporation, Ignacio Castano
 | 
				
			||||||
License: Expat
 | 
					License: Expat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/zlib/
 | 
					Files: thirdparty/zlib/*
 | 
				
			||||||
Comment: zlib
 | 
					Comment: zlib
 | 
				
			||||||
Copyright: 1995-2024, Jean-loup Gailly and Mark Adler
 | 
					Copyright: 1995-2024, Jean-loup Gailly and Mark Adler
 | 
				
			||||||
License: Zlib
 | 
					License: Zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: ./thirdparty/zstd/
 | 
					Files: thirdparty/zstd/*
 | 
				
			||||||
Comment: Zstandard
 | 
					Comment: Zstandard
 | 
				
			||||||
Copyright: Meta Platforms, Inc. and affiliates.
 | 
					Copyright: Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
License: BSD-3-clause
 | 
					License: BSD-3-clause
 | 
				
			||||||
| 
						 | 
					@ -569,6 +604,196 @@ License: BSD-3-clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
License: Apache-2.0
 | 
					License: Apache-2.0
 | 
				
			||||||
 | 
					                               Apache License
 | 
				
			||||||
 | 
					                         Version 2.0, January 2004
 | 
				
			||||||
 | 
					                      http://www.apache.org/licenses/
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 1. Definitions.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "License" shall mean the terms and conditions for use, reproduction,
 | 
				
			||||||
 | 
					    and distribution as defined by Sections 1 through 9 of this document.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Licensor" shall mean the copyright owner or entity authorized by
 | 
				
			||||||
 | 
					    the copyright owner that is granting the License.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Legal Entity" shall mean the union of the acting entity and all
 | 
				
			||||||
 | 
					    other entities that control, are controlled by, or are under common
 | 
				
			||||||
 | 
					    control with that entity. For the purposes of this definition,
 | 
				
			||||||
 | 
					    "control" means (i) the power, direct or indirect, to cause the
 | 
				
			||||||
 | 
					    direction or management of such entity, whether by contract or
 | 
				
			||||||
 | 
					    otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
				
			||||||
 | 
					    outstanding shares, or (iii) beneficial ownership of such entity.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "You" (or "Your") shall mean an individual or Legal Entity
 | 
				
			||||||
 | 
					    exercising permissions granted by this License.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Source" form shall mean the preferred form for making modifications,
 | 
				
			||||||
 | 
					    including but not limited to software source code, documentation
 | 
				
			||||||
 | 
					    source, and configuration files.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Object" form shall mean any form resulting from mechanical
 | 
				
			||||||
 | 
					    transformation or translation of a Source form, including but
 | 
				
			||||||
 | 
					    not limited to compiled object code, generated documentation,
 | 
				
			||||||
 | 
					    and conversions to other media types.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Work" shall mean the work of authorship, whether in Source or
 | 
				
			||||||
 | 
					    Object form, made available under the License, as indicated by a
 | 
				
			||||||
 | 
					    copyright notice that is included in or attached to the work
 | 
				
			||||||
 | 
					    (an example is provided in the Appendix below).
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Derivative Works" shall mean any work, whether in Source or Object
 | 
				
			||||||
 | 
					    form, that is based on (or derived from) the Work and for which the
 | 
				
			||||||
 | 
					    editorial revisions, annotations, elaborations, or other modifications
 | 
				
			||||||
 | 
					    represent, as a whole, an original work of authorship. For the purposes
 | 
				
			||||||
 | 
					    of this License, Derivative Works shall not include works that remain
 | 
				
			||||||
 | 
					    separable from, or merely link (or bind by name) to the interfaces of,
 | 
				
			||||||
 | 
					    the Work and Derivative Works thereof.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Contribution" shall mean any work of authorship, including
 | 
				
			||||||
 | 
					    the original version of the Work and any modifications or additions
 | 
				
			||||||
 | 
					    to that Work or Derivative Works thereof, that is intentionally
 | 
				
			||||||
 | 
					    submitted to Licensor for inclusion in the Work by the copyright owner
 | 
				
			||||||
 | 
					    or by an individual or Legal Entity authorized to submit on behalf of
 | 
				
			||||||
 | 
					    the copyright owner. For the purposes of this definition, "submitted"
 | 
				
			||||||
 | 
					    means any form of electronic, verbal, or written communication sent
 | 
				
			||||||
 | 
					    to the Licensor or its representatives, including but not limited to
 | 
				
			||||||
 | 
					    communication on electronic mailing lists, source code control systems,
 | 
				
			||||||
 | 
					    and issue tracking systems that are managed by, or on behalf of, the
 | 
				
			||||||
 | 
					    Licensor for the purpose of discussing and improving the Work, but
 | 
				
			||||||
 | 
					    excluding communication that is conspicuously marked or otherwise
 | 
				
			||||||
 | 
					    designated in writing by the copyright owner as "Not a Contribution."
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
				
			||||||
 | 
					    on behalf of whom a Contribution has been received by Licensor and
 | 
				
			||||||
 | 
					    subsequently incorporated within the Work.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 2. Grant of Copyright License. Subject to the terms and conditions of
 | 
				
			||||||
 | 
					    this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||||
 | 
					    worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||||
 | 
					    copyright license to reproduce, prepare Derivative Works of,
 | 
				
			||||||
 | 
					    publicly display, publicly perform, sublicense, and distribute the
 | 
				
			||||||
 | 
					    Work and such Derivative Works in Source or Object form.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 3. Grant of Patent License. Subject to the terms and conditions of
 | 
				
			||||||
 | 
					    this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||||
 | 
					    worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||||
 | 
					    (except as stated in this section) patent license to make, have made,
 | 
				
			||||||
 | 
					    use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
				
			||||||
 | 
					    where such license applies only to those patent claims licensable
 | 
				
			||||||
 | 
					    by such Contributor that are necessarily infringed by their
 | 
				
			||||||
 | 
					    Contribution(s) alone or by combination of their Contribution(s)
 | 
				
			||||||
 | 
					    with the Work to which such Contribution(s) was submitted. If You
 | 
				
			||||||
 | 
					    institute patent litigation against any entity (including a
 | 
				
			||||||
 | 
					    cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
				
			||||||
 | 
					    or a Contribution incorporated within the Work constitutes direct
 | 
				
			||||||
 | 
					    or contributory patent infringement, then any patent licenses
 | 
				
			||||||
 | 
					    granted to You under this License for that Work shall terminate
 | 
				
			||||||
 | 
					    as of the date such litigation is filed.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 4. Redistribution. You may reproduce and distribute copies of the
 | 
				
			||||||
 | 
					    Work or Derivative Works thereof in any medium, with or without
 | 
				
			||||||
 | 
					    modifications, and in Source or Object form, provided that You
 | 
				
			||||||
 | 
					    meet the following conditions:
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 (a) You must give any other recipients of the Work or
 | 
				
			||||||
 | 
					     Derivative Works a copy of this License; and
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 (b) You must cause any modified files to carry prominent notices
 | 
				
			||||||
 | 
					     stating that You changed the files; and
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 (c) You must retain, in the Source form of any Derivative Works
 | 
				
			||||||
 | 
					     that You distribute, all copyright, patent, trademark, and
 | 
				
			||||||
 | 
					     attribution notices from the Source form of the Work,
 | 
				
			||||||
 | 
					     excluding those notices that do not pertain to any part of
 | 
				
			||||||
 | 
					     the Derivative Works; and
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 (d) If the Work includes a "NOTICE" text file as part of its
 | 
				
			||||||
 | 
					     distribution, then any Derivative Works that You distribute must
 | 
				
			||||||
 | 
					     include a readable copy of the attribution notices contained
 | 
				
			||||||
 | 
					     within such NOTICE file, excluding those notices that do not
 | 
				
			||||||
 | 
					     pertain to any part of the Derivative Works, in at least one
 | 
				
			||||||
 | 
					     of the following places: within a NOTICE text file distributed
 | 
				
			||||||
 | 
					     as part of the Derivative Works; within the Source form or
 | 
				
			||||||
 | 
					     documentation, if provided along with the Derivative Works; or,
 | 
				
			||||||
 | 
					     within a display generated by the Derivative Works, if and
 | 
				
			||||||
 | 
					     wherever such third-party notices normally appear. The contents
 | 
				
			||||||
 | 
					     of the NOTICE file are for informational purposes only and
 | 
				
			||||||
 | 
					     do not modify the License. You may add Your own attribution
 | 
				
			||||||
 | 
					     notices within Derivative Works that You distribute, alongside
 | 
				
			||||||
 | 
					     or as an addendum to the NOTICE text from the Work, provided
 | 
				
			||||||
 | 
					     that such additional attribution notices cannot be construed
 | 
				
			||||||
 | 
					     as modifying the License.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 You may add Your own copyright statement to Your modifications and
 | 
				
			||||||
 | 
					 may provide additional or different license terms and conditions
 | 
				
			||||||
 | 
					 for use, reproduction, or distribution of Your modifications, or
 | 
				
			||||||
 | 
					 for any such Derivative Works as a whole, provided Your use,
 | 
				
			||||||
 | 
					 reproduction, and distribution of the Work otherwise complies with
 | 
				
			||||||
 | 
					 the conditions stated in this License.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
				
			||||||
 | 
					    any Contribution intentionally submitted for inclusion in the Work
 | 
				
			||||||
 | 
					    by You to the Licensor shall be under the terms and conditions of
 | 
				
			||||||
 | 
					    this License, without any additional terms or conditions.
 | 
				
			||||||
 | 
					    Notwithstanding the above, nothing herein shall supersede or modify
 | 
				
			||||||
 | 
					    the terms of any separate license agreement you may have executed
 | 
				
			||||||
 | 
					    with Licensor regarding such Contributions.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 6. Trademarks. This License does not grant permission to use the trade
 | 
				
			||||||
 | 
					    names, trademarks, service marks, or product names of the Licensor,
 | 
				
			||||||
 | 
					    except as required for reasonable and customary use in describing the
 | 
				
			||||||
 | 
					    origin of the Work and reproducing the content of the NOTICE file.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 7. Disclaimer of Warranty. Unless required by applicable law or
 | 
				
			||||||
 | 
					    agreed to in writing, Licensor provides the Work (and each
 | 
				
			||||||
 | 
					    Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
				
			||||||
 | 
					    implied, including, without limitation, any warranties or conditions
 | 
				
			||||||
 | 
					    of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
				
			||||||
 | 
					    PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
				
			||||||
 | 
					    appropriateness of using or redistributing the Work and assume any
 | 
				
			||||||
 | 
					    risks associated with Your exercise of permissions under this License.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 8. Limitation of Liability. In no event and under no legal theory,
 | 
				
			||||||
 | 
					    whether in tort (including negligence), contract, or otherwise,
 | 
				
			||||||
 | 
					    unless required by applicable law (such as deliberate and grossly
 | 
				
			||||||
 | 
					    negligent acts) or agreed to in writing, shall any Contributor be
 | 
				
			||||||
 | 
					    liable to You for damages, including any direct, indirect, special,
 | 
				
			||||||
 | 
					    incidental, or consequential damages of any character arising as a
 | 
				
			||||||
 | 
					    result of this License or out of the use or inability to use the
 | 
				
			||||||
 | 
					    Work (including but not limited to damages for loss of goodwill,
 | 
				
			||||||
 | 
					    work stoppage, computer failure or malfunction, or any and all
 | 
				
			||||||
 | 
					    other commercial damages or losses), even if such Contributor
 | 
				
			||||||
 | 
					    has been advised of the possibility of such damages.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 9. Accepting Warranty or Additional Liability. While redistributing
 | 
				
			||||||
 | 
					    the Work or Derivative Works thereof, You may choose to offer,
 | 
				
			||||||
 | 
					    and charge a fee for, acceptance of support, warranty, indemnity,
 | 
				
			||||||
 | 
					    or other liability obligations and/or rights consistent with this
 | 
				
			||||||
 | 
					    License. However, in accepting such obligations, You may act only
 | 
				
			||||||
 | 
					    on Your own behalf and on Your sole responsibility, not on behalf
 | 
				
			||||||
 | 
					    of any other Contributor, and only if You agree to indemnify,
 | 
				
			||||||
 | 
					    defend, and hold each Contributor harmless for any liability
 | 
				
			||||||
 | 
					    incurred by, or claims asserted against, such Contributor by reason
 | 
				
			||||||
 | 
					    of your accepting any such warranty or additional liability.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 APPENDIX: How to apply the Apache License to your work.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					    To apply the Apache License to your work, attach the following
 | 
				
			||||||
 | 
					    boilerplate notice, with the fields enclosed by brackets "[]"
 | 
				
			||||||
 | 
					    replaced with your own identifying information. (Don't include
 | 
				
			||||||
 | 
					    the brackets!)  The text should be enclosed in the appropriate
 | 
				
			||||||
 | 
					    comment syntax for the file format. We also recommend that a
 | 
				
			||||||
 | 
					    file or class name and description of purpose be included on the
 | 
				
			||||||
 | 
					    same "printed page" as the copyright notice for easier
 | 
				
			||||||
 | 
					    identification within third-party archives.
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					 Copyright [yyyy] [name of copyright owner]
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 you may not use this file except in compliance with the License.
 | 
					 you may not use this file except in compliance with the License.
 | 
				
			||||||
 You may obtain a copy of the License at
 | 
					 You may obtain a copy of the License at
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,12 +12,12 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Patrons
 | 
					## Patrons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Khronos® Group <https://www.khronos.org/>
 | 
				
			||||||
    OSS Capital <https://oss.capital/>
 | 
					    OSS Capital <https://oss.capital/>
 | 
				
			||||||
    Re-Logic <https://re-logic.com/>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Platinum sponsors
 | 
					## Platinum sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Google Play <https://play.google.com/>
 | 
					    Google Play <https://play.google.com>
 | 
				
			||||||
    Ramatak <https://ramatak.com/>
 | 
					    Ramatak <https://ramatak.com/>
 | 
				
			||||||
    V-Sekai <https://github.com/V-Sekai>
 | 
					    V-Sekai <https://github.com/V-Sekai>
 | 
				
			||||||
    W4 Games <https://w4games.com/>
 | 
					    W4 Games <https://w4games.com/>
 | 
				
			||||||
| 
						 | 
					@ -25,53 +25,56 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
## Gold sponsors
 | 
					## Gold sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Mega Crit <https://www.megacrit.com/>
 | 
					    Mega Crit <https://www.megacrit.com/>
 | 
				
			||||||
    Pirate Software <https://gopiratesoftware.com/>
 | 
					    Pirate Software <https://gopiratesoftware.com>
 | 
				
			||||||
    Prehensile Tales <https://prehensile-tales.com/>
 | 
					    Prehensile Tales <https://prehensile-tales.com>
 | 
				
			||||||
    Robot Gentleman <http://robotgentleman.com/>
 | 
					    Robot Gentleman <http://robotgentleman.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Silver sponsors
 | 
					## Silver sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Broken Rules <https://brokenrul.es/>
 | 
					    Broken Rules <https://brokenrul.es>
 | 
				
			||||||
    Chasing Carrots <https://www.chasing-carrots.com/>
 | 
					    Chasing Carrots <https://www.chasing-carrots.com>
 | 
				
			||||||
    Copia Wealth Studios <https://copiawealthstudios.com/>
 | 
					    Copia Wealth Studios <https://copiawealthstudios.com/>
 | 
				
			||||||
    Indoor Astronaut <https://indoorastronaut.ch/>
 | 
					    Indoor Astronaut <https://indoorastronaut.ch/>
 | 
				
			||||||
    Load Complete <https://loadcomplete.com/>
 | 
					    LoadComplete <https://loadcomplete.com/>
 | 
				
			||||||
    Null <https://null.com/>
 | 
					    Null <https://null.com/>
 | 
				
			||||||
    Orbital Knight <https://www.orbitalknight.com/>
 | 
					    Orbital Knight <https://www.orbitalknight.com/>
 | 
				
			||||||
    Playful Studios <https://playfulstudios.com/>
 | 
					    Playful Studios <https://playfulstudios.com/>
 | 
				
			||||||
 | 
					    Re-Logic <https://re-logic.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Diamond members
 | 
					## Diamond members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Bippinbits <http://domekeepergame.com/>
 | 
					    Bippinbits <http://domekeepergame.com/>
 | 
				
			||||||
    Sealow
 | 
					    Sylv <https://rankith.itch.io/unnamed-space-idle-prototype>
 | 
				
			||||||
    And 5 anonymous donors
 | 
					    And 3 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Titanium members
 | 
					## Titanium members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Adriaan de Jongh <https://adriaan.games/>
 | 
					    Adriaan de Jongh <https://adriaan.games>
 | 
				
			||||||
    Anitya Space <https://www.anitya.space/>
 | 
					    Anitya Space <https://www.anitya.space>
 | 
				
			||||||
    Basically Games
 | 
					    Basically Games
 | 
				
			||||||
    FDG Entertainment <https://www.fdg-entertainment.com/>
 | 
					    FDG Entertainment <https://www.fdg-entertainment.com>
 | 
				
			||||||
    Game Dev Artisan <https://gamedevartisan.com/>
 | 
					    Game Dev Artisan <https://gamedevartisan.com>
 | 
				
			||||||
    Garry Newman
 | 
					    Garry Newman
 | 
				
			||||||
    Isaiah Smith <https://www.isaiahsmith.dev/>
 | 
					    Kenney <https://kenney.nl/>
 | 
				
			||||||
    Libretrend <https://libretrend.com/>
 | 
					    Libretrend <https://libretrend.com>
 | 
				
			||||||
    Life Art Studios <https://lifeartstudios.net/>
 | 
					    Life Art Studios <https://lifeartstudios.net/>
 | 
				
			||||||
    Lucid Silence Games
 | 
					    Lucid Silence Games
 | 
				
			||||||
    Matthew Campbell
 | 
					    Matthew Campbell
 | 
				
			||||||
    PolyMars <https://polymars.dev/>
 | 
					    PolyMars <https://polymars.dev/>
 | 
				
			||||||
    RPG in a Box <https://www.rpginabox.com/>
 | 
					 | 
				
			||||||
    Razenpok <https://www.youtube.com/watch?v=-QxI-RP6-HM>
 | 
					    Razenpok <https://www.youtube.com/watch?v=-QxI-RP6-HM>
 | 
				
			||||||
    Smirk Software <https://smirk.gg/>
 | 
					    RPG in a Box <https://www.rpginabox.com>
 | 
				
			||||||
 | 
					    Smirk Software <https://smirk.gg>
 | 
				
			||||||
 | 
					    Studio Sunshower <https://www.studiosunshower.com/>
 | 
				
			||||||
 | 
					    TrampolineTales <https://TrampolineTales.com/>
 | 
				
			||||||
    粟二华 (Su Erhua)
 | 
					    粟二华 (Su Erhua)
 | 
				
			||||||
    And 6 anonymous donors
 | 
					    And 4 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Platinum members
 | 
					## Platinum members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Andy Touch
 | 
					    Andy Touch
 | 
				
			||||||
    BlockImperiumGames (BIG)
 | 
					    BlockImperiumGames (BIG)
 | 
				
			||||||
    Christoph Woinke
 | 
					 | 
				
			||||||
    Christopher Shifflett
 | 
					    Christopher Shifflett
 | 
				
			||||||
 | 
					    Christoph Woinke
 | 
				
			||||||
    Cody Bentley
 | 
					    Cody Bentley
 | 
				
			||||||
    Darrin Massena
 | 
					    Darrin Massena
 | 
				
			||||||
    Edward Flick
 | 
					    Edward Flick
 | 
				
			||||||
| 
						 | 
					@ -79,8 +82,8 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    HP van Braam
 | 
					    HP van Braam
 | 
				
			||||||
    iCommitGames
 | 
					    iCommitGames
 | 
				
			||||||
    Jonah Stich
 | 
					    Jonah Stich
 | 
				
			||||||
 | 
					    Justo Delgado Baudí
 | 
				
			||||||
    katnamag
 | 
					    katnamag
 | 
				
			||||||
    Marek Belski
 | 
					 | 
				
			||||||
    Matthew Ekenstedt
 | 
					    Matthew Ekenstedt
 | 
				
			||||||
    Memories in 8Bit
 | 
					    Memories in 8Bit
 | 
				
			||||||
    Mike King
 | 
					    Mike King
 | 
				
			||||||
| 
						 | 
					@ -97,13 +100,14 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    TigerJ
 | 
					    TigerJ
 | 
				
			||||||
    Violin Iliev
 | 
					    Violin Iliev
 | 
				
			||||||
    Vladimír Chvátil
 | 
					    Vladimír Chvátil
 | 
				
			||||||
    And 16 anonymous donors
 | 
					    And 13 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Gold members
 | 
					## Gold members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    80px
 | 
					    80px
 | 
				
			||||||
    afreytes
 | 
					    afreytes
 | 
				
			||||||
    alMoo Games
 | 
					    alMoo Games
 | 
				
			||||||
 | 
					    alMoo Games
 | 
				
			||||||
    Alva Majo
 | 
					    Alva Majo
 | 
				
			||||||
    Antti Vesanen
 | 
					    Antti Vesanen
 | 
				
			||||||
    Asher Glick
 | 
					    Asher Glick
 | 
				
			||||||
| 
						 | 
					@ -119,6 +123,8 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Bryce Dixon
 | 
					    Bryce Dixon
 | 
				
			||||||
    c64cosmin
 | 
					    c64cosmin
 | 
				
			||||||
    Carlo del Mundo
 | 
					    Carlo del Mundo
 | 
				
			||||||
 | 
					    Carl van der Geest
 | 
				
			||||||
 | 
					    Chocolate Software
 | 
				
			||||||
    Cindy Trieu
 | 
					    Cindy Trieu
 | 
				
			||||||
    ClarkThyLord
 | 
					    ClarkThyLord
 | 
				
			||||||
    Codex404
 | 
					    Codex404
 | 
				
			||||||
| 
						 | 
					@ -135,17 +141,21 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    dgehrig
 | 
					    dgehrig
 | 
				
			||||||
    dhanielk
 | 
					    dhanielk
 | 
				
			||||||
    Distorted Realities
 | 
					    Distorted Realities
 | 
				
			||||||
 | 
					    Donkung
 | 
				
			||||||
    Dono
 | 
					    Dono
 | 
				
			||||||
    Don't You Know Who I Am? Inc.
 | 
					    Don't You Know Who I Am? Inc.
 | 
				
			||||||
    Dustuu
 | 
					    Dustuu
 | 
				
			||||||
 | 
					    Dylan P.
 | 
				
			||||||
    Edelweiss
 | 
					    Edelweiss
 | 
				
			||||||
    Ends
 | 
					    Ends
 | 
				
			||||||
    Eren Ogrul
 | 
					    Eren Ogrul
 | 
				
			||||||
    Eric Brand
 | 
					    Eric Brand
 | 
				
			||||||
    Eric Phy
 | 
					    Eric Phy
 | 
				
			||||||
    Faisal Al-Kubaisi (QatariGameDev)
 | 
					    Faisal Al-Kubaisi (QatariGameDev)
 | 
				
			||||||
 | 
					    Felix Adam
 | 
				
			||||||
    FeralBytes
 | 
					    FeralBytes
 | 
				
			||||||
    Festzeltgaming.de
 | 
					    Festzeltgaming.de
 | 
				
			||||||
 | 
					    Frozen Fractal
 | 
				
			||||||
    Gaudipern
 | 
					    Gaudipern
 | 
				
			||||||
    GlassBrick
 | 
					    GlassBrick
 | 
				
			||||||
    Grau
 | 
					    Grau
 | 
				
			||||||
| 
						 | 
					@ -153,6 +163,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Hayden Oliver
 | 
					    Hayden Oliver
 | 
				
			||||||
    hiulit
 | 
					    hiulit
 | 
				
			||||||
    Illyan
 | 
					    Illyan
 | 
				
			||||||
 | 
					    Immaculate Lift Studio
 | 
				
			||||||
    Ivan Tabashki
 | 
					    Ivan Tabashki
 | 
				
			||||||
    Jacob (HACKhalo2 Studios)
 | 
					    Jacob (HACKhalo2 Studios)
 | 
				
			||||||
    Jam
 | 
					    Jam
 | 
				
			||||||
| 
						 | 
					@ -160,13 +171,12 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Javier Roman
 | 
					    Javier Roman
 | 
				
			||||||
    Jeff Hungerford
 | 
					    Jeff Hungerford
 | 
				
			||||||
    Jeronimo Schreyer
 | 
					    Jeronimo Schreyer
 | 
				
			||||||
    Joel Martinez
 | 
					 | 
				
			||||||
    Johannes Wuensch
 | 
					    Johannes Wuensch
 | 
				
			||||||
    John Gabriel
 | 
					    John Gabriel
 | 
				
			||||||
    Jonas Yamazaki
 | 
					    Jonas Yamazaki
 | 
				
			||||||
 | 
					    Jonathan
 | 
				
			||||||
    José Canepa
 | 
					    José Canepa
 | 
				
			||||||
    Joshua Stelly
 | 
					    Joshua Stelly
 | 
				
			||||||
    Justin Sasso
 | 
					 | 
				
			||||||
    Kalydi Balázs
 | 
					    Kalydi Balázs
 | 
				
			||||||
    KAR Games
 | 
					    KAR Games
 | 
				
			||||||
    Kiri "ExpiredPopsicle" Artemis
 | 
					    Kiri "ExpiredPopsicle" Artemis
 | 
				
			||||||
| 
						 | 
					@ -181,7 +191,9 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    m1n1ster
 | 
					    m1n1ster
 | 
				
			||||||
    Manuel Requena
 | 
					    Manuel Requena
 | 
				
			||||||
    Mara Huldra
 | 
					    Mara Huldra
 | 
				
			||||||
 | 
					    Marek Belski
 | 
				
			||||||
    Martin Šenkeřík
 | 
					    Martin Šenkeřík
 | 
				
			||||||
 | 
					    MHDante
 | 
				
			||||||
    Michael Gooch
 | 
					    Michael Gooch
 | 
				
			||||||
    Modus Ponens
 | 
					    Modus Ponens
 | 
				
			||||||
    Moshe Harris
 | 
					    Moshe Harris
 | 
				
			||||||
| 
						 | 
					@ -190,6 +202,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Nassor Paulino da Silva
 | 
					    Nassor Paulino da Silva
 | 
				
			||||||
    nezticle
 | 
					    nezticle
 | 
				
			||||||
    Niklas Wahrman
 | 
					    Niklas Wahrman
 | 
				
			||||||
 | 
					    Nitzan Bueno
 | 
				
			||||||
    Niwl Games
 | 
					    Niwl Games
 | 
				
			||||||
    NotNet
 | 
					    NotNet
 | 
				
			||||||
    Oathbringer
 | 
					    Oathbringer
 | 
				
			||||||
| 
						 | 
					@ -207,6 +220,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    re:thinc
 | 
					    re:thinc
 | 
				
			||||||
    Richard Ivánek
 | 
					    Richard Ivánek
 | 
				
			||||||
    Rudi P
 | 
					    Rudi P
 | 
				
			||||||
 | 
					    Sam Leathers
 | 
				
			||||||
    Samuel Judd
 | 
					    Samuel Judd
 | 
				
			||||||
    ScoreSpace
 | 
					    ScoreSpace
 | 
				
			||||||
    Shiny Shinken
 | 
					    Shiny Shinken
 | 
				
			||||||
| 
						 | 
					@ -238,12 +252,12 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Zhu Li
 | 
					    Zhu Li
 | 
				
			||||||
    zikes
 | 
					    zikes
 | 
				
			||||||
    嗯大爷
 | 
					    嗯大爷
 | 
				
			||||||
 | 
					    潘彦圣
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Alex Khayrullin
 | 
					    Alex Khayrullin
 | 
				
			||||||
    Algebrute
 | 
					    Algebrute
 | 
				
			||||||
    Andriy
 | 
					    Andriy
 | 
				
			||||||
    Antanas Paskauskas
 | 
					    Antanas Paskauskas
 | 
				
			||||||
    anti666
 | 
					 | 
				
			||||||
    Ari
 | 
					    Ari
 | 
				
			||||||
    Arisaka Mayuki
 | 
					    Arisaka Mayuki
 | 
				
			||||||
    Arthur S. Muszynski
 | 
					    Arthur S. Muszynski
 | 
				
			||||||
| 
						 | 
					@ -269,13 +283,11 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Liam Smyth
 | 
					    Liam Smyth
 | 
				
			||||||
    LoparPanda
 | 
					    LoparPanda
 | 
				
			||||||
    Martin Gulliksson
 | 
					    Martin Gulliksson
 | 
				
			||||||
    Martin Soucek
 | 
					 | 
				
			||||||
    Michael Dürwald
 | 
					    Michael Dürwald
 | 
				
			||||||
    Michael Policastro
 | 
					    Michael Policastro
 | 
				
			||||||
    n00sh
 | 
					    n00sh
 | 
				
			||||||
    Nicolás Monner Sans
 | 
					    Nicolás Monner Sans
 | 
				
			||||||
    Nikita Rotskov
 | 
					    Nikita Rotskov
 | 
				
			||||||
    Nikola Whallon
 | 
					 | 
				
			||||||
    Oliver Dick
 | 
					    Oliver Dick
 | 
				
			||||||
    Patrick Wuttke
 | 
					    Patrick Wuttke
 | 
				
			||||||
    Pete Goodwin
 | 
					    Pete Goodwin
 | 
				
			||||||
| 
						 | 
					@ -298,7 +310,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    VoidPointer
 | 
					    VoidPointer
 | 
				
			||||||
    Yifan Lai
 | 
					    Yifan Lai
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Aaron Mayfield
 | 
					 | 
				
			||||||
    Adam Carr
 | 
					    Adam Carr
 | 
				
			||||||
    Adam Smeltzer
 | 
					    Adam Smeltzer
 | 
				
			||||||
    Adisibio
 | 
					    Adisibio
 | 
				
			||||||
| 
						 | 
					@ -315,7 +326,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Ano Nim
 | 
					    Ano Nim
 | 
				
			||||||
    Arch Toasty
 | 
					    Arch Toasty
 | 
				
			||||||
    Arda Erol
 | 
					    Arda Erol
 | 
				
			||||||
    A Really Tall Horse
 | 
					 | 
				
			||||||
    Arturo Rosales
 | 
					    Arturo Rosales
 | 
				
			||||||
    Ash K
 | 
					    Ash K
 | 
				
			||||||
    Aubrey Falconer
 | 
					    Aubrey Falconer
 | 
				
			||||||
| 
						 | 
					@ -343,6 +353,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Dakota Watkins
 | 
					    Dakota Watkins
 | 
				
			||||||
    Daniele Tolomelli
 | 
					    Daniele Tolomelli
 | 
				
			||||||
    Daniel Ramos
 | 
					    Daniel Ramos
 | 
				
			||||||
 | 
					    Daren Scot Wilson
 | 
				
			||||||
    Dave Jansen
 | 
					    Dave Jansen
 | 
				
			||||||
    Davesnothere
 | 
					    Davesnothere
 | 
				
			||||||
    David Baker
 | 
					    David Baker
 | 
				
			||||||
| 
						 | 
					@ -361,12 +372,11 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Eric Stokes
 | 
					    Eric Stokes
 | 
				
			||||||
    Eric Williams
 | 
					    Eric Williams
 | 
				
			||||||
    Erkki Seppälä
 | 
					    Erkki Seppälä
 | 
				
			||||||
    Ewan Holmes
 | 
					 | 
				
			||||||
    Felix Adam
 | 
					 | 
				
			||||||
    Frank
 | 
					    Frank
 | 
				
			||||||
    Frying☆Pan
 | 
					    Frying☆Pan
 | 
				
			||||||
    Game Endeavor
 | 
					    Game Endeavor
 | 
				
			||||||
    gamerminstrel
 | 
					    gamerminstrel
 | 
				
			||||||
 | 
					    Garrett S
 | 
				
			||||||
    Gary Thomas
 | 
					    Gary Thomas
 | 
				
			||||||
    gebba
 | 
					    gebba
 | 
				
			||||||
    Greyson Richey
 | 
					    Greyson Richey
 | 
				
			||||||
| 
						 | 
					@ -385,7 +395,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Jamie Massey
 | 
					    Jamie Massey
 | 
				
			||||||
    JARKKO PARVIAINEN
 | 
					    JARKKO PARVIAINEN
 | 
				
			||||||
    Jason Evans
 | 
					    Jason Evans
 | 
				
			||||||
    Joakim Askenbäck
 | 
					 | 
				
			||||||
    Jonas
 | 
					    Jonas
 | 
				
			||||||
    Jonas Arndt
 | 
					    Jonas Arndt
 | 
				
			||||||
    Jonas Yamazaki
 | 
					    Jonas Yamazaki
 | 
				
			||||||
| 
						 | 
					@ -421,7 +430,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Martin Holas
 | 
					    Martin Holas
 | 
				
			||||||
    Martin Liška
 | 
					    Martin Liška
 | 
				
			||||||
    Martin Trbola
 | 
					    Martin Trbola
 | 
				
			||||||
    Matěj Drábek
 | 
					 | 
				
			||||||
    Mathieu
 | 
					    Mathieu
 | 
				
			||||||
    Matt Edwards
 | 
					    Matt Edwards
 | 
				
			||||||
    Maverick
 | 
					    Maverick
 | 
				
			||||||
| 
						 | 
					@ -441,7 +449,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Neofytos Chimonas
 | 
					    Neofytos Chimonas
 | 
				
			||||||
    Nerdforge
 | 
					    Nerdforge
 | 
				
			||||||
    Nerdyninja
 | 
					    Nerdyninja
 | 
				
			||||||
    Nick Eldrenkamp
 | 
					 | 
				
			||||||
    Nik Rudenko
 | 
					    Nik Rudenko
 | 
				
			||||||
    Noel Billig
 | 
					    Noel Billig
 | 
				
			||||||
    ozrk
 | 
					    ozrk
 | 
				
			||||||
| 
						 | 
					@ -450,7 +457,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Patrick Nafarrete
 | 
					    Patrick Nafarrete
 | 
				
			||||||
    Paul Black
 | 
					    Paul Black
 | 
				
			||||||
    Paul Gieske
 | 
					    Paul Gieske
 | 
				
			||||||
    Paul Mozet
 | 
					 | 
				
			||||||
    Pete
 | 
					    Pete
 | 
				
			||||||
    Phoenix Jauregui
 | 
					    Phoenix Jauregui
 | 
				
			||||||
    Pierre Caye
 | 
					    Pierre Caye
 | 
				
			||||||
| 
						 | 
					@ -462,7 +468,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    Raghava Kovvali
 | 
					    Raghava Kovvali
 | 
				
			||||||
    Ragnar Pettersson
 | 
					    Ragnar Pettersson
 | 
				
			||||||
    Rammeow
 | 
					    Rammeow
 | 
				
			||||||
    Rebecca H
 | 
					 | 
				
			||||||
    Richard Hayes
 | 
					    Richard Hayes
 | 
				
			||||||
    Riley
 | 
					    Riley
 | 
				
			||||||
    RobotCritter
 | 
					    RobotCritter
 | 
				
			||||||
| 
						 | 
					@ -508,7 +513,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
    ケルベロス
 | 
					    ケルベロス
 | 
				
			||||||
    貴宏 小松
 | 
					    貴宏 小松
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    And 181 anonymous donors
 | 
					    And 176 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Silver and bronze donors
 | 
					## Silver and bronze donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,14 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EnsureSConsVersion(3, 1, 2)
 | 
					EnsureSConsVersion(4, 0)
 | 
				
			||||||
EnsurePythonVersion(3, 6)
 | 
					EnsurePythonVersion(3, 8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# System
 | 
					# System
 | 
				
			||||||
import atexit
 | 
					 | 
				
			||||||
import glob
 | 
					import glob
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import pickle
 | 
					import pickle
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
from collections import OrderedDict
 | 
					from collections import OrderedDict
 | 
				
			||||||
from importlib.util import module_from_spec, spec_from_file_location
 | 
					from importlib.util import module_from_spec, spec_from_file_location
 | 
				
			||||||
from types import ModuleType
 | 
					from types import ModuleType
 | 
				
			||||||
| 
						 | 
					@ -51,37 +50,20 @@ _helper_module("platform_methods", "platform_methods.py")
 | 
				
			||||||
_helper_module("version", "version.py")
 | 
					_helper_module("version", "version.py")
 | 
				
			||||||
_helper_module("core.core_builders", "core/core_builders.py")
 | 
					_helper_module("core.core_builders", "core/core_builders.py")
 | 
				
			||||||
_helper_module("main.main_builders", "main/main_builders.py")
 | 
					_helper_module("main.main_builders", "main/main_builders.py")
 | 
				
			||||||
 | 
					_helper_module("misc.utility.color", "misc/utility/color.py")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Local
 | 
					# Local
 | 
				
			||||||
import gles3_builders
 | 
					import gles3_builders
 | 
				
			||||||
import glsl_builders
 | 
					import glsl_builders
 | 
				
			||||||
import methods
 | 
					import methods
 | 
				
			||||||
import scu_builders
 | 
					import scu_builders
 | 
				
			||||||
from methods import print_error, print_warning
 | 
					from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning
 | 
				
			||||||
from platform_methods import architecture_aliases, architectures
 | 
					from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ARGUMENTS.get("target", "editor") == "editor":
 | 
					if ARGUMENTS.get("target", "editor") == "editor":
 | 
				
			||||||
    _helper_module("editor.editor_builders", "editor/editor_builders.py")
 | 
					    _helper_module("editor.editor_builders", "editor/editor_builders.py")
 | 
				
			||||||
    _helper_module("editor.template_builders", "editor/template_builders.py")
 | 
					    _helper_module("editor.template_builders", "editor/template_builders.py")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
 | 
					 | 
				
			||||||
# <https://github.com/python/cpython/issues/73245>
 | 
					 | 
				
			||||||
if sys.stdout.isatty() and sys.platform == "win32":
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        from ctypes import WinError, byref, windll  # type: ignore
 | 
					 | 
				
			||||||
        from ctypes.wintypes import DWORD  # type: ignore
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
 | 
					 | 
				
			||||||
        mode = DWORD(0)
 | 
					 | 
				
			||||||
        if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
 | 
					 | 
				
			||||||
            raise WinError()
 | 
					 | 
				
			||||||
        mode = DWORD(mode.value | 4)
 | 
					 | 
				
			||||||
        if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
 | 
					 | 
				
			||||||
            raise WinError()
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        methods._colorize = False
 | 
					 | 
				
			||||||
        print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Scan possible build platforms
 | 
					# Scan possible build platforms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
platform_list = []  # list of platforms
 | 
					platform_list = []  # list of platforms
 | 
				
			||||||
| 
						 | 
					@ -91,8 +73,6 @@ platform_doc_class_path = {}
 | 
				
			||||||
platform_exporters = []
 | 
					platform_exporters = []
 | 
				
			||||||
platform_apis = []
 | 
					platform_apis = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
time_at_start = time.time()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
for x in sorted(glob.glob("platform/*")):
 | 
					for x in sorted(glob.glob("platform/*")):
 | 
				
			||||||
    if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
 | 
					    if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
 | 
				
			||||||
        continue
 | 
					        continue
 | 
				
			||||||
| 
						 | 
					@ -127,34 +107,21 @@ for x in sorted(glob.glob("platform/*")):
 | 
				
			||||||
    sys.path.remove(tmppath)
 | 
					    sys.path.remove(tmppath)
 | 
				
			||||||
    sys.modules.pop("detect")
 | 
					    sys.modules.pop("detect")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
custom_tools = ["default"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if platform_arg == "android":
 | 
					 | 
				
			||||||
    custom_tools = ["clang", "clang++", "as", "ar", "link"]
 | 
					 | 
				
			||||||
elif platform_arg == "web":
 | 
					 | 
				
			||||||
    # Use generic POSIX build toolchain for Emscripten.
 | 
					 | 
				
			||||||
    custom_tools = ["cc", "c++", "ar", "link", "textfile", "zip"]
 | 
					 | 
				
			||||||
elif os.name == "nt" and methods.get_cmdline_bool("use_mingw", False):
 | 
					 | 
				
			||||||
    custom_tools = ["mingw"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# We let SCons build its default ENV as it includes OS-specific things which we don't
 | 
					# We let SCons build its default ENV as it includes OS-specific things which we don't
 | 
				
			||||||
# want to have to pull in manually.
 | 
					# want to have to pull in manually. However we enforce no "tools", which we register
 | 
				
			||||||
 | 
					# further down after parsing our platform-specific configuration.
 | 
				
			||||||
# Then we prepend PATH to make it take precedence, while preserving SCons' own entries.
 | 
					# Then we prepend PATH to make it take precedence, while preserving SCons' own entries.
 | 
				
			||||||
env = Environment(tools=custom_tools)
 | 
					env = Environment(tools=[])
 | 
				
			||||||
env.PrependENVPath("PATH", os.getenv("PATH"))
 | 
					env.PrependENVPath("PATH", os.getenv("PATH"))
 | 
				
			||||||
env.PrependENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
 | 
					env.PrependENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
 | 
				
			||||||
if "TERM" in os.environ:  # Used for colored output.
 | 
					if "TERM" in os.environ:  # Used for colored output.
 | 
				
			||||||
    env["ENV"]["TERM"] = os.environ["TERM"]
 | 
					    env["ENV"]["TERM"] = os.environ["TERM"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env.disabled_modules = []
 | 
					env.disabled_modules = set()
 | 
				
			||||||
env.module_version_string = ""
 | 
					env.module_version_string = ""
 | 
				
			||||||
env.msvc = False
 | 
					env.msvc = False
 | 
				
			||||||
env.scons_version = env._get_major_minor_revision(scons_raw_version)
 | 
					env.scons_version = env._get_major_minor_revision(scons_raw_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env.__class__.disable_module = methods.disable_module
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
env.__class__.add_module_version_string = methods.add_module_version_string
 | 
					env.__class__.add_module_version_string = methods.add_module_version_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env.__class__.add_source_files = methods.add_source_files
 | 
					env.__class__.add_source_files = methods.add_source_files
 | 
				
			||||||
| 
						 | 
					@ -190,11 +157,7 @@ if profile:
 | 
				
			||||||
opts = Variables(customs, ARGUMENTS)
 | 
					opts = Variables(customs, ARGUMENTS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Target build options
 | 
					# Target build options
 | 
				
			||||||
if env.scons_version >= (4, 3):
 | 
					opts.Add((["platform", "p"], "Target platform (%s)" % "|".join(platform_list), ""))
 | 
				
			||||||
    opts.Add(["platform", "p"], "Target platform (%s)" % "|".join(platform_list), "")
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    opts.Add("platform", "Target platform (%s)" % "|".join(platform_list), "")
 | 
					 | 
				
			||||||
    opts.Add("p", "Alias for 'platform'", "")
 | 
					 | 
				
			||||||
opts.Add(EnumVariable("target", "Compilation target", "editor", ("editor", "template_release", "template_debug")))
 | 
					opts.Add(EnumVariable("target", "Compilation target", "editor", ("editor", "template_release", "template_debug")))
 | 
				
			||||||
opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
 | 
					opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
 | 
				
			||||||
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
 | 
					opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
 | 
				
			||||||
| 
						 | 
					@ -217,11 +180,12 @@ opts.Add(BoolVariable("threads", "Enable threading support", True))
 | 
				
			||||||
opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
 | 
					opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
 | 
				
			||||||
opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double")))
 | 
					opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double")))
 | 
				
			||||||
opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
 | 
					opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
 | 
				
			||||||
opts.Add(BoolVariable("brotli", "Enable Brotli for decompresson and WOFF2 fonts support", True))
 | 
					opts.Add(BoolVariable("brotli", "Enable Brotli for decompression and WOFF2 fonts support", True))
 | 
				
			||||||
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
 | 
					opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver on supported platforms", False))
 | 
				
			||||||
opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
 | 
					opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
 | 
				
			||||||
opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
 | 
					opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
 | 
				
			||||||
opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver", False))
 | 
					opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False))
 | 
				
			||||||
 | 
					opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False))
 | 
				
			||||||
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
 | 
					opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
 | 
				
			||||||
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
 | 
					opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
 | 
				
			||||||
opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
 | 
					opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
 | 
				
			||||||
| 
						 | 
					@ -229,11 +193,22 @@ opts.Add("custom_modules", "A list of comma-separated directory paths containing
 | 
				
			||||||
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
 | 
					opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Advanced options
 | 
					# Advanced options
 | 
				
			||||||
opts.Add(BoolVariable("dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes", False))
 | 
					opts.Add(
 | 
				
			||||||
 | 
					    BoolVariable(
 | 
				
			||||||
 | 
					        "dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes strict_checks=yes", False
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
opts.Add(BoolVariable("tests", "Build the unit tests", False))
 | 
					opts.Add(BoolVariable("tests", "Build the unit tests", False))
 | 
				
			||||||
opts.Add(BoolVariable("fast_unsafe", "Enable unsafe options for faster rebuilds", False))
 | 
					opts.Add(BoolVariable("fast_unsafe", "Enable unsafe options for faster rebuilds", False))
 | 
				
			||||||
opts.Add(BoolVariable("ninja", "Use the ninja backend for faster rebuilds", False))
 | 
					opts.Add(BoolVariable("ninja", "Use the ninja backend for faster rebuilds", False))
 | 
				
			||||||
 | 
					opts.Add(BoolVariable("ninja_auto_run", "Run ninja automatically after generating the ninja file", True))
 | 
				
			||||||
 | 
					opts.Add("ninja_file", "Path to the generated ninja file", "build.ninja")
 | 
				
			||||||
opts.Add(BoolVariable("compiledb", "Generate compilation DB (`compile_commands.json`) for external tools", False))
 | 
					opts.Add(BoolVariable("compiledb", "Generate compilation DB (`compile_commands.json`) for external tools", False))
 | 
				
			||||||
 | 
					opts.Add(
 | 
				
			||||||
 | 
					    "num_jobs",
 | 
				
			||||||
 | 
					    "Use up to N jobs when compiling (equivalent to `-j N`). Defaults to max jobs - 1. Ignored if -j is used.",
 | 
				
			||||||
 | 
					    "",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
 | 
					opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
 | 
				
			||||||
opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True))
 | 
					opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True))
 | 
				
			||||||
opts.Add(EnumVariable("warnings", "Level of compilation warnings", "all", ("extra", "all", "moderate", "no")))
 | 
					opts.Add(EnumVariable("warnings", "Level of compilation warnings", "all", ("extra", "all", "moderate", "no")))
 | 
				
			||||||
| 
						 | 
					@ -254,10 +229,13 @@ opts.Add(
 | 
				
			||||||
    "",
 | 
					    "",
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
 | 
					opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
 | 
				
			||||||
 | 
					opts.Add(BoolVariable("strict_checks", "Enforce stricter checks (debug option)", False))
 | 
				
			||||||
opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
 | 
					opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
 | 
				
			||||||
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
 | 
					opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
 | 
				
			||||||
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
 | 
					opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
 | 
				
			||||||
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
 | 
					opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
 | 
				
			||||||
 | 
					opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "")
 | 
				
			||||||
 | 
					opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Thirdparty libraries
 | 
					# Thirdparty libraries
 | 
				
			||||||
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
 | 
					opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
 | 
				
			||||||
| 
						 | 
					@ -285,7 +263,6 @@ opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built-
 | 
				
			||||||
opts.Add(BoolVariable("builtin_recastnavigation", "Use the built-in Recast navigation library", True))
 | 
					opts.Add(BoolVariable("builtin_recastnavigation", "Use the built-in Recast navigation library", True))
 | 
				
			||||||
opts.Add(BoolVariable("builtin_rvo2_2d", "Use the built-in RVO2 2D library", True))
 | 
					opts.Add(BoolVariable("builtin_rvo2_2d", "Use the built-in RVO2 2D library", True))
 | 
				
			||||||
opts.Add(BoolVariable("builtin_rvo2_3d", "Use the built-in RVO2 3D library", True))
 | 
					opts.Add(BoolVariable("builtin_rvo2_3d", "Use the built-in RVO2 3D library", True))
 | 
				
			||||||
opts.Add(BoolVariable("builtin_squish", "Use the built-in squish library", True))
 | 
					 | 
				
			||||||
opts.Add(BoolVariable("builtin_xatlas", "Use the built-in xatlas library", True))
 | 
					opts.Add(BoolVariable("builtin_xatlas", "Use the built-in xatlas library", True))
 | 
				
			||||||
opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True))
 | 
					opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True))
 | 
				
			||||||
opts.Add(BoolVariable("builtin_zstd", "Use the built-in Zstd library", True))
 | 
					opts.Add(BoolVariable("builtin_zstd", "Use the built-in Zstd library", True))
 | 
				
			||||||
| 
						 | 
					@ -309,6 +286,9 @@ opts.Add("rcflags", "Custom flags for Windows resource compiler")
 | 
				
			||||||
# in following code (especially platform and custom_modules).
 | 
					# in following code (especially platform and custom_modules).
 | 
				
			||||||
opts.Update(env)
 | 
					opts.Update(env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Setup caching logic early to catch everything.
 | 
				
			||||||
 | 
					methods.prepare_cache(env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy custom environment variables if set.
 | 
					# Copy custom environment variables if set.
 | 
				
			||||||
if env["import_env_vars"]:
 | 
					if env["import_env_vars"]:
 | 
				
			||||||
    for env_var in str(env["import_env_vars"]).split(","):
 | 
					    for env_var in str(env["import_env_vars"]).split(","):
 | 
				
			||||||
| 
						 | 
					@ -317,10 +297,7 @@ if env["import_env_vars"]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Platform selection: validate input, and add options.
 | 
					# Platform selection: validate input, and add options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env.scons_version < (4, 3) and not env["platform"]:
 | 
					if not env["platform"]:
 | 
				
			||||||
    env["platform"] = env["p"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if env["platform"] == "":
 | 
					 | 
				
			||||||
    # Missing `platform` argument, try to detect platform automatically
 | 
					    # Missing `platform` argument, try to detect platform automatically
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
        sys.platform.startswith("linux")
 | 
					        sys.platform.startswith("linux")
 | 
				
			||||||
| 
						 | 
					@ -335,38 +312,29 @@ if env["platform"] == "":
 | 
				
			||||||
    elif sys.platform == "win32":
 | 
					    elif sys.platform == "win32":
 | 
				
			||||||
        env["platform"] = "windows"
 | 
					        env["platform"] = "windows"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if env["platform"] != "":
 | 
					    if env["platform"]:
 | 
				
			||||||
        print(f'Automatically detected platform: {env["platform"]}')
 | 
					        print(f"Automatically detected platform: {env['platform']}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env["platform"] == "osx":
 | 
					# Deprecated aliases kept for compatibility.
 | 
				
			||||||
    # Deprecated alias kept for compatibility.
 | 
					if env["platform"] in compatibility_platform_aliases:
 | 
				
			||||||
    print_warning('Platform "osx" has been renamed to "macos" in Godot 4. Building for platform "macos".')
 | 
					    alias = env["platform"]
 | 
				
			||||||
    env["platform"] = "macos"
 | 
					    platform = compatibility_platform_aliases[alias]
 | 
				
			||||||
 | 
					    print_warning(
 | 
				
			||||||
 | 
					        f'Platform "{alias}" has been renamed to "{platform}" in Godot 4. Building for platform "{platform}".'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    env["platform"] = platform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env["platform"] == "iphone":
 | 
					# Alias for convenience.
 | 
				
			||||||
    # Deprecated alias kept for compatibility.
 | 
					if env["platform"] in ["linux", "bsd"]:
 | 
				
			||||||
    print_warning('Platform "iphone" has been renamed to "ios" in Godot 4. Building for platform "ios".')
 | 
					 | 
				
			||||||
    env["platform"] = "ios"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if env["platform"] in ["linux", "bsd", "x11"]:
 | 
					 | 
				
			||||||
    if env["platform"] == "x11":
 | 
					 | 
				
			||||||
        # Deprecated alias kept for compatibility.
 | 
					 | 
				
			||||||
        print_warning('Platform "x11" has been renamed to "linuxbsd" in Godot 4. Building for platform "linuxbsd".')
 | 
					 | 
				
			||||||
    # Alias for convenience.
 | 
					 | 
				
			||||||
    env["platform"] = "linuxbsd"
 | 
					    env["platform"] = "linuxbsd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env["platform"] == "javascript":
 | 
					 | 
				
			||||||
    # Deprecated alias kept for compatibility.
 | 
					 | 
				
			||||||
    print_warning('Platform "javascript" has been renamed to "web" in Godot 4. Building for platform "web".')
 | 
					 | 
				
			||||||
    env["platform"] = "web"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if env["platform"] not in platform_list:
 | 
					if env["platform"] not in platform_list:
 | 
				
			||||||
    text = "The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list))
 | 
					    text = "The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list))
 | 
				
			||||||
    text += "Please run SCons again and select a valid platform: platform=<string>."
 | 
					    text += "Please run SCons again and select a valid platform: platform=<string>."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if env["platform"] == "list":
 | 
					    if env["platform"] == "list":
 | 
				
			||||||
        print(text)
 | 
					        print(text)
 | 
				
			||||||
    elif env["platform"] == "":
 | 
					    elif not env["platform"]:
 | 
				
			||||||
        print_error("Could not detect platform automatically.\n" + text)
 | 
					        print_error("Could not detect platform automatically.\n" + text)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        print_error(f'Invalid target platform "{env["platform"]}".\n' + text)
 | 
					        print_error(f'Invalid target platform "{env["platform"]}".\n' + text)
 | 
				
			||||||
| 
						 | 
					@ -375,8 +343,7 @@ if env["platform"] not in platform_list:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Add platform-specific options.
 | 
					# Add platform-specific options.
 | 
				
			||||||
if env["platform"] in platform_opts:
 | 
					if env["platform"] in platform_opts:
 | 
				
			||||||
    for opt in platform_opts[env["platform"]]:
 | 
					    opts.AddVariables(*platform_opts[env["platform"]])
 | 
				
			||||||
        opts.Add(opt)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Platform-specific flags.
 | 
					# Platform-specific flags.
 | 
				
			||||||
# These can sometimes override default options, so they need to be processed
 | 
					# These can sometimes override default options, so they need to be processed
 | 
				
			||||||
| 
						 | 
					@ -432,12 +399,11 @@ for name, path in modules_detected.items():
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        enabled = False
 | 
					        enabled = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
 | 
					    opts.Add(BoolVariable(f"module_{name}_enabled", f"Enable module '{name}'", enabled))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Add module-specific options.
 | 
					    # Add module-specific options.
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        for opt in config.get_opts(env["platform"]):
 | 
					        opts.AddVariables(*config.get_opts(env["platform"]))
 | 
				
			||||||
            opts.Add(opt)
 | 
					 | 
				
			||||||
    except AttributeError:
 | 
					    except AttributeError:
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -450,6 +416,23 @@ env.modules_detected = modules_detected
 | 
				
			||||||
opts.Update(env, {**ARGUMENTS, **env.Dictionary()})
 | 
					opts.Update(env, {**ARGUMENTS, **env.Dictionary()})
 | 
				
			||||||
Help(opts.GenerateHelpText(env))
 | 
					Help(opts.GenerateHelpText(env))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: Tool assignment happening at this stage is a direct consequence of getting the platform logic AFTER the SCons
 | 
				
			||||||
 | 
					# environment was already been constructed. Fixing this would require a broader refactor where all options are setup
 | 
				
			||||||
 | 
					# ahead of time with native validator/converter functions.
 | 
				
			||||||
 | 
					tmppath = "./platform/" + env["platform"]
 | 
				
			||||||
 | 
					sys.path.insert(0, tmppath)
 | 
				
			||||||
 | 
					import detect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					custom_tools = ["default"]
 | 
				
			||||||
 | 
					try:  # Platform custom tools are optional
 | 
				
			||||||
 | 
					    custom_tools = detect.get_tools(env)
 | 
				
			||||||
 | 
					except AttributeError:
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					for tool in custom_tools:
 | 
				
			||||||
 | 
					    env.Tool(tool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# add default include paths
 | 
					# add default include paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env.Prepend(CPPPATH=["#"])
 | 
					env.Prepend(CPPPATH=["#"])
 | 
				
			||||||
| 
						 | 
					@ -496,14 +479,19 @@ else:
 | 
				
			||||||
    # Disable assert() for production targets (only used in thirdparty code).
 | 
					    # Disable assert() for production targets (only used in thirdparty code).
 | 
				
			||||||
    env.Append(CPPDEFINES=["NDEBUG"])
 | 
					    env.Append(CPPDEFINES=["NDEBUG"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This is not part of fast_unsafe because the only downside it has compared to
 | 
				
			||||||
 | 
					# the default is that SCons won't mark files that were changed in the last second
 | 
				
			||||||
 | 
					# as different. This is unlikely to be a problem in any real situation as just booting
 | 
				
			||||||
 | 
					# up scons takes more than that time.
 | 
				
			||||||
 | 
					# Renamed to `content-timestamp` in SCons >= 4.2, keeping MD5 for compat.
 | 
				
			||||||
 | 
					env.Decider("MD5-timestamp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SCons speed optimization controlled by the `fast_unsafe` option, which provide
 | 
					# SCons speed optimization controlled by the `fast_unsafe` option, which provide
 | 
				
			||||||
# more than 10 s speed up for incremental rebuilds.
 | 
					# more than 10 s speed up for incremental rebuilds.
 | 
				
			||||||
# Unsafe as they reduce the certainty of rebuilding all changed files, so it's
 | 
					# Unsafe as they reduce the certainty of rebuilding all changed files, so it's
 | 
				
			||||||
# enabled by default for `debug` builds, and can be overridden from command line.
 | 
					# enabled by default for `debug` builds, and can be overridden from command line.
 | 
				
			||||||
# Ref: https://github.com/SCons/scons/wiki/GoFastButton
 | 
					# Ref: https://github.com/SCons/scons/wiki/GoFastButton
 | 
				
			||||||
if methods.get_cmdline_bool("fast_unsafe", env.dev_build):
 | 
					if methods.get_cmdline_bool("fast_unsafe", env.dev_build):
 | 
				
			||||||
    # Renamed to `content-timestamp` in SCons >= 4.2, keeping MD5 for compat.
 | 
					 | 
				
			||||||
    env.Decider("MD5-timestamp")
 | 
					 | 
				
			||||||
    env.SetOption("implicit_cache", 1)
 | 
					    env.SetOption("implicit_cache", 1)
 | 
				
			||||||
    env.SetOption("max_drift", 60)
 | 
					    env.SetOption("max_drift", 60)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -526,10 +514,6 @@ if not env["deprecated"]:
 | 
				
			||||||
if env["precision"] == "double":
 | 
					if env["precision"] == "double":
 | 
				
			||||||
    env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
 | 
					    env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tmppath = "./platform/" + env["platform"]
 | 
					 | 
				
			||||||
sys.path.insert(0, tmppath)
 | 
					 | 
				
			||||||
import detect
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Default num_jobs to local cpu count if not user specified.
 | 
					# Default num_jobs to local cpu count if not user specified.
 | 
				
			||||||
# SCons has a peculiarity where user-specified options won't be overridden
 | 
					# SCons has a peculiarity where user-specified options won't be overridden
 | 
				
			||||||
# by SetOption, so we can rely on this to know if we should use our default.
 | 
					# by SetOption, so we can rely on this to know if we should use our default.
 | 
				
			||||||
| 
						 | 
					@ -537,16 +521,22 @@ initial_num_jobs = env.GetOption("num_jobs")
 | 
				
			||||||
altered_num_jobs = initial_num_jobs + 1
 | 
					altered_num_jobs = initial_num_jobs + 1
 | 
				
			||||||
env.SetOption("num_jobs", altered_num_jobs)
 | 
					env.SetOption("num_jobs", altered_num_jobs)
 | 
				
			||||||
if env.GetOption("num_jobs") == altered_num_jobs:
 | 
					if env.GetOption("num_jobs") == altered_num_jobs:
 | 
				
			||||||
    cpu_count = os.cpu_count()
 | 
					    num_jobs = env.get("num_jobs", "")
 | 
				
			||||||
    if cpu_count is None:
 | 
					    if str(num_jobs).isdigit() and int(num_jobs) > 0:
 | 
				
			||||||
        print_warning("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.")
 | 
					        env.SetOption("num_jobs", num_jobs)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
 | 
					        cpu_count = os.cpu_count()
 | 
				
			||||||
        print(
 | 
					        if cpu_count is None:
 | 
				
			||||||
            "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument."
 | 
					            print_warning(
 | 
				
			||||||
            % (cpu_count, safer_cpu_count)
 | 
					                "Couldn't auto-detect CPU count to configure build parallelism. Specify it with the `-j` or `num_jobs` arguments."
 | 
				
			||||||
        )
 | 
					            )
 | 
				
			||||||
        env.SetOption("num_jobs", safer_cpu_count)
 | 
					        else:
 | 
				
			||||||
 | 
					            safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
 | 
				
			||||||
 | 
					            print(
 | 
				
			||||||
 | 
					                "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the `-j` or `num_jobs` arguments."
 | 
				
			||||||
 | 
					                % (cpu_count, safer_cpu_count)
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            env.SetOption("num_jobs", safer_cpu_count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env.extra_suffix = ""
 | 
					env.extra_suffix = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -566,7 +556,7 @@ env.Append(RCFLAGS=env.get("rcflags", "").split())
 | 
				
			||||||
# Feature build profile
 | 
					# Feature build profile
 | 
				
			||||||
env.disabled_classes = []
 | 
					env.disabled_classes = []
 | 
				
			||||||
if env["build_profile"] != "":
 | 
					if env["build_profile"] != "":
 | 
				
			||||||
    print('Using feature build profile: "{}"'.format(env["build_profile"]))
 | 
					    print(f'Using feature build profile: "{env["build_profile"]}"')
 | 
				
			||||||
    import json
 | 
					    import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
| 
						 | 
					@ -578,7 +568,7 @@ if env["build_profile"] != "":
 | 
				
			||||||
            for c in dbo:
 | 
					            for c in dbo:
 | 
				
			||||||
                env[c] = dbo[c]
 | 
					                env[c] = dbo[c]
 | 
				
			||||||
    except json.JSONDecodeError:
 | 
					    except json.JSONDecodeError:
 | 
				
			||||||
        print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
 | 
					        print_error(f'Failed to open feature build profile: "{env["build_profile"]}"')
 | 
				
			||||||
        Exit(255)
 | 
					        Exit(255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 'dev_mode' and 'production' are aliases to set default options if they haven't been
 | 
					# 'dev_mode' and 'production' are aliases to set default options if they haven't been
 | 
				
			||||||
| 
						 | 
					@ -588,12 +578,18 @@ if env["dev_mode"]:
 | 
				
			||||||
    env["warnings"] = ARGUMENTS.get("warnings", "extra")
 | 
					    env["warnings"] = ARGUMENTS.get("warnings", "extra")
 | 
				
			||||||
    env["werror"] = methods.get_cmdline_bool("werror", True)
 | 
					    env["werror"] = methods.get_cmdline_bool("werror", True)
 | 
				
			||||||
    env["tests"] = methods.get_cmdline_bool("tests", True)
 | 
					    env["tests"] = methods.get_cmdline_bool("tests", True)
 | 
				
			||||||
 | 
					    env["strict_checks"] = methods.get_cmdline_bool("strict_checks", True)
 | 
				
			||||||
if env["production"]:
 | 
					if env["production"]:
 | 
				
			||||||
    env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
 | 
					    env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
 | 
				
			||||||
    env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
 | 
					    env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
 | 
				
			||||||
 | 
					    if env["platform"] == "android":
 | 
				
			||||||
 | 
					        env["swappy"] = methods.get_cmdline_bool("swappy", True)
 | 
				
			||||||
    # LTO "auto" means we handle the preferred option in each platform detect.py.
 | 
					    # LTO "auto" means we handle the preferred option in each platform detect.py.
 | 
				
			||||||
    env["lto"] = ARGUMENTS.get("lto", "auto")
 | 
					    env["lto"] = ARGUMENTS.get("lto", "auto")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if env["strict_checks"]:
 | 
				
			||||||
 | 
					    env.Append(CPPDEFINES=["STRICT_CHECKS"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Run SCU file generation script if in a SCU build.
 | 
					# Run SCU file generation script if in a SCU build.
 | 
				
			||||||
if env["scu_build"]:
 | 
					if env["scu_build"]:
 | 
				
			||||||
    max_includes_per_scu = 8
 | 
					    max_includes_per_scu = 8
 | 
				
			||||||
| 
						 | 
					@ -613,28 +609,21 @@ detect.configure(env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
print(f'Building for platform "{env["platform"]}", architecture "{env["arch"]}", target "{env["target"]}".')
 | 
					print(f'Building for platform "{env["platform"]}", architecture "{env["arch"]}", target "{env["target"]}".')
 | 
				
			||||||
if env.dev_build:
 | 
					if env.dev_build:
 | 
				
			||||||
    print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
 | 
					    print_info("Developer build, with debug optimization level and debug symbols (unless overridden).")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Enforce our minimal compiler version requirements
 | 
					# Enforce our minimal compiler version requirements
 | 
				
			||||||
cc_version = methods.get_compiler_version(env) or {
 | 
					cc_version = methods.get_compiler_version(env)
 | 
				
			||||||
    "major": None,
 | 
					cc_version_major = cc_version["major"]
 | 
				
			||||||
    "minor": None,
 | 
					cc_version_minor = cc_version["minor"]
 | 
				
			||||||
    "patch": None,
 | 
					cc_version_metadata1 = cc_version["metadata1"]
 | 
				
			||||||
    "metadata1": None,
 | 
					 | 
				
			||||||
    "metadata2": None,
 | 
					 | 
				
			||||||
    "date": None,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
cc_version_major = int(cc_version["major"] or -1)
 | 
					 | 
				
			||||||
cc_version_minor = int(cc_version["minor"] or -1)
 | 
					 | 
				
			||||||
cc_version_metadata1 = cc_version["metadata1"] or ""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if methods.using_gcc(env):
 | 
					if cc_version_major == -1:
 | 
				
			||||||
    if cc_version_major == -1:
 | 
					    print_warning(
 | 
				
			||||||
        print_warning(
 | 
					        "Couldn't detect compiler version, skipping version checks. "
 | 
				
			||||||
            "Couldn't detect compiler version, skipping version checks. "
 | 
					        "Build may fail if the compiler doesn't support C++17 fully."
 | 
				
			||||||
            "Build may fail if the compiler doesn't support C++17 fully."
 | 
					    )
 | 
				
			||||||
        )
 | 
					elif methods.using_gcc(env):
 | 
				
			||||||
    elif cc_version_major < 9:
 | 
					    if cc_version_major < 9:
 | 
				
			||||||
        print_error(
 | 
					        print_error(
 | 
				
			||||||
            "Detected GCC version older than 9, which does not fully support "
 | 
					            "Detected GCC version older than 9, which does not fully support "
 | 
				
			||||||
            "C++17, or has bugs when compiling Godot. Supported versions are 9 "
 | 
					            "C++17, or has bugs when compiling Godot. Supported versions are 9 "
 | 
				
			||||||
| 
						 | 
					@ -650,45 +639,68 @@ if methods.using_gcc(env):
 | 
				
			||||||
            "to switch to posix threads."
 | 
					            "to switch to posix threads."
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        Exit(255)
 | 
					        Exit(255)
 | 
				
			||||||
    if env["debug_paths_relative"] and cc_version_major < 8:
 | 
					 | 
				
			||||||
        print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
 | 
					 | 
				
			||||||
        env["debug_paths_relative"] = False
 | 
					 | 
				
			||||||
elif methods.using_clang(env):
 | 
					elif methods.using_clang(env):
 | 
				
			||||||
    if cc_version_major == -1:
 | 
					 | 
				
			||||||
        print_warning(
 | 
					 | 
				
			||||||
            "Couldn't detect compiler version, skipping version checks. "
 | 
					 | 
				
			||||||
            "Build may fail if the compiler doesn't support C++17 fully."
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    # Apple LLVM versions differ from upstream LLVM version \o/, compare
 | 
					    # Apple LLVM versions differ from upstream LLVM version \o/, compare
 | 
				
			||||||
    # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
 | 
					    # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
 | 
				
			||||||
    elif env["platform"] == "macos" or env["platform"] == "ios":
 | 
					    if methods.is_apple_clang(env):
 | 
				
			||||||
        vanilla = methods.is_vanilla_clang(env)
 | 
					        if cc_version_major < 10:
 | 
				
			||||||
        if vanilla and cc_version_major < 6:
 | 
					 | 
				
			||||||
            print_warning(
 | 
					 | 
				
			||||||
                "Detected Clang version older than 6, which does not fully support "
 | 
					 | 
				
			||||||
                "C++17. Supported versions are Clang 6 and later."
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            Exit(255)
 | 
					 | 
				
			||||||
        elif not vanilla and cc_version_major < 10:
 | 
					 | 
				
			||||||
            print_error(
 | 
					            print_error(
 | 
				
			||||||
                "Detected Apple Clang version older than 10, which does not fully "
 | 
					                "Detected Apple Clang version older than 10, which does not fully "
 | 
				
			||||||
                "support C++17. Supported versions are Apple Clang 10 and later."
 | 
					                "support C++17. Supported versions are Apple Clang 10 and later."
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            Exit(255)
 | 
					            Exit(255)
 | 
				
			||||||
        if env["debug_paths_relative"] and not vanilla and cc_version_major < 12:
 | 
					        elif env["debug_paths_relative"] and cc_version_major < 12:
 | 
				
			||||||
            print_warning(
 | 
					            print_warning(
 | 
				
			||||||
                "Apple Clang < 12 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option."
 | 
					                "Apple Clang < 12 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option."
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            env["debug_paths_relative"] = False
 | 
					            env["debug_paths_relative"] = False
 | 
				
			||||||
    elif cc_version_major < 6:
 | 
					    else:
 | 
				
			||||||
 | 
					        if cc_version_major < 6:
 | 
				
			||||||
 | 
					            print_error(
 | 
				
			||||||
 | 
					                "Detected Clang version older than 6, which does not fully support "
 | 
				
			||||||
 | 
					                "C++17. Supported versions are Clang 6 and later."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            Exit(255)
 | 
				
			||||||
 | 
					        elif env["debug_paths_relative"] and cc_version_major < 10:
 | 
				
			||||||
 | 
					            print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
 | 
				
			||||||
 | 
					            env["debug_paths_relative"] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					elif env.msvc:
 | 
				
			||||||
 | 
					    # Ensure latest minor builds of Visual Studio 2017/2019.
 | 
				
			||||||
 | 
					    # https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
 | 
				
			||||||
 | 
					    if cc_version_major == 16 and cc_version_minor < 11:
 | 
				
			||||||
        print_error(
 | 
					        print_error(
 | 
				
			||||||
            "Detected Clang version older than 6, which does not fully support "
 | 
					            "Detected Visual Studio 2019 version older than 16.11, which has bugs "
 | 
				
			||||||
            "C++17. Supported versions are Clang 6 and later."
 | 
					            "when compiling Godot. Use a newer VS2019 version, or VS2022."
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        Exit(255)
 | 
					        Exit(255)
 | 
				
			||||||
    if env["debug_paths_relative"] and cc_version_major < 10:
 | 
					    if cc_version_major == 15 and cc_version_minor < 9:
 | 
				
			||||||
        print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
 | 
					        print_error(
 | 
				
			||||||
        env["debug_paths_relative"] = False
 | 
					            "Detected Visual Studio 2017 version older than 15.9, which has bugs "
 | 
				
			||||||
 | 
					            "when compiling Godot. Use a newer VS2017 version, or VS2019/VS2022."
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        Exit(255)
 | 
				
			||||||
 | 
					    if cc_version_major < 15:
 | 
				
			||||||
 | 
					        print_error(
 | 
				
			||||||
 | 
					            "Detected Visual Studio 2015 or earlier, which is unsupported in Godot. "
 | 
				
			||||||
 | 
					            "Supported versions are Visual Studio 2017 and later."
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        Exit(255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Default architecture flags.
 | 
				
			||||||
 | 
					if env["arch"] == "x86_32":
 | 
				
			||||||
 | 
					    if env.msvc:
 | 
				
			||||||
 | 
					        env.Append(CCFLAGS=["/arch:SSE2"])
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        env.Append(CCFLAGS=["-msse2"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Explicitly specify colored output.
 | 
				
			||||||
 | 
					if methods.using_gcc(env):
 | 
				
			||||||
 | 
					    env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"])
 | 
				
			||||||
 | 
					elif methods.using_clang(env) or methods.using_emcc(env):
 | 
				
			||||||
 | 
					    env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"])
 | 
				
			||||||
 | 
					    if sys.platform == "win32":
 | 
				
			||||||
 | 
					        env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Set optimize and debug_symbols flags.
 | 
					# Set optimize and debug_symbols flags.
 | 
				
			||||||
# "custom" means do nothing and let users set their own optimization flags.
 | 
					# "custom" means do nothing and let users set their own optimization flags.
 | 
				
			||||||
| 
						 | 
					@ -712,9 +724,15 @@ if env.msvc:
 | 
				
			||||||
        env.Append(CCFLAGS=["/Od"])
 | 
					        env.Append(CCFLAGS=["/Od"])
 | 
				
			||||||
else:
 | 
					else:
 | 
				
			||||||
    if env["debug_symbols"]:
 | 
					    if env["debug_symbols"]:
 | 
				
			||||||
        # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
 | 
					        if env["platform"] == "windows":
 | 
				
			||||||
        # otherwise addr2line doesn't understand them
 | 
					            if methods.using_clang(env):
 | 
				
			||||||
        env.Append(CCFLAGS=["-gdwarf-4"])
 | 
					                env.Append(CCFLAGS=["-gdwarf-4"])  # clang dwarf-5 symbols are broken on Windows.
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                env.Append(CCFLAGS=["-gdwarf-5"])  # For gcc, only dwarf-5 symbols seem usable by libbacktrace.
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
 | 
				
			||||||
 | 
					            # otherwise addr2line doesn't understand them
 | 
				
			||||||
 | 
					            env.Append(CCFLAGS=["-gdwarf-4"])
 | 
				
			||||||
        if methods.using_emcc(env):
 | 
					        if methods.using_emcc(env):
 | 
				
			||||||
            # Emscripten only produces dwarf symbols when using "-g3".
 | 
					            # Emscripten only produces dwarf symbols when using "-g3".
 | 
				
			||||||
            env.Append(CCFLAGS=["-g3"])
 | 
					            env.Append(CCFLAGS=["-g3"])
 | 
				
			||||||
| 
						 | 
					@ -730,7 +748,7 @@ else:
 | 
				
			||||||
            project_path = Dir("#").abspath
 | 
					            project_path = Dir("#").abspath
 | 
				
			||||||
            env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
 | 
					            env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        if methods.using_clang(env) and not methods.is_vanilla_clang(env):
 | 
					        if methods.is_apple_clang(env):
 | 
				
			||||||
            # Apple Clang, its linker doesn't like -s.
 | 
					            # Apple Clang, its linker doesn't like -s.
 | 
				
			||||||
            env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
 | 
					            env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
| 
						 | 
					@ -766,13 +784,23 @@ if env["lto"] != "none":
 | 
				
			||||||
# This needs to come after `configure`, otherwise we don't have env.msvc.
 | 
					# This needs to come after `configure`, otherwise we don't have env.msvc.
 | 
				
			||||||
if not env.msvc:
 | 
					if not env.msvc:
 | 
				
			||||||
    # Specifying GNU extensions support explicitly, which are supported by
 | 
					    # Specifying GNU extensions support explicitly, which are supported by
 | 
				
			||||||
    # both GCC and Clang. Both currently default to gnu11 and gnu++14.
 | 
					    # both GCC and Clang. Both currently default to gnu17 and gnu++17.
 | 
				
			||||||
    env.Prepend(CFLAGS=["-std=gnu11"])
 | 
					    env.Prepend(CFLAGS=["-std=gnu17"])
 | 
				
			||||||
    env.Prepend(CXXFLAGS=["-std=gnu++17"])
 | 
					    env.Prepend(CXXFLAGS=["-std=gnu++17"])
 | 
				
			||||||
else:
 | 
					else:
 | 
				
			||||||
    # MSVC doesn't have clear C standard support, /std only covers C++.
 | 
					    # MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all
 | 
				
			||||||
    # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
 | 
					    # of our supported VS2019 & VS2022 versions; VS2017 will only pass the C++ standard.
 | 
				
			||||||
    env.Prepend(CCFLAGS=["/std:c++17"])
 | 
					    env.Prepend(CXXFLAGS=["/std:c++17"])
 | 
				
			||||||
 | 
					    if cc_version_major < 16:
 | 
				
			||||||
 | 
					        print_warning("Visual Studio 2017 cannot specify a C-Standard.")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        env.Prepend(CFLAGS=["/std:c17"])
 | 
				
			||||||
 | 
					    # MSVC is non-conforming with the C++ standard by default, so we enable more conformance.
 | 
				
			||||||
 | 
					    # Note that this is still not complete conformance, as certain Windows-related headers
 | 
				
			||||||
 | 
					    # don't compile under complete conformance.
 | 
				
			||||||
 | 
					    env.Prepend(CCFLAGS=["/permissive-"])
 | 
				
			||||||
 | 
					    # Allow use of `__cplusplus` macro to determine C++ standard universally.
 | 
				
			||||||
 | 
					    env.Prepend(CXXFLAGS=["/Zc:__cplusplus"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
 | 
					# Disable exception handling. Godot doesn't use exceptions anywhere, and this
 | 
				
			||||||
# saves around 20% of binary size and very significant build time (GH-80513).
 | 
					# saves around 20% of binary size and very significant build time (GH-80513).
 | 
				
			||||||
| 
						 | 
					@ -785,44 +813,42 @@ elif env.msvc:
 | 
				
			||||||
    env.Append(CXXFLAGS=["/EHsc"])
 | 
					    env.Append(CXXFLAGS=["/EHsc"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Configure compiler warnings
 | 
					# Configure compiler warnings
 | 
				
			||||||
if env.msvc:  # MSVC
 | 
					if env.msvc and not methods.using_clang(env):  # MSVC
 | 
				
			||||||
    if env["warnings"] == "no":
 | 
					    # Disable warnings which we don't plan to fix.
 | 
				
			||||||
        env.Append(CCFLAGS=["/w"])
 | 
					    disabled_warnings = [
 | 
				
			||||||
    else:
 | 
					        "/wd4100",  # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
 | 
				
			||||||
        if env["warnings"] == "extra":
 | 
					        "/wd4127",  # C4127 (conditional expression is constant)
 | 
				
			||||||
            env.Append(CCFLAGS=["/W4"])
 | 
					        "/wd4201",  # C4201 (non-standard nameless struct/union): Only relevant for C89.
 | 
				
			||||||
        elif env["warnings"] == "all":
 | 
					        "/wd4244",  # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
 | 
				
			||||||
            # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too.
 | 
					        "/wd4245",
 | 
				
			||||||
            env.Append(CCFLAGS=["/W3", "/w34458"])
 | 
					        "/wd4267",
 | 
				
			||||||
        elif env["warnings"] == "moderate":
 | 
					        "/wd4305",  # C4305 (truncation): double to float or real_t, too hard to avoid.
 | 
				
			||||||
            env.Append(CCFLAGS=["/W2"])
 | 
					        "/wd4324",  # C4820 (structure was padded due to alignment specifier)
 | 
				
			||||||
        # Disable warnings which we don't plan to fix.
 | 
					        "/wd4514",  # C4514 (unreferenced inline function has been removed)
 | 
				
			||||||
 | 
					        "/wd4714",  # C4714 (function marked as __forceinline not inlined)
 | 
				
			||||||
 | 
					        "/wd4820",  # C4820 (padding added after construct)
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        env.Append(
 | 
					    if env["warnings"] == "extra":
 | 
				
			||||||
            CCFLAGS=[
 | 
					        env.Append(CCFLAGS=["/W4"] + disabled_warnings)
 | 
				
			||||||
                "/wd4100",  # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
 | 
					    elif env["warnings"] == "all":
 | 
				
			||||||
                "/wd4127",  # C4127 (conditional expression is constant)
 | 
					        # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too.
 | 
				
			||||||
                "/wd4201",  # C4201 (non-standard nameless struct/union): Only relevant for C89.
 | 
					        env.Append(CCFLAGS=["/W3", "/w34458"] + disabled_warnings)
 | 
				
			||||||
                "/wd4244",  # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
 | 
					    elif env["warnings"] == "moderate":
 | 
				
			||||||
                "/wd4245",
 | 
					        env.Append(CCFLAGS=["/W2"] + disabled_warnings)
 | 
				
			||||||
                "/wd4267",
 | 
					    else:  # 'no'
 | 
				
			||||||
                "/wd4305",  # C4305 (truncation): double to float or real_t, too hard to avoid.
 | 
					        # C4267 is particularly finicky & needs to be explicitly disabled.
 | 
				
			||||||
                "/wd4514",  # C4514 (unreferenced inline function has been removed)
 | 
					        env.Append(CCFLAGS=["/w", "/wd4267"])
 | 
				
			||||||
                "/wd4714",  # C4714 (function marked as __forceinline not inlined)
 | 
					 | 
				
			||||||
                "/wd4820",  # C4820 (padding added after construct)
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if env["werror"]:
 | 
					    if env["werror"]:
 | 
				
			||||||
        env.Append(CCFLAGS=["/WX"])
 | 
					        env.Append(CCFLAGS=["/WX"])
 | 
				
			||||||
        env.Append(LINKFLAGS=["/WX"])
 | 
					        env.Append(LINKFLAGS=["/WX"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
else:  # GCC, Clang
 | 
					else:  # GCC, Clang
 | 
				
			||||||
    common_warnings = []
 | 
					    common_warnings = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if methods.using_gcc(env):
 | 
					    if methods.using_gcc(env):
 | 
				
			||||||
        common_warnings += ["-Wshadow", "-Wno-misleading-indentation"]
 | 
					        common_warnings += ["-Wshadow", "-Wno-misleading-indentation"]
 | 
				
			||||||
        if cc_version_major == 7:  # Bogus warning fixed in 8+.
 | 
					 | 
				
			||||||
            common_warnings += ["-Wno-strict-overflow"]
 | 
					 | 
				
			||||||
        if cc_version_major < 11:
 | 
					        if cc_version_major < 11:
 | 
				
			||||||
            # Regression in GCC 9/10, spams so much in our variadic templates
 | 
					            # Regression in GCC 9/10, spams so much in our variadic templates
 | 
				
			||||||
            # that we need to outright disable it.
 | 
					            # that we need to outright disable it.
 | 
				
			||||||
| 
						 | 
					@ -835,8 +861,11 @@ else:  # GCC, Clang
 | 
				
			||||||
        # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
 | 
					        # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
 | 
				
			||||||
        common_warnings += ["-Wno-ordered-compare-function-pointers"]
 | 
					        common_warnings += ["-Wno-ordered-compare-function-pointers"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast
 | 
				
			||||||
 | 
					    W_ALL = "-Wall" if not env.msvc else "-W3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if env["warnings"] == "extra":
 | 
					    if env["warnings"] == "extra":
 | 
				
			||||||
        env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
 | 
					        env.Append(CCFLAGS=[W_ALL, "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings)
 | 
				
			||||||
        env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
 | 
					        env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
 | 
				
			||||||
        if methods.using_gcc(env):
 | 
					        if methods.using_gcc(env):
 | 
				
			||||||
            env.Append(
 | 
					            env.Append(
 | 
				
			||||||
| 
						 | 
					@ -858,9 +887,9 @@ else:  # GCC, Clang
 | 
				
			||||||
        elif methods.using_clang(env) or methods.using_emcc(env):
 | 
					        elif methods.using_clang(env) or methods.using_emcc(env):
 | 
				
			||||||
            env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
 | 
					            env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
 | 
				
			||||||
    elif env["warnings"] == "all":
 | 
					    elif env["warnings"] == "all":
 | 
				
			||||||
        env.Append(CCFLAGS=["-Wall"] + common_warnings)
 | 
					        env.Append(CCFLAGS=[W_ALL] + common_warnings)
 | 
				
			||||||
    elif env["warnings"] == "moderate":
 | 
					    elif env["warnings"] == "moderate":
 | 
				
			||||||
        env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings)
 | 
					        env.Append(CCFLAGS=[W_ALL, "-Wno-unused"] + common_warnings)
 | 
				
			||||||
    else:  # 'no'
 | 
					    else:  # 'no'
 | 
				
			||||||
        env.Append(CCFLAGS=["-w"])
 | 
					        env.Append(CCFLAGS=["-w"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -895,7 +924,7 @@ env.module_icons_paths = []
 | 
				
			||||||
env.doc_class_path = platform_doc_class_path
 | 
					env.doc_class_path = platform_doc_class_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for name, path in modules_detected.items():
 | 
					for name, path in modules_detected.items():
 | 
				
			||||||
    if not env["module_" + name + "_enabled"]:
 | 
					    if not env[f"module_{name}_enabled"]:
 | 
				
			||||||
        continue
 | 
					        continue
 | 
				
			||||||
    sys.path.insert(0, path)
 | 
					    sys.path.insert(0, path)
 | 
				
			||||||
    env.current_module = name
 | 
					    env.current_module = name
 | 
				
			||||||
| 
						 | 
					@ -932,7 +961,7 @@ methods.sort_module_list(env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env.editor_build:
 | 
					if env.editor_build:
 | 
				
			||||||
    # Add editor-specific dependencies to the dependency graph.
 | 
					    # Add editor-specific dependencies to the dependency graph.
 | 
				
			||||||
    env.module_add_dependencies("editor", ["freetype", "svg"])
 | 
					    env.module_add_dependencies("editor", ["freetype", "regex", "svg"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # And check if they are met.
 | 
					    # And check if they are met.
 | 
				
			||||||
    if not env.module_check_dependencies("editor"):
 | 
					    if not env.module_check_dependencies("editor"):
 | 
				
			||||||
| 
						 | 
					@ -969,8 +998,7 @@ if env["disable_3d"]:
 | 
				
			||||||
if env["disable_advanced_gui"]:
 | 
					if env["disable_advanced_gui"]:
 | 
				
			||||||
    if env.editor_build:
 | 
					    if env.editor_build:
 | 
				
			||||||
        print_error(
 | 
					        print_error(
 | 
				
			||||||
            "Build option `disable_advanced_gui=yes` cannot be used for editor builds, "
 | 
					            "Build option `disable_advanced_gui=yes` cannot be used for editor builds, only for export template builds."
 | 
				
			||||||
            "only for export template builds."
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        Exit(255)
 | 
					        Exit(255)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
| 
						 | 
					@ -1002,36 +1030,22 @@ GLSL_BUILDERS = {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
env.Append(BUILDERS=GLSL_BUILDERS)
 | 
					env.Append(BUILDERS=GLSL_BUILDERS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
scons_cache_path = os.environ.get("SCONS_CACHE")
 | 
					 | 
				
			||||||
if scons_cache_path is not None:
 | 
					 | 
				
			||||||
    CacheDir(scons_cache_path)
 | 
					 | 
				
			||||||
    print("Scons cache enabled... (path: '" + scons_cache_path + "')")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if env["vsproj"]:
 | 
					 | 
				
			||||||
    env.vs_incs = []
 | 
					 | 
				
			||||||
    env.vs_srcs = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if env["compiledb"]:
 | 
					if env["compiledb"]:
 | 
				
			||||||
    if env.scons_version < (4, 0, 0):
 | 
					 | 
				
			||||||
        # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
 | 
					 | 
				
			||||||
        print_error("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version)
 | 
					 | 
				
			||||||
        Exit(255)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    env.Tool("compilation_db")
 | 
					    env.Tool("compilation_db")
 | 
				
			||||||
    env.Alias("compiledb", env.CompilationDatabase())
 | 
					    env.Alias("compiledb", env.CompilationDatabase())
 | 
				
			||||||
 | 
					    env.NoCache(env.CompilationDatabase())
 | 
				
			||||||
 | 
					    if not env["verbose"]:
 | 
				
			||||||
 | 
					        env["COMPILATIONDB_COMSTR"] = "$GENCOMSTR"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env["ninja"]:
 | 
					if env["ninja"]:
 | 
				
			||||||
    if env.scons_version < (4, 2, 0):
 | 
					    if env.scons_version < (4, 2, 0):
 | 
				
			||||||
        print_error("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version)
 | 
					        print_error(f"The `ninja=yes` option requires SCons 4.2 or later, but your version is {scons_raw_version}.")
 | 
				
			||||||
        Exit(255)
 | 
					        Exit(255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SetOption("experimental", "ninja")
 | 
					    SetOption("experimental", "ninja")
 | 
				
			||||||
    env.Tool("ninja")
 | 
					    env["NINJA_FILE_NAME"] = env["ninja_file"]
 | 
				
			||||||
 | 
					    env["NINJA_DISABLE_AUTO_RUN"] = not env["ninja_auto_run"]
 | 
				
			||||||
    # By setting this we allow the user to run ninja by themselves with all
 | 
					    env.Tool("ninja", env["ninja_file"])
 | 
				
			||||||
    # the flags they need, as apparently automatically running from scons
 | 
					 | 
				
			||||||
    # is way slower.
 | 
					 | 
				
			||||||
    SetOption("disable_execute_ninja", True)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Threads
 | 
					# Threads
 | 
				
			||||||
if env["threads"]:
 | 
					if env["threads"]:
 | 
				
			||||||
| 
						 | 
					@ -1070,35 +1084,9 @@ if "check_c_headers" in env:
 | 
				
			||||||
            env.AppendUnique(CPPDEFINES=[headers[header]])
 | 
					            env.AppendUnique(CPPDEFINES=[headers[header]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME: This method mixes both cosmetic progress stuff and cache handling...
 | 
					 | 
				
			||||||
methods.show_progress(env)
 | 
					methods.show_progress(env)
 | 
				
			||||||
# TODO: replace this with `env.Dump(format="json")`
 | 
					# TODO: replace this with `env.Dump(format="json")`
 | 
				
			||||||
# once we start requiring SCons 4.0 as min version.
 | 
					# once we start requiring SCons 4.0 as min version.
 | 
				
			||||||
methods.dump(env)
 | 
					methods.dump(env)
 | 
				
			||||||
 | 
					methods.prepare_purge(env)
 | 
				
			||||||
 | 
					methods.prepare_timer()
 | 
				
			||||||
def print_elapsed_time():
 | 
					 | 
				
			||||||
    elapsed_time_sec = round(time.time() - time_at_start, 2)
 | 
					 | 
				
			||||||
    time_centiseconds = round((elapsed_time_sec % 1) * 100)
 | 
					 | 
				
			||||||
    print(
 | 
					 | 
				
			||||||
        "{}[Time elapsed: {}.{:02}]{}".format(
 | 
					 | 
				
			||||||
            methods.ANSI.GRAY,
 | 
					 | 
				
			||||||
            time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
 | 
					 | 
				
			||||||
            time_centiseconds,
 | 
					 | 
				
			||||||
            methods.ANSI.RESET,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
atexit.register(print_elapsed_time)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def purge_flaky_files():
 | 
					 | 
				
			||||||
    paths_to_keep = ["ninja.build"]
 | 
					 | 
				
			||||||
    for build_failure in GetBuildFailures():
 | 
					 | 
				
			||||||
        path = build_failure.node.path
 | 
					 | 
				
			||||||
        if os.path.isfile(path) and path not in paths_to_keep:
 | 
					 | 
				
			||||||
            os.remove(path)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
atexit.register(purge_flaky_files)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,8 @@ if env["builtin_zlib"]:
 | 
				
			||||||
    env.Prepend(CPPPATH=[thirdparty_zlib_dir])
 | 
					    env.Prepend(CPPPATH=[thirdparty_zlib_dir])
 | 
				
			||||||
    if env.dev_build:
 | 
					    if env.dev_build:
 | 
				
			||||||
        env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
 | 
					        env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
 | 
				
			||||||
 | 
					        # Affects headers so it should also be defined for Godot code
 | 
				
			||||||
 | 
					        env.Append(CPPDEFINES=["ZLIB_DEBUG"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,7 +143,7 @@ if env["builtin_zstd"]:
 | 
				
			||||||
        "decompress/zstd_decompress_block.c",
 | 
					        "decompress/zstd_decompress_block.c",
 | 
				
			||||||
        "decompress/zstd_decompress.c",
 | 
					        "decompress/zstd_decompress.c",
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    if env["platform"] in ["android", "ios", "linuxbsd", "macos"]:
 | 
					    if env["platform"] in ["android", "ios", "linuxbsd", "macos"] and env["arch"] == "x86_64":
 | 
				
			||||||
        # Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
 | 
					        # Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
 | 
				
			||||||
        thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
 | 
					        thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
 | 
				
			||||||
    thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
 | 
					    thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@
 | 
				
			||||||
#include "core/license.gen.h"
 | 
					#include "core/license.gen.h"
 | 
				
			||||||
#include "core/variant/typed_array.h"
 | 
					#include "core/variant/typed_array.h"
 | 
				
			||||||
#include "core/version.h"
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					#include "servers/rendering/rendering_device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Engine::set_physics_ticks_per_second(int p_ips) {
 | 
					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.");
 | 
						ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
 | 
				
			||||||
| 
						 | 
					@ -68,6 +69,11 @@ double Engine::get_physics_jitter_fix() const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Engine::set_max_fps(int p_fps) {
 | 
					void Engine::set_max_fps(int p_fps) {
 | 
				
			||||||
	_max_fps = p_fps > 0 ? p_fps : 0;
 | 
						_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 {
 | 
					int Engine::get_max_fps() const {
 | 
				
			||||||
| 
						 | 
					@ -110,6 +116,10 @@ void Engine::set_time_scale(double p_scale) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
double Engine::get_time_scale() const {
 | 
					double Engine::get_time_scale() const {
 | 
				
			||||||
 | 
						return freeze_time_scale ? 0 : _time_scale;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double Engine::get_unfrozen_time_scale() const {
 | 
				
			||||||
	return _time_scale;
 | 
						return _time_scale;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,6 +248,9 @@ String Engine::get_architecture_name() const {
 | 
				
			||||||
	return "ppc";
 | 
						return "ppc";
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__loongarch64)
 | 
				
			||||||
 | 
						return "loongarch64";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined(__wasm__)
 | 
					#elif defined(__wasm__)
 | 
				
			||||||
#if defined(__wasm64__)
 | 
					#if defined(__wasm64__)
 | 
				
			||||||
	return "wasm64";
 | 
						return "wasm64";
 | 
				
			||||||
| 
						 | 
					@ -263,6 +276,24 @@ bool Engine::is_generate_spirv_debug_info_enabled() const {
 | 
				
			||||||
	return generate_spirv_debug_info;
 | 
						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) {
 | 
					void Engine::set_print_error_messages(bool p_enabled) {
 | 
				
			||||||
	CoreGlobals::print_error_enabled = p_enabled;
 | 
						CoreGlobals::print_error_enabled = p_enabled;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -380,6 +411,18 @@ bool Engine::notify_frame_server_synced() {
 | 
				
			||||||
	return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
 | 
						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() {
 | 
					Engine::Engine() {
 | 
				
			||||||
	singleton = this;
 | 
						singleton = this;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,6 @@
 | 
				
			||||||
#include "core/os/main_loop.h"
 | 
					#include "core/os/main_loop.h"
 | 
				
			||||||
#include "core/string/ustring.h"
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
#include "core/templates/list.h"
 | 
					#include "core/templates/list.h"
 | 
				
			||||||
#include "core/templates/vector.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
class TypedArray;
 | 
					class TypedArray;
 | 
				
			||||||
| 
						 | 
					@ -72,6 +71,10 @@ private:
 | 
				
			||||||
	bool abort_on_gpu_errors = false;
 | 
						bool abort_on_gpu_errors = false;
 | 
				
			||||||
	bool use_validation_layers = false;
 | 
						bool use_validation_layers = false;
 | 
				
			||||||
	bool generate_spirv_debug_info = 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;
 | 
						int32_t gpu_idx = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t _process_frames = 0;
 | 
						uint64_t _process_frames = 0;
 | 
				
			||||||
| 
						 | 
					@ -83,6 +86,8 @@ private:
 | 
				
			||||||
	bool editor_hint = false;
 | 
						bool editor_hint = false;
 | 
				
			||||||
	bool project_manager_hint = false;
 | 
						bool project_manager_hint = false;
 | 
				
			||||||
	bool extension_reloading = false;
 | 
						bool extension_reloading = false;
 | 
				
			||||||
 | 
						bool embedded_in_editor = false;
 | 
				
			||||||
 | 
						bool recovery_mode_hint = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool _print_header = true;
 | 
						bool _print_header = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,6 +100,8 @@ private:
 | 
				
			||||||
	int server_syncs = 0;
 | 
						int server_syncs = 0;
 | 
				
			||||||
	bool frame_server_synced = false;
 | 
						bool frame_server_synced = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool freeze_time_scale = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static Engine *get_singleton();
 | 
						static Engine *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,6 +133,10 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_time_scale(double p_scale);
 | 
						void set_time_scale(double p_scale);
 | 
				
			||||||
	double get_time_scale() const;
 | 
						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);
 | 
						void set_print_error_messages(bool p_enabled);
 | 
				
			||||||
	bool is_printing_error_messages() const;
 | 
						bool is_printing_error_messages() const;
 | 
				
			||||||
| 
						 | 
					@ -152,6 +163,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; }
 | 
						_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_ 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
 | 
					#else
 | 
				
			||||||
	_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
 | 
						_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
 | 
				
			||||||
	_FORCE_INLINE_ bool is_editor_hint() const { return false; }
 | 
						_FORCE_INLINE_ bool is_editor_hint() const { return false; }
 | 
				
			||||||
| 
						 | 
					@ -161,6 +175,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
 | 
						_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
 | 
				
			||||||
	_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; }
 | 
						_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
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Dictionary get_version_info() const;
 | 
						Dictionary get_version_info() const;
 | 
				
			||||||
| 
						 | 
					@ -181,11 +198,19 @@ public:
 | 
				
			||||||
	bool is_abort_on_gpu_errors_enabled() const;
 | 
						bool is_abort_on_gpu_errors_enabled() const;
 | 
				
			||||||
	bool is_validation_layers_enabled() const;
 | 
						bool is_validation_layers_enabled() const;
 | 
				
			||||||
	bool is_generate_spirv_debug_info_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;
 | 
						int32_t get_gpu_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void increment_frames_drawn();
 | 
						void increment_frames_drawn();
 | 
				
			||||||
	bool notify_frame_server_synced();
 | 
						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();
 | 
						Engine();
 | 
				
			||||||
	virtual ~Engine();
 | 
						virtual ~Engine();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,6 @@
 | 
				
			||||||
#include "core/io/marshalls.h"
 | 
					#include "core/io/marshalls.h"
 | 
				
			||||||
#include "core/io/resource_uid.h"
 | 
					#include "core/io/resource_uid.h"
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
#include "core/os/keyboard.h"
 | 
					 | 
				
			||||||
#include "core/templates/rb_set.h"
 | 
					#include "core/templates/rb_set.h"
 | 
				
			||||||
#include "core/variant/typed_array.h"
 | 
					#include "core/variant/typed_array.h"
 | 
				
			||||||
#include "core/variant/variant_parser.h"
 | 
					#include "core/variant/variant_parser.h"
 | 
				
			||||||
| 
						 | 
					@ -194,7 +193,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return cwd.replace_first(res_path, "res://");
 | 
							return cwd.replace_first(res_path, "res://");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		int sep = path.rfind("/");
 | 
							int sep = path.rfind_char('/');
 | 
				
			||||||
		if (sep == -1) {
 | 
							if (sep == -1) {
 | 
				
			||||||
			return "res://" + path;
 | 
								return "res://" + path;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -214,36 +213,36 @@ String ProjectSettings::localize_path(const String &p_path) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_value) {
 | 
					void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_value) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Duplicate so that if value is array or dictionary, changing the setting will not change the stored initial value.
 | 
						// Duplicate so that if value is array or dictionary, changing the setting will not change the stored initial value.
 | 
				
			||||||
	props[p_name].initial = p_value.duplicate();
 | 
						props[p_name].initial = p_value.duplicate();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restart) {
 | 
					void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restart) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	props[p_name].restart_if_changed = p_restart;
 | 
						props[p_name].restart_if_changed = p_restart;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) {
 | 
					void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	props[p_name].basic = p_basic;
 | 
						props[p_name].basic = p_basic;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_as_internal(const String &p_name, bool p_internal) {
 | 
					void ProjectSettings::set_as_internal(const String &p_name, bool p_internal) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	props[p_name].internal = p_internal;
 | 
						props[p_name].internal = p_internal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) {
 | 
					void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
#ifdef DEBUG_METHODS_ENABLED
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
	props[p_name].ignore_value_in_docs = p_ignore;
 | 
						props[p_name].ignore_value_in_docs = p_ignore;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const {
 | 
					bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!props.has(p_name), false, "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_V_MSG(!props.has(p_name), false, vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
#ifdef DEBUG_METHODS_ENABLED
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
	return props[p_name].ignore_value_in_docs;
 | 
						return props[p_name].ignore_value_in_docs;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -262,6 +261,12 @@ String ProjectSettings::globalize_path(const String &p_path) const {
 | 
				
			||||||
			return p_path.replace("res:/", resource_path);
 | 
								return p_path.replace("res:/", resource_path);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return p_path.replace("res://", "");
 | 
							return p_path.replace("res://", "");
 | 
				
			||||||
 | 
						} else if (p_path.begins_with("uid://")) {
 | 
				
			||||||
 | 
							const String path = ResourceUID::uid_to_path(p_path);
 | 
				
			||||||
 | 
							if (!resource_path.is_empty()) {
 | 
				
			||||||
 | 
								return path.replace("res:/", resource_path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return path.replace("res://", "");
 | 
				
			||||||
	} else if (p_path.begins_with("user://")) {
 | 
						} else if (p_path.begins_with("user://")) {
 | 
				
			||||||
		String data_dir = OS::get_singleton()->get_user_data_dir();
 | 
							String data_dir = OS::get_singleton()->get_user_data_dir();
 | 
				
			||||||
		if (!data_dir.is_empty()) {
 | 
							if (!data_dir.is_empty()) {
 | 
				
			||||||
| 
						 | 
					@ -300,7 +305,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{ // Feature overrides.
 | 
							{ // Feature overrides.
 | 
				
			||||||
			int dot = p_name.operator String().find(".");
 | 
								int dot = p_name.operator String().find_char('.');
 | 
				
			||||||
			if (dot != -1) {
 | 
								if (dot != -1) {
 | 
				
			||||||
				Vector<String> s = p_name.operator String().split(".");
 | 
									Vector<String> s = p_name.operator String().split(".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -348,7 +353,6 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!props.has(p_name)) {
 | 
						if (!props.has(p_name)) {
 | 
				
			||||||
		WARN_PRINT("Property not found: " + String(p_name));
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r_ret = props[p_name].variant;
 | 
						r_ret = props[p_name].variant;
 | 
				
			||||||
| 
						 | 
					@ -372,7 +376,7 @@ Variant ProjectSettings::get_setting_with_override(const StringName &p_name) con
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!props.has(name)) {
 | 
						if (!props.has(name)) {
 | 
				
			||||||
		WARN_PRINT("Property not found: " + String(name));
 | 
							WARN_PRINT(vformat("Property not found: '%s'.", String(name)));
 | 
				
			||||||
		return Variant();
 | 
							return Variant();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return props[name].variant;
 | 
						return props[name].variant;
 | 
				
			||||||
| 
						 | 
					@ -436,7 +440,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (const _VCSort &E : vclist) {
 | 
						for (const _VCSort &E : vclist) {
 | 
				
			||||||
		String prop_info_name = E.name;
 | 
							String prop_info_name = E.name;
 | 
				
			||||||
		int dot = prop_info_name.find(".");
 | 
							int dot = prop_info_name.find_char('.');
 | 
				
			||||||
		if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
 | 
							if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
 | 
				
			||||||
			prop_info_name = prop_info_name.substr(0, dot);
 | 
								prop_info_name = prop_info_name.substr(0, dot);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -468,13 +472,30 @@ void ProjectSettings::_emit_changed() {
 | 
				
			||||||
	emit_signal("settings_changed");
 | 
						emit_signal("settings_changed");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
 | 
					bool ProjectSettings::load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
 | 
				
			||||||
 | 
						return ProjectSettings::_load_resource_pack(p_pack, p_replace_files, p_offset, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset, bool p_main_pack) {
 | 
				
			||||||
	if (PackedData::get_singleton()->is_disabled()) {
 | 
						if (PackedData::get_singleton()->is_disabled()) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
 | 
						if (p_pack == "res://") {
 | 
				
			||||||
 | 
							// Loading the resource directory as a pack source is reserved for internal use only.
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p_main_pack && !using_datapack && !OS::get_singleton()->get_resource_dir().is_empty()) {
 | 
				
			||||||
 | 
							// Add the project's resource file system to PackedData so directory access keeps working when
 | 
				
			||||||
 | 
							// the game is running without a main pack, like in the editor or on Android.
 | 
				
			||||||
 | 
							PackedData::get_singleton()->add_pack_source(memnew(PackedSourceDirectory));
 | 
				
			||||||
 | 
							PackedData::get_singleton()->add_pack("res://", false, 0);
 | 
				
			||||||
 | 
							DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
 | 
				
			||||||
 | 
							using_datapack = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
 | 
				
			||||||
	if (!ok) {
 | 
						if (!ok) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -487,14 +508,17 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f
 | 
				
			||||||
		ResourceUID::get_singleton()->load_from_cache(false);
 | 
							ResourceUID::get_singleton()->load_from_cache(false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//if data.pck is found, all directory access will be from here
 | 
						// If the data pack was found, all directory access will be from here.
 | 
				
			||||||
	DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
 | 
						if (!using_datapack) {
 | 
				
			||||||
	using_datapack = true;
 | 
							DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
 | 
				
			||||||
 | 
							using_datapack = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::_convert_to_last_version(int p_from_version) {
 | 
					void ProjectSettings::_convert_to_last_version(int p_from_version) {
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
	if (p_from_version <= 3) {
 | 
						if (p_from_version <= 3) {
 | 
				
			||||||
		// Converts the actions from array to dictionary (array of events to dictionary with deadzone + events)
 | 
							// Converts the actions from array to dictionary (array of events to dictionary with deadzone + events)
 | 
				
			||||||
		for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
 | 
							for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
 | 
				
			||||||
| 
						 | 
					@ -508,6 +532,7 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -548,8 +573,8 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 | 
				
			||||||
	// Attempt with a user-defined main pack first
 | 
						// Attempt with a user-defined main pack first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!p_main_pack.is_empty()) {
 | 
						if (!p_main_pack.is_empty()) {
 | 
				
			||||||
		bool ok = _load_resource_pack(p_main_pack);
 | 
							bool ok = _load_resource_pack(p_main_pack, false, 0, true);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, "Cannot open resource pack '" + p_main_pack + "'.");
 | 
							ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, vformat("Cannot open resource pack '%s'.", p_main_pack));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
 | 
							Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
 | 
				
			||||||
		if (err == OK && !p_ignore_override) {
 | 
							if (err == OK && !p_ignore_override) {
 | 
				
			||||||
| 
						 | 
					@ -567,7 +592,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 | 
				
			||||||
		// and if so, we attempt loading it at the end.
 | 
							// and if so, we attempt loading it at the end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Attempt with PCK bundled into executable.
 | 
							// Attempt with PCK bundled into executable.
 | 
				
			||||||
		bool found = _load_resource_pack(exec_path);
 | 
							bool found = _load_resource_pack(exec_path, false, 0, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Attempt with exec_name.pck.
 | 
							// Attempt with exec_name.pck.
 | 
				
			||||||
		// (This is the usual case when distributing a Godot game.)
 | 
							// (This is the usual case when distributing a Godot game.)
 | 
				
			||||||
| 
						 | 
					@ -583,20 +608,20 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 | 
				
			||||||
#ifdef MACOS_ENABLED
 | 
					#ifdef MACOS_ENABLED
 | 
				
			||||||
		if (!found) {
 | 
							if (!found) {
 | 
				
			||||||
			// Attempt to load PCK from macOS .app bundle resources.
 | 
								// Attempt to load PCK from macOS .app bundle resources.
 | 
				
			||||||
			found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
 | 
								found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"), false, 0, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!found) {
 | 
							if (!found) {
 | 
				
			||||||
			// Try to load data pack at the location of the executable.
 | 
								// Try to load data pack at the location of the executable.
 | 
				
			||||||
			// As mentioned above, we have two potential names to attempt.
 | 
								// As mentioned above, we have two potential names to attempt.
 | 
				
			||||||
			found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
 | 
								found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"), false, 0, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!found) {
 | 
							if (!found) {
 | 
				
			||||||
			// If we couldn't find them next to the executable, we attempt
 | 
								// If we couldn't find them next to the executable, we attempt
 | 
				
			||||||
			// the current working directory. Same story, two tests.
 | 
								// the current working directory. Same story, two tests.
 | 
				
			||||||
			found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
 | 
								found = _load_resource_pack(exec_basename + ".pck", false, 0, true) || _load_resource_pack(exec_filename + ".pck", false, 0, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If we opened our package, try and load our project.
 | 
							// If we opened our package, try and load our project.
 | 
				
			||||||
| 
						 | 
					@ -624,11 +649,33 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef MACOS_ENABLED
 | 
				
			||||||
 | 
						// Attempt to load project file from macOS .app bundle resources.
 | 
				
			||||||
 | 
						resource_path = OS::get_singleton()->get_bundle_resource_dir();
 | 
				
			||||||
 | 
						if (!resource_path.is_empty()) {
 | 
				
			||||||
 | 
							if (resource_path[resource_path.length() - 1] == '/') {
 | 
				
			||||||
 | 
								resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", resource_path));
 | 
				
			||||||
 | 
							d->change_dir(resource_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = _load_settings_text_or_binary(resource_path.path_join("project.godot"), resource_path.path_join("project.binary"));
 | 
				
			||||||
 | 
							if (err == OK && !p_ignore_override) {
 | 
				
			||||||
 | 
								// Optional, we don't mind if it fails.
 | 
				
			||||||
 | 
								_load_settings_text(resource_path.path_join("override.cfg"));
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Nothing was found, try to find a project file in provided path (`p_path`)
 | 
						// Nothing was found, try to find a project file in provided path (`p_path`)
 | 
				
			||||||
	// or, if requested (`p_upwards`) in parent directories.
 | 
						// or, if requested (`p_upwards`) in parent directories.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
						Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'.");
 | 
						ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", p_path));
 | 
				
			||||||
	d->change_dir(p_path);
 | 
						d->change_dir(p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String current_dir = d->get_current_dir();
 | 
						String current_dir = d->get_current_dir();
 | 
				
			||||||
| 
						 | 
					@ -724,7 +771,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
 | 
				
			||||||
		cs[slen] = 0;
 | 
							cs[slen] = 0;
 | 
				
			||||||
		f->get_buffer((uint8_t *)cs.ptr(), slen);
 | 
							f->get_buffer((uint8_t *)cs.ptr(), slen);
 | 
				
			||||||
		String key;
 | 
							String key;
 | 
				
			||||||
		key.parse_utf8(cs.ptr());
 | 
							key.parse_utf8(cs.ptr(), slen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint32_t vlen = f->get_32();
 | 
							uint32_t vlen = f->get_32();
 | 
				
			||||||
		Vector<uint8_t> d;
 | 
							Vector<uint8_t> d;
 | 
				
			||||||
| 
						 | 
					@ -732,7 +779,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
 | 
				
			||||||
		f->get_buffer(d.ptrw(), vlen);
 | 
							f->get_buffer(d.ptrw(), vlen);
 | 
				
			||||||
		Variant value;
 | 
							Variant value;
 | 
				
			||||||
		err = decode_variant(value, d.ptr(), d.size(), nullptr, true);
 | 
							err = decode_variant(value, d.ptr(), d.size(), nullptr, true);
 | 
				
			||||||
		ERR_CONTINUE_MSG(err != OK, "Error decoding property: " + key + ".");
 | 
							ERR_CONTINUE_MSG(err != OK, vformat("Error decoding property: '%s'.", key));
 | 
				
			||||||
		set(key, value);
 | 
							set(key, value);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -774,7 +821,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
 | 
				
			||||||
			last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
 | 
								last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
 | 
				
			||||||
			return OK;
 | 
								return OK;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error parsing '%s' at line %d: %s File might be corrupted.", p_path, lines, error_text));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!assign.is_empty()) {
 | 
							if (!assign.is_empty()) {
 | 
				
			||||||
			if (section.is_empty() && assign == "config_version") {
 | 
								if (section.is_empty() && assign == "config_version") {
 | 
				
			||||||
| 
						 | 
					@ -800,7 +847,7 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
 | 
				
			||||||
		return OK;
 | 
							return OK;
 | 
				
			||||||
	} else if (err != ERR_FILE_NOT_FOUND) {
 | 
						} else if (err != ERR_FILE_NOT_FOUND) {
 | 
				
			||||||
		// If the file exists but can't be loaded, we want to know it.
 | 
							// If the file exists but can't be loaded, we want to know it.
 | 
				
			||||||
		ERR_PRINT("Couldn't load file '" + p_bin_path + "', error code " + itos(err) + ".");
 | 
							ERR_PRINT(vformat("Couldn't load file '%s', error code %d.", p_bin_path, err));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Fallback to text-based project.godot file if binary was not found.
 | 
						// Fallback to text-based project.godot file if binary was not found.
 | 
				
			||||||
| 
						 | 
					@ -808,7 +855,7 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
 | 
				
			||||||
	if (err == OK) {
 | 
						if (err == OK) {
 | 
				
			||||||
		return OK;
 | 
							return OK;
 | 
				
			||||||
	} else if (err != ERR_FILE_NOT_FOUND) {
 | 
						} else if (err != ERR_FILE_NOT_FOUND) {
 | 
				
			||||||
		ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err) + ".");
 | 
							ERR_PRINT(vformat("Couldn't load file '%s', error code %d.", p_text_path, err));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -822,17 +869,17 @@ Error ProjectSettings::load_custom(const String &p_path) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ProjectSettings::get_order(const String &p_name) const {
 | 
					int ProjectSettings::get_order(const String &p_name) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!props.has(p_name), -1, "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_V_MSG(!props.has(p_name), -1, vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	return props[p_name].order;
 | 
						return props[p_name].order;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_order(const String &p_name, int p_order) {
 | 
					void ProjectSettings::set_order(const String &p_name, int p_order) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	props[p_name].order = p_order;
 | 
						props[p_name].order = p_order;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_builtin_order(const String &p_name) {
 | 
					void ProjectSettings::set_builtin_order(const String &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	if (props[p_name].order >= NO_BUILTIN_ORDER_BASE) {
 | 
						if (props[p_name].order >= NO_BUILTIN_ORDER_BASE) {
 | 
				
			||||||
		props[p_name].order = last_builtin_order++;
 | 
							props[p_name].order = last_builtin_order++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -840,12 +887,12 @@ void ProjectSettings::set_builtin_order(const String &p_name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProjectSettings::is_builtin_setting(const String &p_name) const {
 | 
					bool ProjectSettings::is_builtin_setting(const String &p_name) const {
 | 
				
			||||||
	// Return true because a false negative is worse than a false positive.
 | 
						// Return true because a false negative is worse than a false positive.
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!props.has(p_name), true, "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_V_MSG(!props.has(p_name), true, vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	return props[p_name].order < NO_BUILTIN_ORDER_BASE;
 | 
						return props[p_name].order < NO_BUILTIN_ORDER_BASE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::clear(const String &p_name) {
 | 
					void ProjectSettings::clear(const String &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
 | 
						ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name));
 | 
				
			||||||
	props.erase(p_name);
 | 
						props.erase(p_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -860,7 +907,7 @@ Error ProjectSettings::save() {
 | 
				
			||||||
Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
 | 
					Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
 | 
				
			||||||
	Error err;
 | 
						Error err;
 | 
				
			||||||
	Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
 | 
						Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + ".");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Couldn't save project.binary at '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t hdr[4] = { 'E', 'C', 'F', 'G' };
 | 
						uint8_t hdr[4] = { 'E', 'C', 'F', 'G' };
 | 
				
			||||||
	file->store_buffer(hdr, 4);
 | 
						file->store_buffer(hdr, 4);
 | 
				
			||||||
| 
						 | 
					@ -873,7 +920,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!p_custom_features.is_empty()) {
 | 
						if (!p_custom_features.is_empty()) {
 | 
				
			||||||
		// Store how many properties are saved, add one for custom features, which must always go first.
 | 
							// Store how many properties are saved, add one for custom features, which must always go first.
 | 
				
			||||||
		file->store_32(count + 1);
 | 
							file->store_32(uint32_t(count + 1));
 | 
				
			||||||
		String key = CoreStringName(_custom_features);
 | 
							String key = CoreStringName(_custom_features);
 | 
				
			||||||
		file->store_pascal_string(key);
 | 
							file->store_pascal_string(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -886,12 +933,12 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = encode_variant(p_custom_features, buff.ptrw(), len, false);
 | 
							err = encode_variant(p_custom_features, buff.ptrw(), len, false);
 | 
				
			||||||
		ERR_FAIL_COND_V(err != OK, err);
 | 
							ERR_FAIL_COND_V(err != OK, err);
 | 
				
			||||||
		file->store_32(len);
 | 
							file->store_32(uint32_t(len));
 | 
				
			||||||
		file->store_buffer(buff.ptr(), buff.size());
 | 
							file->store_buffer(buff.ptr(), buff.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Store how many properties are saved.
 | 
							// Store how many properties are saved.
 | 
				
			||||||
		file->store_32(count);
 | 
							file->store_32(uint32_t(count));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (const KeyValue<String, List<String>> &E : p_props) {
 | 
						for (const KeyValue<String, List<String>> &E : p_props) {
 | 
				
			||||||
| 
						 | 
					@ -918,7 +965,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			err = encode_variant(value, buff.ptrw(), len, true);
 | 
								err = encode_variant(value, buff.ptrw(), len, true);
 | 
				
			||||||
			ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
 | 
								ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
 | 
				
			||||||
			file->store_32(len);
 | 
								file->store_32(uint32_t(len));
 | 
				
			||||||
			file->store_buffer(buff.ptr(), buff.size());
 | 
								file->store_buffer(buff.ptr(), buff.size());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -930,7 +977,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
 | 
				
			||||||
	Error err;
 | 
						Error err;
 | 
				
			||||||
	Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
 | 
						Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.godot - " + p_file + ".");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Couldn't save project.godot - %s.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file->store_line("; Engine configuration file.");
 | 
						file->store_line("; Engine configuration file.");
 | 
				
			||||||
	file->store_line("; It's best edited using the editor UI and not directly,");
 | 
						file->store_line("; It's best edited using the editor UI and not directly,");
 | 
				
			||||||
| 
						 | 
					@ -1016,7 +1063,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Check for the existence of a csproj file.
 | 
						// Check for the existence of a csproj file.
 | 
				
			||||||
	if (_csproj_exists(p_path.get_base_dir())) {
 | 
						if (_csproj_exists(get_resource_path())) {
 | 
				
			||||||
		// If there is a csproj file, add the C# feature if it doesn't already exist.
 | 
							// If there is a csproj file, add the C# feature if it doesn't already exist.
 | 
				
			||||||
		if (!project_features.has("C#")) {
 | 
							if (!project_features.has("C#")) {
 | 
				
			||||||
			project_features.append("C#");
 | 
								project_features.append("C#");
 | 
				
			||||||
| 
						 | 
					@ -1076,7 +1123,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
 | 
				
			||||||
		String category = E.name;
 | 
							String category = E.name;
 | 
				
			||||||
		String name = E.name;
 | 
							String name = E.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int div = category.find("/");
 | 
							int div = category.find_char('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (div < 0) {
 | 
							if (div < 0) {
 | 
				
			||||||
			category = "";
 | 
								category = "";
 | 
				
			||||||
| 
						 | 
					@ -1103,7 +1150,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
 | 
				
			||||||
	} else if (p_path.ends_with(".binary")) {
 | 
						} else if (p_path.ends_with(".binary")) {
 | 
				
			||||||
		return _save_settings_binary(p_path, save_props, p_custom, save_features);
 | 
							return _save_settings_binary(p_path, save_props, p_custom, save_features);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path);
 | 
							ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("Unknown config file format: '%s'.", p_path));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1168,22 +1215,16 @@ bool ProjectSettings::is_project_loaded() const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProjectSettings::_property_can_revert(const StringName &p_name) const {
 | 
					bool ProjectSettings::_property_can_revert(const StringName &p_name) const {
 | 
				
			||||||
	if (!props.has(p_name)) {
 | 
						return props.has(p_name);
 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return props[p_name].initial != props[p_name].variant;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
 | 
					bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
 | 
				
			||||||
	if (!props.has(p_name)) {
 | 
						const RBMap<StringName, ProjectSettings::VariantContainer>::Element *value = props.find(p_name);
 | 
				
			||||||
		return false;
 | 
						if (value) {
 | 
				
			||||||
 | 
							r_property = value->value().initial.duplicate();
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
	// Duplicate so that if value is array or dictionary, changing the setting will not change the stored initial value.
 | 
					 | 
				
			||||||
	r_property = props[p_name].initial.duplicate();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
 | 
					void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
 | 
				
			||||||
| 
						 | 
					@ -1204,10 +1245,10 @@ void ProjectSettings::refresh_global_class_list() {
 | 
				
			||||||
	Array script_classes = get_global_class_list();
 | 
						Array script_classes = get_global_class_list();
 | 
				
			||||||
	for (int i = 0; i < script_classes.size(); i++) {
 | 
						for (int i = 0; i < script_classes.size(); i++) {
 | 
				
			||||||
		Dictionary c = script_classes[i];
 | 
							Dictionary c = script_classes[i];
 | 
				
			||||||
		if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
 | 
							if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base") || !c.has("is_abstract") || !c.has("is_tool")) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"]);
 | 
							ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"], c["is_abstract"], c["is_tool"]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1378,7 +1419,7 @@ void ProjectSettings::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
 | 
						ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
 | 
						ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
 | 
						ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
 | 
						ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::load_resource_pack, DEFVAL(true), DEFVAL(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
 | 
						ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1398,7 +1439,7 @@ void ProjectSettings::_add_builtin_input_map() {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Dictionary action;
 | 
								Dictionary action;
 | 
				
			||||||
			action["deadzone"] = Variant(0.5f);
 | 
								action["deadzone"] = Variant(InputMap::DEFAULT_DEADZONE);
 | 
				
			||||||
			action["events"] = events;
 | 
								action["events"] = events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			String action_name = "input/" + E.key;
 | 
								String action_name = "input/" + E.key;
 | 
				
			||||||
| 
						 | 
					@ -1467,15 +1508,12 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
	GLOBAL_DEF("display/window/size/transparent", false);
 | 
						GLOBAL_DEF("display/window/size/transparent", false);
 | 
				
			||||||
	GLOBAL_DEF("display/window/size/extend_to_title", false);
 | 
						GLOBAL_DEF("display/window/size/extend_to_title", false);
 | 
				
			||||||
	GLOBAL_DEF("display/window/size/no_focus", false);
 | 
						GLOBAL_DEF("display/window/size/no_focus", false);
 | 
				
			||||||
 | 
						GLOBAL_DEF("display/window/size/sharp_corners", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
 | 
						GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					 | 
				
			||||||
	GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor_hint", false);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
 | 
						GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
 | 
				
			||||||
	GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
 | 
						GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1489,15 +1527,6 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"), 0);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"), 0);
 | 
				
			||||||
	GLOBAL_DEF("audio/general/ios/mix_with_others", false);
 | 
						GLOBAL_DEF("audio/general/ios/mix_with_others", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PackedStringArray extensions;
 | 
					 | 
				
			||||||
	extensions.push_back("gd");
 | 
					 | 
				
			||||||
	if (ClassDB::class_exists("CSharpScript")) {
 | 
					 | 
				
			||||||
		extensions.push_back("cs");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	extensions.push_back("gdshader");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_add_builtin_input_map();
 | 
						_add_builtin_input_map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
 | 
						// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
 | 
				
			||||||
| 
						 | 
					@ -1505,7 +1534,15 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
	GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
 | 
						GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
 | 
				
			||||||
	// Keep the enum values in sync with the `DisplayServer::VSyncMode` enum.
 | 
						// Keep the enum values in sync with the `DisplayServer::VSyncMode` enum.
 | 
				
			||||||
	custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox");
 | 
						custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox");
 | 
				
			||||||
	custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
 | 
					
 | 
				
			||||||
 | 
						GLOBAL_DEF("display/window/frame_pacing/android/enable_frame_pacing", true);
 | 
				
			||||||
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/frame_pacing/android/swappy_mode", PROPERTY_HINT_ENUM, "pipeline_forced_on,auto_fps_pipeline_forced_on,auto_fps_auto_pipeline"), 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Safe:1,Separate");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
 | 
						GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
 | 
				
			||||||
	GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
 | 
						GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1548,6 +1585,7 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
 | 
				
			||||||
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_download_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
 | 
				
			||||||
	GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
 | 
						GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
 | 
				
			||||||
	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
 | 
						GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
 | 
				
			||||||
| 
						 | 
					@ -1563,13 +1601,18 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
	// installed by the scripts provided in the repository
 | 
						// installed by the scripts provided in the repository
 | 
				
			||||||
	// (check `misc/scripts/install_d3d12_sdk_windows.py`).
 | 
						// (check `misc/scripts/install_d3d12_sdk_windows.py`).
 | 
				
			||||||
	// For example, if the script installs 1.613.3, the default value must be 613.
 | 
						// For example, if the script installs 1.613.3, the default value must be 613.
 | 
				
			||||||
	GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 613);
 | 
						GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version", PROPERTY_HINT_RANGE, "0,10000,1,or_greater,hide_slider"), 613);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
 | 
						GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
 | 
				
			||||||
	GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
 | 
						GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GLOBAL_DEF("collada/use_ambient", false);
 | 
						GLOBAL_DEF("collada/use_ambient", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Input settings
 | 
				
			||||||
 | 
						GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
 | 
				
			||||||
 | 
						GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
 | 
				
			||||||
 | 
						GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
 | 
						// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
 | 
				
			||||||
	GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
 | 
						GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
 | 
				
			||||||
	GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
 | 
						GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
 | 
				
			||||||
| 
						 | 
					@ -1582,6 +1625,7 @@ ProjectSettings::ProjectSettings() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ProjectSettings::ProjectSettings(const String &p_path) {
 | 
					ProjectSettings::ProjectSettings(const String &p_path) {
 | 
				
			||||||
	if (load_custom(p_path) == OK) {
 | 
						if (load_custom(p_path) == OK) {
 | 
				
			||||||
 | 
							resource_path = p_path.get_base_dir();
 | 
				
			||||||
		project_loaded = true;
 | 
							project_loaded = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,10 +47,8 @@ public:
 | 
				
			||||||
	typedef HashMap<String, Variant> CustomMap;
 | 
						typedef HashMap<String, Variant> CustomMap;
 | 
				
			||||||
	static const String PROJECT_DATA_DIR_NAME_SUFFIX;
 | 
						static const String PROJECT_DATA_DIR_NAME_SUFFIX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum {
 | 
						// Properties that are not for built in values begin from this value, so builtin ones are displayed first.
 | 
				
			||||||
		// 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;
 | 
				
			||||||
		NO_BUILTIN_ORDER_BASE = 1 << 16
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	const static PackedStringArray get_required_features();
 | 
						const static PackedStringArray get_required_features();
 | 
				
			||||||
| 
						 | 
					@ -137,7 +135,8 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void _convert_to_last_version(int p_from_version);
 | 
						void _convert_to_last_version(int p_from_version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
 | 
						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);
 | 
						void _add_property_info_bind(const Dictionary &p_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										62
									
								
								engine/core/core_bind.compat.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								engine/core/core_bind.compat.inc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_bind.compat.inc                                                  */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace core_bind {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Semaphore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Semaphore::_post_bind_compat_93605() {
 | 
				
			||||||
 | 
						post(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Semaphore::_bind_compatibility_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("post"), &Semaphore::_post_bind_compat_93605);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String OS::_read_string_from_stdin_bind_compat_91201() {
 | 
				
			||||||
 | 
						return read_string_from_stdin(1024);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
 | 
				
			||||||
 | 
						return execute_with_pipe(p_path, p_arguments, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OS::_bind_compatibility_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace core_bind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
| 
						 | 
					@ -29,13 +29,12 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core_bind.h"
 | 
					#include "core_bind.h"
 | 
				
			||||||
 | 
					#include "core_bind.compat.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/crypto/crypto_core.h"
 | 
					#include "core/crypto/crypto_core.h"
 | 
				
			||||||
#include "core/debugger/engine_debugger.h"
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
#include "core/debugger/script_debugger.h"
 | 
					#include "core/debugger/script_debugger.h"
 | 
				
			||||||
#include "core/io/file_access_compressed.h"
 | 
					 | 
				
			||||||
#include "core/io/file_access_encrypted.h"
 | 
					 | 
				
			||||||
#include "core/io/marshalls.h"
 | 
					#include "core/io/marshalls.h"
 | 
				
			||||||
#include "core/math/geometry_2d.h"
 | 
					#include "core/math/geometry_2d.h"
 | 
				
			||||||
#include "core/math/geometry_3d.h"
 | 
					#include "core/math/geometry_3d.h"
 | 
				
			||||||
| 
						 | 
					@ -56,8 +55,11 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
 | 
				
			||||||
ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const String &p_path, Array r_progress) {
 | 
					ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const String &p_path, Array r_progress) {
 | 
				
			||||||
	float progress = 0;
 | 
						float progress = 0;
 | 
				
			||||||
	::ResourceLoader::ThreadLoadStatus tls = ::ResourceLoader::load_threaded_get_status(p_path, &progress);
 | 
						::ResourceLoader::ThreadLoadStatus tls = ::ResourceLoader::load_threaded_get_status(p_path, &progress);
 | 
				
			||||||
	r_progress.resize(1);
 | 
						// Default array should never be modified, it causes the hash of the method to change.
 | 
				
			||||||
	r_progress[0] = progress;
 | 
						if (!ClassDB::is_default_array_arg(r_progress)) {
 | 
				
			||||||
 | 
							r_progress.resize(1);
 | 
				
			||||||
 | 
							r_progress[0] = progress;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return (ThreadLoadStatus)tls;
 | 
						return (ThreadLoadStatus)tls;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,7 +73,7 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
 | 
				
			||||||
	Error err = OK;
 | 
						Error err = OK;
 | 
				
			||||||
	Ref<Resource> ret = ::ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
 | 
						Ref<Resource> ret = ::ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, ret, vformat("Error loading resource: '%s'.", p_path));
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,10 +113,15 @@ PackedStringArray ResourceLoader::get_dependencies(const String &p_path) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ResourceLoader::has_cached(const String &p_path) {
 | 
					bool ResourceLoader::has_cached(const String &p_path) {
 | 
				
			||||||
	String local_path = ProjectSettings::get_singleton()->localize_path(p_path);
 | 
						String local_path = ::ResourceLoader::_validate_local_path(p_path);
 | 
				
			||||||
	return ResourceCache::has(local_path);
 | 
						return ResourceCache::has(local_path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<Resource> ResourceLoader::get_cached_ref(const String &p_path) {
 | 
				
			||||||
 | 
						String local_path = ::ResourceLoader::_validate_local_path(p_path);
 | 
				
			||||||
 | 
						return ResourceCache::get_ref(local_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
 | 
					bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
 | 
				
			||||||
	return ::ResourceLoader::exists(p_path, p_type_hint);
 | 
						return ::ResourceLoader::exists(p_path, p_type_hint);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -123,9 +130,13 @@ ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) {
 | 
				
			||||||
	return ::ResourceLoader::get_resource_uid(p_path);
 | 
						return ::ResourceLoader::get_resource_uid(p_path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vector<String> ResourceLoader::list_directory(const String &p_directory) {
 | 
				
			||||||
 | 
						return ::ResourceLoader::list_directory(p_directory);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ResourceLoader::_bind_methods() {
 | 
					void ResourceLoader::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load_threaded_request", "path", "type_hint", "use_sub_threads", "cache_mode"), &ResourceLoader::load_threaded_request, DEFVAL(""), DEFVAL(false), DEFVAL(CACHE_MODE_REUSE));
 | 
						ClassDB::bind_method(D_METHOD("load_threaded_request", "path", "type_hint", "use_sub_threads", "cache_mode"), &ResourceLoader::load_threaded_request, DEFVAL(""), DEFVAL(false), DEFVAL(CACHE_MODE_REUSE));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &ResourceLoader::load_threaded_get_status, DEFVAL(Array()));
 | 
						ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &ResourceLoader::load_threaded_get_status, DEFVAL_ARRAY);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &ResourceLoader::load_threaded_get);
 | 
						ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &ResourceLoader::load_threaded_get);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
 | 
						ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
 | 
				
			||||||
| 
						 | 
					@ -135,8 +146,10 @@ void ResourceLoader::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &ResourceLoader::set_abort_on_missing_resources);
 | 
						ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &ResourceLoader::set_abort_on_missing_resources);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &ResourceLoader::get_dependencies);
 | 
						ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &ResourceLoader::get_dependencies);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("has_cached", "path"), &ResourceLoader::has_cached);
 | 
						ClassDB::bind_method(D_METHOD("has_cached", "path"), &ResourceLoader::has_cached);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_cached_ref", "path"), &ResourceLoader::get_cached_ref);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &ResourceLoader::exists, DEFVAL(""));
 | 
						ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &ResourceLoader::exists, DEFVAL(""));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_resource_uid", "path"), &ResourceLoader::get_resource_uid);
 | 
						ClassDB::bind_method(D_METHOD("get_resource_uid", "path"), &ResourceLoader::get_resource_uid);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("list_directory", "directory_path"), &ResourceLoader::list_directory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE);
 | 
						BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
 | 
						BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
 | 
				
			||||||
| 
						 | 
					@ -174,6 +187,10 @@ void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_form
 | 
				
			||||||
	::ResourceSaver::remove_resource_format_saver(p_format_saver);
 | 
						::ResourceSaver::remove_resource_format_saver(p_format_saver);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ResourceUID::ID ResourceSaver::get_resource_id_for_path(const String &p_path, bool p_generate) {
 | 
				
			||||||
 | 
						return ::ResourceSaver::get_resource_id_for_path(p_path, p_generate);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ResourceSaver *ResourceSaver::singleton = nullptr;
 | 
					ResourceSaver *ResourceSaver::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ResourceSaver::_bind_methods() {
 | 
					void ResourceSaver::_bind_methods() {
 | 
				
			||||||
| 
						 | 
					@ -181,6 +198,7 @@ void ResourceSaver::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions);
 | 
						ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver);
 | 
						ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_resource_id_for_path", "path", "generate"), &ResourceSaver::get_resource_id_for_path, DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_BITFIELD_FLAG(FLAG_NONE);
 | 
						BIND_BITFIELD_FLAG(FLAG_NONE);
 | 
				
			||||||
	BIND_BITFIELD_FLAG(FLAG_RELATIVE_PATHS);
 | 
						BIND_BITFIELD_FLAG(FLAG_RELATIVE_PATHS);
 | 
				
			||||||
| 
						 | 
					@ -288,8 +306,24 @@ Error OS::shell_show_in_file_manager(const String &p_path, bool p_open_folder) {
 | 
				
			||||||
	return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
 | 
						return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String OS::read_string_from_stdin() {
 | 
					String OS::read_string_from_stdin(int64_t p_buffer_size) {
 | 
				
			||||||
	return ::OS::get_singleton()->get_stdin_string();
 | 
						return ::OS::get_singleton()->get_stdin_string(p_buffer_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedByteArray OS::read_buffer_from_stdin(int64_t p_buffer_size) {
 | 
				
			||||||
 | 
						return ::OS::get_singleton()->get_stdin_buffer(p_buffer_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OS::StdHandleType OS::get_stdin_type() const {
 | 
				
			||||||
 | 
						return (OS::StdHandleType)::OS::get_singleton()->get_stdin_type();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OS::StdHandleType OS::get_stdout_type() const {
 | 
				
			||||||
 | 
						return (OS::StdHandleType)::OS::get_singleton()->get_stdout_type();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OS::StdHandleType OS::get_stderr_type() const {
 | 
				
			||||||
 | 
						return (OS::StdHandleType)::OS::get_singleton()->get_stderr_type();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
 | 
					int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
 | 
				
			||||||
| 
						 | 
					@ -300,19 +334,22 @@ int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r
 | 
				
			||||||
	String pipe;
 | 
						String pipe;
 | 
				
			||||||
	int exitcode = 0;
 | 
						int exitcode = 0;
 | 
				
			||||||
	Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr, nullptr, p_open_console);
 | 
						Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr, nullptr, p_open_console);
 | 
				
			||||||
	r_output.push_back(pipe);
 | 
						// Default array should never be modified, it causes the hash of the method to change.
 | 
				
			||||||
 | 
						if (!ClassDB::is_default_array_arg(r_output)) {
 | 
				
			||||||
 | 
							r_output.push_back(pipe);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (err != OK) {
 | 
						if (err != OK) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return exitcode;
 | 
						return exitcode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Dictionary OS::execute_with_pipe(const String &p_path, const Vector<String> &p_arguments) {
 | 
					Dictionary OS::execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking) {
 | 
				
			||||||
	List<String> args;
 | 
						List<String> args;
 | 
				
			||||||
	for (const String &arg : p_arguments) {
 | 
						for (const String &arg : p_arguments) {
 | 
				
			||||||
		args.push_back(arg);
 | 
							args.push_back(arg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ::OS::get_singleton()->execute_with_pipe(p_path, args);
 | 
						return ::OS::get_singleton()->execute_with_pipe(p_path, args, p_blocking);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int OS::create_instance(const Vector<String> &p_arguments) {
 | 
					int OS::create_instance(const Vector<String> &p_arguments) {
 | 
				
			||||||
| 
						 | 
					@ -385,6 +422,10 @@ String OS::get_version() const {
 | 
				
			||||||
	return ::OS::get_singleton()->get_version();
 | 
						return ::OS::get_singleton()->get_version();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String OS::get_version_alias() const {
 | 
				
			||||||
 | 
						return ::OS::get_singleton()->get_version_alias();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector<String> OS::get_video_adapter_driver_info() const {
 | 
					Vector<String> OS::get_video_adapter_driver_info() const {
 | 
				
			||||||
	return ::OS::get_singleton()->get_video_adapter_driver_info();
 | 
						return ::OS::get_singleton()->get_video_adapter_driver_info();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -450,11 +491,11 @@ Error OS::set_thread_name(const String &p_name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::Thread::ID OS::get_thread_caller_id() const {
 | 
					::Thread::ID OS::get_thread_caller_id() const {
 | 
				
			||||||
	return ::Thread::get_caller_id();
 | 
						return ::Thread::get_caller_id();
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::Thread::ID OS::get_main_thread_id() const {
 | 
					::Thread::ID OS::get_main_thread_id() const {
 | 
				
			||||||
	return ::Thread::get_main_id();
 | 
						return ::Thread::get_main_id();
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool OS::has_feature(const String &p_feature) const {
 | 
					bool OS::has_feature(const String &p_feature) const {
 | 
				
			||||||
	const bool *value_ptr = feature_cache.getptr(p_feature);
 | 
						const bool *value_ptr = feature_cache.getptr(p_feature);
 | 
				
			||||||
| 
						 | 
					@ -538,6 +579,11 @@ String OS::get_cache_dir() const {
 | 
				
			||||||
	return ::OS::get_singleton()->get_cache_path();
 | 
						return ::OS::get_singleton()->get_cache_path();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String OS::get_temp_dir() const {
 | 
				
			||||||
 | 
						// Exposed as `get_temp_dir()` instead of `get_temp_path()` for consistency with other exposed OS methods.
 | 
				
			||||||
 | 
						return ::OS::get_singleton()->get_temp_path();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool OS::is_debug_build() const {
 | 
					bool OS::is_debug_build() const {
 | 
				
			||||||
#ifdef DEBUG_ENABLED
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
| 
						 | 
					@ -610,9 +656,15 @@ void OS::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
 | 
						ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::execute_with_pipe);
 | 
						ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL_ARRAY, DEFVAL(false), DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments", "blocking"), &OS::execute_with_pipe, DEFVAL(true));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
 | 
						ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
 | 
						ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
 | 
				
			||||||
| 
						 | 
					@ -630,6 +682,7 @@ void OS::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
 | 
						ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
 | 
						ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version);
 | 
						ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_version_alias"), &OS::get_version_alias);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
 | 
						ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
 | 
						ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -660,6 +713,7 @@ void OS::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_config_dir"), &OS::get_config_dir);
 | 
						ClassDB::bind_method(D_METHOD("get_config_dir"), &OS::get_config_dir);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_data_dir"), &OS::get_data_dir);
 | 
						ClassDB::bind_method(D_METHOD("get_data_dir"), &OS::get_data_dir);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir);
 | 
						ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_temp_dir"), &OS::get_temp_dir);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id);
 | 
						ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string);
 | 
						ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string);
 | 
				
			||||||
| 
						 | 
					@ -692,6 +746,7 @@ void OS::_bind_methods() {
 | 
				
			||||||
	BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
 | 
						BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
 | 
						BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(RENDERING_DRIVER_D3D12);
 | 
						BIND_ENUM_CONSTANT(RENDERING_DRIVER_D3D12);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(RENDERING_DRIVER_METAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP);
 | 
						BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM);
 | 
						BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM);
 | 
				
			||||||
| 
						 | 
					@ -701,6 +756,12 @@ void OS::_bind_methods() {
 | 
				
			||||||
	BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC);
 | 
						BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
 | 
						BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES);
 | 
						BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(STD_HANDLE_INVALID);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(STD_HANDLE_CONSOLE);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(STD_HANDLE_FILE);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(STD_HANDLE_PIPE);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////// Geometry2D //////
 | 
					////// Geometry2D //////
 | 
				
			||||||
| 
						 | 
					@ -901,6 +962,19 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypedArray<Point2i> Geometry2D::bresenham_line(const Point2i &p_from, const Point2i &p_to) {
 | 
				
			||||||
 | 
						Vector<Point2i> points = ::Geometry2D::bresenham_line(p_from, p_to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypedArray<Point2i> result;
 | 
				
			||||||
 | 
						result.resize(points.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < points.size(); i++) {
 | 
				
			||||||
 | 
							result[i] = points[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Geometry2D::_bind_methods() {
 | 
					void Geometry2D::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &Geometry2D::is_point_in_circle);
 | 
						ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &Geometry2D::is_point_in_circle);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &Geometry2D::segment_intersects_circle);
 | 
						ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &Geometry2D::segment_intersects_circle);
 | 
				
			||||||
| 
						 | 
					@ -935,6 +1009,8 @@ void Geometry2D::_bind_methods() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &Geometry2D::make_atlas);
 | 
						ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &Geometry2D::make_atlas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("bresenham_line", "from", "to"), &Geometry2D::bresenham_line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_ENUM_CONSTANT(OPERATION_UNION);
 | 
						BIND_ENUM_CONSTANT(OPERATION_UNION);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE);
 | 
						BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
 | 
						BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
 | 
				
			||||||
| 
						 | 
					@ -1209,14 +1285,15 @@ bool Semaphore::try_wait() {
 | 
				
			||||||
	return semaphore.try_wait();
 | 
						return semaphore.try_wait();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Semaphore::post() {
 | 
					void Semaphore::post(int p_count) {
 | 
				
			||||||
	semaphore.post();
 | 
						ERR_FAIL_COND(p_count <= 0);
 | 
				
			||||||
 | 
						semaphore.post(p_count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Semaphore::_bind_methods() {
 | 
					void Semaphore::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("wait"), &Semaphore::wait);
 | 
						ClassDB::bind_method(D_METHOD("wait"), &Semaphore::wait);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("try_wait"), &Semaphore::try_wait);
 | 
						ClassDB::bind_method(D_METHOD("try_wait"), &Semaphore::try_wait);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("post"), &Semaphore::post);
 | 
						ClassDB::bind_method(D_METHOD("post", "count"), &Semaphore::post, DEFVAL(1));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////// Mutex //////
 | 
					////// Mutex //////
 | 
				
			||||||
| 
						 | 
					@ -1280,7 +1357,7 @@ void Thread::_start_func(void *ud) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ce.error != Callable::CallError::CALL_OK) {
 | 
						if (ce.error != Callable::CallError::CALL_OK) {
 | 
				
			||||||
		ERR_FAIL_MSG("Could not call function '" + func_name + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce) + ".");
 | 
							ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %d: %s.", func_name, t->get_id(), Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1404,6 +1481,11 @@ Variant ClassDB::instantiate(const StringName &p_class) const {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ClassDB::APIType ClassDB::class_get_api_type(const StringName &p_class) const {
 | 
				
			||||||
 | 
						::ClassDB::APIType api_type = ::ClassDB::get_api_type(p_class);
 | 
				
			||||||
 | 
						return (APIType)api_type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ClassDB::class_has_signal(const StringName &p_class, const StringName &p_signal) const {
 | 
					bool ClassDB::class_has_signal(const StringName &p_class, const StringName &p_signal) const {
 | 
				
			||||||
	return ::ClassDB::has_signal(p_class, p_signal);
 | 
						return ::ClassDB::has_signal(p_class, p_signal);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1440,6 +1522,14 @@ TypedArray<Dictionary> ClassDB::class_get_property_list(const StringName &p_clas
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StringName ClassDB::class_get_property_getter(const StringName &p_class, const StringName &p_property) {
 | 
				
			||||||
 | 
						return ::ClassDB::get_property_getter(p_class, p_property);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StringName ClassDB::class_get_property_setter(const StringName &p_class, const StringName &p_property) {
 | 
				
			||||||
 | 
						return ::ClassDB::get_property_setter(p_class, p_property);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Variant ClassDB::class_get_property(Object *p_object, const StringName &p_property) const {
 | 
					Variant ClassDB::class_get_property(Object *p_object, const StringName &p_property) const {
 | 
				
			||||||
	Variant ret;
 | 
						Variant ret;
 | 
				
			||||||
	::ClassDB::get_property(p_object, p_property, ret);
 | 
						::ClassDB::get_property(p_object, p_property, ret);
 | 
				
			||||||
| 
						 | 
					@ -1492,6 +1582,23 @@ TypedArray<Dictionary> ClassDB::class_get_method_list(const StringName &p_class,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Variant ClassDB::class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) {
 | 
				
			||||||
 | 
						if (p_argcount < 2) {
 | 
				
			||||||
 | 
							r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
 | 
				
			||||||
 | 
							return Variant::NIL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!p_arguments[0]->is_string() || !p_arguments[1]->is_string()) {
 | 
				
			||||||
 | 
							r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
 | 
				
			||||||
 | 
							return Variant::NIL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						StringName class_ = *p_arguments[0];
 | 
				
			||||||
 | 
						StringName method = *p_arguments[1];
 | 
				
			||||||
 | 
						const MethodBind *bind = ::ClassDB::get_method(class_, method);
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V_MSG(bind, Variant::NIL, "Cannot find static method.");
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!bind->is_static(), Variant::NIL, "Method is not static.");
 | 
				
			||||||
 | 
						return bind->call(nullptr, p_arguments + 2, p_argcount - 2, r_call_error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PackedStringArray ClassDB::class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance) const {
 | 
					PackedStringArray ClassDB::class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance) const {
 | 
				
			||||||
	List<String> constants;
 | 
						List<String> constants;
 | 
				
			||||||
	::ClassDB::get_integer_constant_list(p_class, &constants, p_no_inheritance);
 | 
						::ClassDB::get_integer_constant_list(p_class, &constants, p_no_inheritance);
 | 
				
			||||||
| 
						 | 
					@ -1575,7 +1682,7 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List
 | 
				
			||||||
				pf == "class_has_method" || pf == "class_get_method_list" ||
 | 
									pf == "class_has_method" || pf == "class_get_method_list" ||
 | 
				
			||||||
				pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" ||
 | 
									pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" ||
 | 
				
			||||||
				pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" ||
 | 
									pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" ||
 | 
				
			||||||
				pf == "is_class_enabled" || pf == "is_class_enum_bitfield");
 | 
									pf == "is_class_enabled" || pf == "is_class_enum_bitfield" || pf == "class_get_api_type");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (first_argument_is_class || pf == "is_parent_class") {
 | 
						if (first_argument_is_class || pf == "is_parent_class") {
 | 
				
			||||||
		for (const String &E : get_class_list()) {
 | 
							for (const String &E : get_class_list()) {
 | 
				
			||||||
| 
						 | 
					@ -1596,11 +1703,15 @@ void ClassDB::_bind_methods() {
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &ClassDB::can_instantiate);
 | 
						::ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &ClassDB::can_instantiate);
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("instantiate", "class"), &ClassDB::instantiate);
 | 
						::ClassDB::bind_method(D_METHOD("instantiate", "class"), &ClassDB::instantiate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						::ClassDB::bind_method(D_METHOD("class_get_api_type", "class"), &ClassDB::class_get_api_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &ClassDB::class_has_signal);
 | 
						::ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &ClassDB::class_has_signal);
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &ClassDB::class_get_signal);
 | 
						::ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &ClassDB::class_get_signal);
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_signal_list", "class", "no_inheritance"), &ClassDB::class_get_signal_list, DEFVAL(false));
 | 
						::ClassDB::bind_method(D_METHOD("class_get_signal_list", "class", "no_inheritance"), &ClassDB::class_get_signal_list, DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_property_list", "class", "no_inheritance"), &ClassDB::class_get_property_list, DEFVAL(false));
 | 
						::ClassDB::bind_method(D_METHOD("class_get_property_list", "class", "no_inheritance"), &ClassDB::class_get_property_list, DEFVAL(false));
 | 
				
			||||||
 | 
						::ClassDB::bind_method(D_METHOD("class_get_property_getter", "class", "property"), &ClassDB::class_get_property_getter);
 | 
				
			||||||
 | 
						::ClassDB::bind_method(D_METHOD("class_get_property_setter", "class", "property"), &ClassDB::class_get_property_setter);
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property);
 | 
						::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property);
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::class_set_property);
 | 
						::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::class_set_property);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1612,6 +1723,8 @@ void ClassDB::_bind_methods() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false));
 | 
						::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "class_call_static", &ClassDB::class_call_static, MethodInfo("class_call_static", PropertyInfo(Variant::STRING_NAME, "class"), PropertyInfo(Variant::STRING_NAME, "method")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false));
 | 
						::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("class_has_integer_constant", "class", "name"), &ClassDB::class_has_integer_constant);
 | 
						::ClassDB::bind_method(D_METHOD("class_has_integer_constant", "class", "name"), &ClassDB::class_has_integer_constant);
 | 
				
			||||||
| 
						 | 
					@ -1625,6 +1738,12 @@ void ClassDB::_bind_methods() {
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false));
 | 
						::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
 | 
						::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(API_CORE);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(API_EDITOR);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(API_EXTENSION);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(API_EDITOR_EXTENSION);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(API_NONE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace special
 | 
					} // namespace special
 | 
				
			||||||
| 
						 | 
					@ -1737,8 +1856,8 @@ Object *Engine::get_singleton_object(const StringName &p_name) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Engine::register_singleton(const StringName &p_name, Object *p_object) {
 | 
					void Engine::register_singleton(const StringName &p_name, Object *p_object) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(has_singleton(p_name), "Singleton already registered: " + String(p_name));
 | 
						ERR_FAIL_COND_MSG(has_singleton(p_name), vformat("Singleton already registered: '%s'.", String(p_name)));
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!String(p_name).is_valid_identifier(), "Singleton name is not a valid identifier: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!String(p_name).is_valid_ascii_identifier(), vformat("Singleton name is not a valid identifier: '%s'.", p_name));
 | 
				
			||||||
	::Engine::Singleton s;
 | 
						::Engine::Singleton s;
 | 
				
			||||||
	s.class_name = p_name;
 | 
						s.class_name = p_name;
 | 
				
			||||||
	s.name = p_name;
 | 
						s.name = p_name;
 | 
				
			||||||
| 
						 | 
					@ -1748,8 +1867,8 @@ void Engine::register_singleton(const StringName &p_name, Object *p_object) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Engine::unregister_singleton(const StringName &p_name) {
 | 
					void Engine::unregister_singleton(const StringName &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!has_singleton(p_name), "Attempt to remove unregistered singleton: " + String(p_name));
 | 
						ERR_FAIL_COND_MSG(!has_singleton(p_name), vformat("Attempt to remove unregistered singleton: '%s'.", String(p_name)));
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!::Engine::get_singleton()->is_singleton_user_created(p_name), "Attempt to remove non-user created singleton: " + String(p_name));
 | 
						ERR_FAIL_COND_MSG(!::Engine::get_singleton()->is_singleton_user_created(p_name), vformat("Attempt to remove non-user created singleton: '%s'.", String(p_name)));
 | 
				
			||||||
	::Engine::get_singleton()->remove_singleton(p_name);
 | 
						::Engine::get_singleton()->remove_singleton(p_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1787,10 +1906,22 @@ bool Engine::is_editor_hint() const {
 | 
				
			||||||
	return ::Engine::get_singleton()->is_editor_hint();
 | 
						return ::Engine::get_singleton()->is_editor_hint();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_embedded_in_editor() const {
 | 
				
			||||||
 | 
						return ::Engine::get_singleton()->is_embedded_in_editor();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String Engine::get_write_movie_path() const {
 | 
					String Engine::get_write_movie_path() const {
 | 
				
			||||||
	return ::Engine::get_singleton()->get_write_movie_path();
 | 
						return ::Engine::get_singleton()->get_write_movie_path();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_print_to_stdout(bool p_enabled) {
 | 
				
			||||||
 | 
						::Engine::get_singleton()->set_print_to_stdout(p_enabled);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_printing_to_stdout() const {
 | 
				
			||||||
 | 
						return ::Engine::get_singleton()->is_printing_to_stdout();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Engine::set_print_error_messages(bool p_enabled) {
 | 
					void Engine::set_print_error_messages(bool p_enabled) {
 | 
				
			||||||
	::Engine::get_singleton()->set_print_error_messages(p_enabled);
 | 
						::Engine::get_singleton()->set_print_error_messages(p_enabled);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1856,13 +1987,18 @@ void Engine::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_script_language", "index"), &Engine::get_script_language);
 | 
						ClassDB::bind_method(D_METHOD("get_script_language", "index"), &Engine::get_script_language);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint);
 | 
						ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_embedded_in_editor"), &Engine::is_embedded_in_editor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_write_movie_path"), &Engine::get_write_movie_path);
 | 
						ClassDB::bind_method(D_METHOD("get_write_movie_path"), &Engine::get_write_movie_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("set_print_to_stdout", "enabled"), &Engine::set_print_to_stdout);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_printing_to_stdout"), &Engine::is_printing_to_stdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &Engine::set_print_error_messages);
 | 
						ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &Engine::set_print_error_messages);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &Engine::is_printing_error_messages);
 | 
						ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &Engine::is_printing_error_messages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
 | 
				
			||||||
 | 
						ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_to_stdout"), "set_print_to_stdout", "is_printing_to_stdout");
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame");
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps");
 | 
				
			||||||
| 
						 | 
					@ -1881,14 +2017,14 @@ bool EngineDebugger::is_active() {
 | 
				
			||||||
void EngineDebugger::register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler) {
 | 
					void EngineDebugger::register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler) {
 | 
				
			||||||
	ERR_FAIL_COND(p_profiler.is_null());
 | 
						ERR_FAIL_COND(p_profiler.is_null());
 | 
				
			||||||
	ERR_FAIL_COND_MSG(p_profiler->is_bound(), "Profiler already registered.");
 | 
						ERR_FAIL_COND_MSG(p_profiler->is_bound(), "Profiler already registered.");
 | 
				
			||||||
	ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler name already in use: " + p_name);
 | 
						ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), vformat("Profiler name already in use: '%s'.", p_name));
 | 
				
			||||||
	Error err = p_profiler->bind(p_name);
 | 
						Error err = p_profiler->bind(p_name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(err != OK, "Profiler failed to register with error: " + itos(err));
 | 
						ERR_FAIL_COND_MSG(err != OK, vformat("Profiler failed to register with error: %d.", err));
 | 
				
			||||||
	profilers.insert(p_name, p_profiler);
 | 
						profilers.insert(p_name, p_profiler);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
					void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name));
 | 
				
			||||||
	profilers[p_name]->unbind();
 | 
						profilers[p_name]->unbind();
 | 
				
			||||||
	profilers.erase(p_name);
 | 
						profilers.erase(p_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1912,7 +2048,7 @@ void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
 | 
					void EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), vformat("Capture already registered: '%s'.", p_name));
 | 
				
			||||||
	captures.insert(p_name, p_callable);
 | 
						captures.insert(p_name, p_callable);
 | 
				
			||||||
	Callable &c = captures[p_name];
 | 
						Callable &c = captures[p_name];
 | 
				
			||||||
	::EngineDebugger::Capture capture(&c, &EngineDebugger::call_capture);
 | 
						::EngineDebugger::Capture capture(&c, &EngineDebugger::call_capture);
 | 
				
			||||||
| 
						 | 
					@ -1920,7 +2056,7 @@ void EngineDebugger::register_message_capture(const StringName &p_name, const Ca
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::unregister_message_capture(const StringName &p_name) {
 | 
					void EngineDebugger::unregister_message_capture(const StringName &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name));
 | 
				
			||||||
	::EngineDebugger::unregister_message_capture(p_name);
 | 
						::EngineDebugger::unregister_message_capture(p_name);
 | 
				
			||||||
	captures.erase(p_name);
 | 
						captures.erase(p_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1954,8 +2090,8 @@ Error EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Arra
 | 
				
			||||||
	Variant retval;
 | 
						Variant retval;
 | 
				
			||||||
	Callable::CallError err;
 | 
						Callable::CallError err;
 | 
				
			||||||
	capture.callp(args, 2, retval, err);
 | 
						capture.callp(args, 2, retval, err);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err));
 | 
						ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, vformat("Error calling 'capture' to callable: %s.", Variant::get_callable_error_text(capture, args, 2, err)));
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool.");
 | 
						ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, vformat("Error calling 'capture' to callable: '%s'. Return type is not bool.", String(capture)));
 | 
				
			||||||
	r_captured = retval;
 | 
						r_captured = retval;
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,11 +32,8 @@
 | 
				
			||||||
#define CORE_BIND_H
 | 
					#define CORE_BIND_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/debugger/engine_profiler.h"
 | 
					#include "core/debugger/engine_profiler.h"
 | 
				
			||||||
#include "core/io/image.h"
 | 
					 | 
				
			||||||
#include "core/io/resource_loader.h"
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
#include "core/io/resource_saver.h"
 | 
					#include "core/io/resource_saver.h"
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					 | 
				
			||||||
#include "core/os/os.h"
 | 
					 | 
				
			||||||
#include "core/os/semaphore.h"
 | 
					#include "core/os/semaphore.h"
 | 
				
			||||||
#include "core/os/thread.h"
 | 
					#include "core/os/thread.h"
 | 
				
			||||||
#include "core/templates/safe_refcount.h"
 | 
					#include "core/templates/safe_refcount.h"
 | 
				
			||||||
| 
						 | 
					@ -73,7 +70,7 @@ public:
 | 
				
			||||||
	static ResourceLoader *get_singleton() { return singleton; }
 | 
						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);
 | 
						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 = Array());
 | 
						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_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);
 | 
						Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
 | 
				
			||||||
| 
						 | 
					@ -83,9 +80,12 @@ public:
 | 
				
			||||||
	void set_abort_on_missing_resources(bool p_abort);
 | 
						void set_abort_on_missing_resources(bool p_abort);
 | 
				
			||||||
	PackedStringArray get_dependencies(const String &p_path);
 | 
						PackedStringArray get_dependencies(const String &p_path);
 | 
				
			||||||
	bool has_cached(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 = "");
 | 
						bool exists(const String &p_path, const String &p_type_hint = "");
 | 
				
			||||||
	ResourceUID::ID get_resource_uid(const String &p_path);
 | 
						ResourceUID::ID get_resource_uid(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<String> list_directory(const String &p_directory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ResourceLoader() { singleton = this; }
 | 
						ResourceLoader() { singleton = this; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,6 +115,8 @@ public:
 | 
				
			||||||
	void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
 | 
						void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
 | 
				
			||||||
	void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
 | 
						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; }
 | 
						ResourceSaver() { singleton = this; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,16 +129,32 @@ protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
	static OS *singleton;
 | 
						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:
 | 
					public:
 | 
				
			||||||
	enum RenderingDriver {
 | 
						enum RenderingDriver {
 | 
				
			||||||
		RENDERING_DRIVER_VULKAN,
 | 
							RENDERING_DRIVER_VULKAN,
 | 
				
			||||||
		RENDERING_DRIVER_OPENGL3,
 | 
							RENDERING_DRIVER_OPENGL3,
 | 
				
			||||||
		RENDERING_DRIVER_D3D12,
 | 
							RENDERING_DRIVER_D3D12,
 | 
				
			||||||
 | 
							RENDERING_DRIVER_METAL,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PackedByteArray get_entropy(int p_bytes);
 | 
						PackedByteArray get_entropy(int p_bytes);
 | 
				
			||||||
	String get_system_ca_certificates();
 | 
						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 PackedStringArray get_connected_midi_inputs();
 | 
				
			||||||
	virtual void open_midi_inputs();
 | 
						virtual void open_midi_inputs();
 | 
				
			||||||
	virtual void close_midi_inputs();
 | 
						virtual void close_midi_inputs();
 | 
				
			||||||
| 
						 | 
					@ -157,9 +175,15 @@ public:
 | 
				
			||||||
	String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) 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;
 | 
						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 get_executable_path() const;
 | 
				
			||||||
	String read_string_from_stdin();
 | 
					
 | 
				
			||||||
	int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
 | 
						String read_string_from_stdin(int64_t p_buffer_size = 1024);
 | 
				
			||||||
	Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments);
 | 
						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_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
 | 
				
			||||||
	int create_instance(const Vector<String> &p_arguments);
 | 
						int create_instance(const Vector<String> &p_arguments);
 | 
				
			||||||
	Error kill(int p_pid);
 | 
						Error kill(int p_pid);
 | 
				
			||||||
| 
						 | 
					@ -182,6 +206,7 @@ public:
 | 
				
			||||||
	String get_name() const;
 | 
						String get_name() const;
 | 
				
			||||||
	String get_distribution_name() const;
 | 
						String get_distribution_name() const;
 | 
				
			||||||
	String get_version() const;
 | 
						String get_version() const;
 | 
				
			||||||
 | 
						String get_version_alias() const;
 | 
				
			||||||
	Vector<String> get_cmdline_args();
 | 
						Vector<String> get_cmdline_args();
 | 
				
			||||||
	Vector<String> get_cmdline_user_args();
 | 
						Vector<String> get_cmdline_user_args();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,6 +261,7 @@ public:
 | 
				
			||||||
	String get_config_dir() const;
 | 
						String get_config_dir() const;
 | 
				
			||||||
	String get_data_dir() const;
 | 
						String get_data_dir() const;
 | 
				
			||||||
	String get_cache_dir() const;
 | 
						String get_cache_dir() const;
 | 
				
			||||||
 | 
						String get_temp_dir() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error set_thread_name(const String &p_name);
 | 
						Error set_thread_name(const String &p_name);
 | 
				
			||||||
	::Thread::ID get_thread_caller_id() const;
 | 
						::Thread::ID get_thread_caller_id() const;
 | 
				
			||||||
| 
						 | 
					@ -315,6 +341,8 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Dictionary make_atlas(const Vector<Size2> &p_rects);
 | 
						Dictionary make_atlas(const Vector<Size2> &p_rects);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypedArray<Point2i> bresenham_line(const Point2i &p_from, const Point2i &p_to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Geometry2D() { singleton = this; }
 | 
						Geometry2D() { singleton = this; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -389,12 +417,17 @@ class Semaphore : public RefCounted {
 | 
				
			||||||
	GDCLASS(Semaphore, RefCounted);
 | 
						GDCLASS(Semaphore, RefCounted);
 | 
				
			||||||
	::Semaphore semaphore;
 | 
						::Semaphore semaphore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						void _post_bind_compat_93605();
 | 
				
			||||||
 | 
						static void _bind_compatibility_methods();
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	void wait();
 | 
						void wait();
 | 
				
			||||||
	bool try_wait();
 | 
						bool try_wait();
 | 
				
			||||||
	void post();
 | 
						void post(int p_count = 1);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Thread : public RefCounted {
 | 
					class Thread : public RefCounted {
 | 
				
			||||||
| 
						 | 
					@ -434,6 +467,14 @@ protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
						enum APIType {
 | 
				
			||||||
 | 
							API_CORE,
 | 
				
			||||||
 | 
							API_EDITOR,
 | 
				
			||||||
 | 
							API_EXTENSION,
 | 
				
			||||||
 | 
							API_EDITOR_EXTENSION,
 | 
				
			||||||
 | 
							API_NONE,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PackedStringArray get_class_list() const;
 | 
						PackedStringArray get_class_list() const;
 | 
				
			||||||
	PackedStringArray get_inheriters_from_class(const StringName &p_class) const;
 | 
						PackedStringArray get_inheriters_from_class(const StringName &p_class) const;
 | 
				
			||||||
	StringName get_parent_class(const StringName &p_class) const;
 | 
						StringName get_parent_class(const StringName &p_class) const;
 | 
				
			||||||
| 
						 | 
					@ -442,11 +483,14 @@ public:
 | 
				
			||||||
	bool can_instantiate(const StringName &p_class) const;
 | 
						bool can_instantiate(const StringName &p_class) const;
 | 
				
			||||||
	Variant 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;
 | 
						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;
 | 
						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_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;
 | 
						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;
 | 
						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;
 | 
						Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -457,6 +501,7 @@ public:
 | 
				
			||||||
	int class_get_method_argument_count(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;
 | 
						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;
 | 
						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;
 | 
						bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
 | 
				
			||||||
| 
						 | 
					@ -539,9 +584,14 @@ public:
 | 
				
			||||||
	void set_editor_hint(bool p_enabled);
 | 
						void set_editor_hint(bool p_enabled);
 | 
				
			||||||
	bool is_editor_hint() const;
 | 
						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.
 | 
						// `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;
 | 
						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);
 | 
						void set_print_error_messages(bool p_enabled);
 | 
				
			||||||
	bool is_printing_error_messages() const;
 | 
						bool is_printing_error_messages() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -611,6 +661,7 @@ VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
 | 
					VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
 | 
				
			||||||
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
 | 
					VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
 | 
					VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
 | 
				
			||||||
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
 | 
					VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
 | 
				
			||||||
| 
						 | 
					@ -618,4 +669,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
 | 
					VARIANT_ENUM_CAST(core_bind::Thread::Priority);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::special::ClassDB::APIType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // CORE_BIND_H
 | 
					#endif // CORE_BIND_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,8 +200,8 @@ def make_license_header(target, source, env):
 | 
				
			||||||
            tag, content = reader.next_tag()
 | 
					            tag, content = reader.next_tag()
 | 
				
			||||||
            if tag in ("Files", "Copyright", "License"):
 | 
					            if tag in ("Files", "Copyright", "License"):
 | 
				
			||||||
                part[tag] = content[:]
 | 
					                part[tag] = content[:]
 | 
				
			||||||
            elif tag == "Comment":
 | 
					            elif tag == "Comment" and part:
 | 
				
			||||||
                # attach part to named project
 | 
					                # attach non-empty part to named project
 | 
				
			||||||
                projects[content[0]] = projects.get(content[0], []) + [part]
 | 
					                projects[content[0]] = projects.get(content[0], []) + [part]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if not tag or not reader.current:
 | 
					            if not tag or not reader.current:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,6 @@
 | 
				
			||||||
#include "core/input/input_event.h"
 | 
					#include "core/input/input_event.h"
 | 
				
			||||||
#include "core/object/class_db.h"
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
#include "core/os/keyboard.h"
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
#include "core/templates/hash_set.h"
 | 
					 | 
				
			||||||
#include "core/variant/variant.h"
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct _CoreConstant {
 | 
					struct _CoreConstant {
 | 
				
			||||||
| 
						 | 
					@ -671,11 +670,14 @@ void register_global_constants() {
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
 | 
						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_LOCALE_ID);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
 | 
				
			||||||
	BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
 | 
						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_ENUM_CONSTANT(PROPERTY_HINT_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@
 | 
				
			||||||
#define CORE_CONSTANTS_H
 | 
					#define CORE_CONSTANTS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/string/string_name.h"
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
#include "core/templates/hash_set.h"
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CoreConstants {
 | 
					class CoreConstants {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,61 +34,56 @@
 | 
				
			||||||
#include "core/string/string_name.h"
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CoreStringNames {
 | 
					class CoreStringNames {
 | 
				
			||||||
	friend void register_core_types();
 | 
						inline static CoreStringNames *singleton = nullptr;
 | 
				
			||||||
	friend void unregister_core_types();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
	static void create() { singleton = memnew(CoreStringNames); }
 | 
						static void create() { singleton = memnew(CoreStringNames); }
 | 
				
			||||||
	static void free() {
 | 
						static void free() {
 | 
				
			||||||
		memdelete(singleton);
 | 
							memdelete(singleton);
 | 
				
			||||||
		singleton = nullptr;
 | 
							singleton = nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CoreStringNames();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	_FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; }
 | 
						_FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static CoreStringNames *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");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName free_; // "free", conflict with C++ keyword.
 | 
						const StringName x = StaticCString::create("x");
 | 
				
			||||||
	StringName changed;
 | 
						const StringName y = StaticCString::create("y");
 | 
				
			||||||
	StringName script;
 | 
						const StringName z = StaticCString::create("z");
 | 
				
			||||||
	StringName script_changed;
 | 
						const StringName w = StaticCString::create("w");
 | 
				
			||||||
	StringName _iter_init;
 | 
						const StringName r = StaticCString::create("r");
 | 
				
			||||||
	StringName _iter_next;
 | 
						const StringName g = StaticCString::create("g");
 | 
				
			||||||
	StringName _iter_get;
 | 
						const StringName b = StaticCString::create("b");
 | 
				
			||||||
	StringName get_rid;
 | 
						const StringName a = StaticCString::create("a");
 | 
				
			||||||
	StringName _to_string;
 | 
						const StringName position = StaticCString::create("position");
 | 
				
			||||||
	StringName _custom_features;
 | 
						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");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName x;
 | 
						const StringName call = StaticCString::create("call");
 | 
				
			||||||
	StringName y;
 | 
						const StringName call_deferred = StaticCString::create("call_deferred");
 | 
				
			||||||
	StringName z;
 | 
						const StringName bind = StaticCString::create("bind");
 | 
				
			||||||
	StringName w;
 | 
						const StringName notification = StaticCString::create("notification");
 | 
				
			||||||
	StringName r;
 | 
						const StringName property_list_changed = StaticCString::create("property_list_changed");
 | 
				
			||||||
	StringName g;
 | 
					 | 
				
			||||||
	StringName b;
 | 
					 | 
				
			||||||
	StringName a;
 | 
					 | 
				
			||||||
	StringName position;
 | 
					 | 
				
			||||||
	StringName size;
 | 
					 | 
				
			||||||
	StringName end;
 | 
					 | 
				
			||||||
	StringName basis;
 | 
					 | 
				
			||||||
	StringName origin;
 | 
					 | 
				
			||||||
	StringName normal;
 | 
					 | 
				
			||||||
	StringName d;
 | 
					 | 
				
			||||||
	StringName h;
 | 
					 | 
				
			||||||
	StringName s;
 | 
					 | 
				
			||||||
	StringName v;
 | 
					 | 
				
			||||||
	StringName r8;
 | 
					 | 
				
			||||||
	StringName g8;
 | 
					 | 
				
			||||||
	StringName b8;
 | 
					 | 
				
			||||||
	StringName a8;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	StringName call;
 | 
					 | 
				
			||||||
	StringName call_deferred;
 | 
					 | 
				
			||||||
	StringName bind;
 | 
					 | 
				
			||||||
	StringName notification;
 | 
					 | 
				
			||||||
	StringName property_list_changed;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name
 | 
					#define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@ class AESContext : public RefCounted {
 | 
				
			||||||
	GDCLASS(AESContext, RefCounted);
 | 
						GDCLASS(AESContext, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	enum Mode {
 | 
						enum Mode : int32_t {
 | 
				
			||||||
		MODE_ECB_ENCRYPT,
 | 
							MODE_ECB_ENCRYPT,
 | 
				
			||||||
		MODE_ECB_DECRYPT,
 | 
							MODE_ECB_DECRYPT,
 | 
				
			||||||
		MODE_CBC_ENCRYPT,
 | 
							MODE_CBC_ENCRYPT,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,16 +30,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "crypto.h"
 | 
					#include "crypto.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/engine.h"
 | 
					 | 
				
			||||||
#include "core/io/certs_compressed.gen.h"
 | 
					 | 
				
			||||||
#include "core/io/compression.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Resources
 | 
					/// Resources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CryptoKey *(*CryptoKey::_create)() = nullptr;
 | 
					CryptoKey *(*CryptoKey::_create)(bool p_notify_postinitialize) = nullptr;
 | 
				
			||||||
CryptoKey *CryptoKey::create() {
 | 
					CryptoKey *CryptoKey::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -52,10 +48,10 @@ void CryptoKey::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
X509Certificate *(*X509Certificate::_create)() = nullptr;
 | 
					X509Certificate *(*X509Certificate::_create)(bool p_notify_postinitialize) = nullptr;
 | 
				
			||||||
X509Certificate *X509Certificate::create() {
 | 
					X509Certificate *X509Certificate::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -116,10 +112,10 @@ void HMACContext::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
 | 
						ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HMACContext *(*HMACContext::_create)() = nullptr;
 | 
					HMACContext *(*HMACContext::_create)(bool p_notify_postinitialize) = nullptr;
 | 
				
			||||||
HMACContext *HMACContext::create() {
 | 
					HMACContext *HMACContext::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
 | 
						ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -127,10 +123,10 @@ HMACContext *HMACContext::create() {
 | 
				
			||||||
/// Crypto
 | 
					/// Crypto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void (*Crypto::_load_default_certificates)(const String &p_path) = nullptr;
 | 
					void (*Crypto::_load_default_certificates)(const String &p_path) = nullptr;
 | 
				
			||||||
Crypto *(*Crypto::_create)() = nullptr;
 | 
					Crypto *(*Crypto::_create)(bool p_notify_postinitialize) = nullptr;
 | 
				
			||||||
Crypto *Crypto::create() {
 | 
					Crypto *Crypto::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled.");
 | 
						ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -240,7 +236,7 @@ Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const Str
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ERR_FAIL_V(ERR_INVALID_PARAMETER);
 | 
							ERR_FAIL_V(ERR_INVALID_PARAMETER);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save Crypto resource to file '" + p_path + "'.");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path));
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,10 +42,10 @@ class CryptoKey : public Resource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
	static CryptoKey *(*_create)();
 | 
						static CryptoKey *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static CryptoKey *create();
 | 
						static CryptoKey *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
	virtual Error load(const String &p_path, bool p_public_only = false) = 0;
 | 
						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 Error save(const String &p_path, bool p_public_only = false) = 0;
 | 
				
			||||||
	virtual String save_to_string(bool p_public_only = false) = 0;
 | 
						virtual String save_to_string(bool p_public_only = false) = 0;
 | 
				
			||||||
| 
						 | 
					@ -58,10 +58,10 @@ class X509Certificate : public Resource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
	static X509Certificate *(*_create)();
 | 
						static X509Certificate *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static X509Certificate *create();
 | 
						static X509Certificate *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
	virtual Error load(const String &p_path) = 0;
 | 
						virtual Error load(const String &p_path) = 0;
 | 
				
			||||||
	virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
 | 
						virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
 | 
				
			||||||
	virtual Error save(const String &p_path) = 0;
 | 
						virtual Error save(const String &p_path) = 0;
 | 
				
			||||||
| 
						 | 
					@ -106,10 +106,10 @@ class HMACContext : public RefCounted {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
	static HMACContext *(*_create)();
 | 
						static HMACContext *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static HMACContext *create();
 | 
						static HMACContext *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) = 0;
 | 
						virtual Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) = 0;
 | 
				
			||||||
	virtual Error update(const PackedByteArray &p_data) = 0;
 | 
						virtual Error update(const PackedByteArray &p_data) = 0;
 | 
				
			||||||
| 
						 | 
					@ -124,11 +124,11 @@ class Crypto : public RefCounted {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
	static Crypto *(*_create)();
 | 
						static Crypto *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
	static void (*_load_default_certificates)(const String &p_path);
 | 
						static void (*_load_default_certificates)(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static Crypto *create();
 | 
						static Crypto *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
	static void load_default_certificates(const String &p_path);
 | 
						static void load_default_certificates(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual PackedByteArray generate_random_bytes(int p_bytes) = 0;
 | 
						virtual PackedByteArray generate_random_bytes(int p_bytes) = 0;
 | 
				
			||||||
| 
						 | 
					@ -155,6 +155,10 @@ public:
 | 
				
			||||||
	virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 | 
						virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 | 
				
			||||||
	virtual bool handles_type(const String &p_type) const override;
 | 
						virtual bool handles_type(const String &p_type) const override;
 | 
				
			||||||
	virtual String get_resource_type(const String &p_path) const override;
 | 
						virtual String get_resource_type(const String &p_path) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 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 {
 | 
					class ResourceFormatSaverCrypto : public ResourceFormatSaver {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,7 @@ int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_bu
 | 
				
			||||||
Error CryptoCore::RandomGenerator::init() {
 | 
					Error CryptoCore::RandomGenerator::init() {
 | 
				
			||||||
	int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
 | 
						int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
 | 
							ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n  ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ Error CryptoCore::RandomGenerator::init() {
 | 
				
			||||||
Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
 | 
					Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
 | 
				
			||||||
	ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
 | 
						ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
 | 
				
			||||||
	int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
 | 
						int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
 | 
						ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n  ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ class HashingContext : public RefCounted {
 | 
				
			||||||
	GDCLASS(HashingContext, RefCounted);
 | 
						GDCLASS(HashingContext, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	enum HashType {
 | 
						enum HashType : int32_t {
 | 
				
			||||||
		HASH_MD5,
 | 
							HASH_MD5,
 | 
				
			||||||
		HASH_SHA1,
 | 
							HASH_SHA1,
 | 
				
			||||||
		HASH_SHA256
 | 
							HASH_SHA256
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,3 +147,37 @@ bool DebuggerMarshalls::OutputError::deserialize(const Array &p_arr) {
 | 
				
			||||||
	CHECK_END(p_arr, idx, "OutputError");
 | 
						CHECK_END(p_arr, idx, "OutputError");
 | 
				
			||||||
	return true;
 | 
						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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
#ifndef DEBUGGER_MARSHALLS_H
 | 
					#ifndef DEBUGGER_MARSHALLS_H
 | 
				
			||||||
#define DEBUGGER_MARSHALLS_H
 | 
					#define DEBUGGER_MARSHALLS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/shortcut.h"
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DebuggerMarshalls {
 | 
					struct DebuggerMarshalls {
 | 
				
			||||||
| 
						 | 
					@ -68,6 +69,9 @@ struct DebuggerMarshalls {
 | 
				
			||||||
		Array serialize();
 | 
							Array serialize();
 | 
				
			||||||
		bool deserialize(const Array &p_arr);
 | 
							bool deserialize(const Array &p_arr);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut);
 | 
				
			||||||
 | 
						static Ref<Shortcut> deserialize_key_shortcut(const Array &p_keys);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // DEBUGGER_MARSHALLS_H
 | 
					#endif // DEBUGGER_MARSHALLS_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,12 +46,12 @@ HashMap<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols;
 | 
				
			||||||
void (*EngineDebugger::allow_focus_steal_fn)();
 | 
					void (*EngineDebugger::allow_focus_steal_fn)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
 | 
					void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(profilers.has(p_name), vformat("Profiler already registered: '%s'.", p_name));
 | 
				
			||||||
	profilers.insert(p_name, p_func);
 | 
						profilers.insert(p_name, p_func);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
					void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name));
 | 
				
			||||||
	Profiler &p = profilers[p_name];
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
	if (p.active && p.toggle) {
 | 
						if (p.active && p.toggle) {
 | 
				
			||||||
		p.toggle(p.data, false, Array());
 | 
							p.toggle(p.data, false, Array());
 | 
				
			||||||
| 
						 | 
					@ -61,22 +61,22 @@ void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) {
 | 
					void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(captures.has(p_name), "Capture already registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(captures.has(p_name), vformat("Capture already registered: '%s'.", p_name));
 | 
				
			||||||
	captures.insert(p_name, p_func);
 | 
						captures.insert(p_name, p_func);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::unregister_message_capture(const StringName &p_name) {
 | 
					void EngineDebugger::unregister_message_capture(const StringName &p_name) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name));
 | 
				
			||||||
	captures.erase(p_name);
 | 
						captures.erase(p_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
 | 
					void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol);
 | 
						ERR_FAIL_COND_MSG(protocols.has(p_protocol), vformat("Protocol handler already registered: '%s'.", p_protocol));
 | 
				
			||||||
	protocols.insert(p_protocol, p_func);
 | 
						protocols.insert(p_protocol, p_func);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
 | 
					void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't change profiler state, no profiler: '%s'.", p_name));
 | 
				
			||||||
	Profiler &p = profilers[p_name];
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
	if (p.toggle) {
 | 
						if (p.toggle) {
 | 
				
			||||||
		p.toggle(p.data, p_enabled, p_opts);
 | 
							p.toggle(p.data, p_enabled, p_opts);
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,7 @@ void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
 | 
					void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't add frame data, no profiler: " + p_name);
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't add frame data, no profiler: '%s'.", p_name));
 | 
				
			||||||
	Profiler &p = profilers[p_name];
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
	if (p.add) {
 | 
						if (p.add) {
 | 
				
			||||||
		p.add(p.data, p_data);
 | 
							p.add(p.data, p_data);
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ bool EngineDebugger::has_capture(const StringName &p_name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) {
 | 
					Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) {
 | 
				
			||||||
	r_captured = false;
 | 
						r_captured = false;
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, "Capture not registered: " + p_name);
 | 
						ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, vformat("Capture not registered: '%s'.", p_name));
 | 
				
			||||||
	const Capture &cap = captures[p_name];
 | 
						const Capture &cap = captures[p_name];
 | 
				
			||||||
	return cap.capture(cap.data, p_msg, p_args, r_captured);
 | 
						return cap.capture(cap.data, p_msg, p_args, r_captured);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -163,8 +163,8 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < p_breakpoints.size(); i++) {
 | 
						for (int i = 0; i < p_breakpoints.size(); i++) {
 | 
				
			||||||
		const String &bp = p_breakpoints[i];
 | 
							const String &bp = p_breakpoints[i];
 | 
				
			||||||
		int sp = bp.rfind(":");
 | 
							int sp = bp.rfind_char(':');
 | 
				
			||||||
		ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format.");
 | 
							ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));
 | 
							singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@
 | 
				
			||||||
#include "core/templates/hash_map.h"
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
#include "core/templates/vector.h"
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
#include "core/variant/array.h"
 | 
					#include "core/variant/array.h"
 | 
				
			||||||
#include "core/variant/variant.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RemoteDebuggerPeer;
 | 
					class RemoteDebuggerPeer;
 | 
				
			||||||
class ScriptDebugger;
 | 
					class ScriptDebugger;
 | 
				
			||||||
| 
						 | 
					@ -106,7 +105,7 @@ public:
 | 
				
			||||||
	_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
 | 
						_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
 | 
				
			||||||
	_FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
 | 
						_FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; };
 | 
						_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
 | 
						static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
 | 
				
			||||||
	static void deinitialize();
 | 
						static void deinitialize();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				String key_value = line.get_slicec(' ', 1);
 | 
									String key_value = line.get_slicec(' ', 1);
 | 
				
			||||||
				int value_pos = key_value.find("=");
 | 
									int value_pos = key_value.find_char('=');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (value_pos < 0) {
 | 
									if (value_pos < 0) {
 | 
				
			||||||
					print_line("Error: Invalid set format. Use: set key=value");
 | 
										print_line("Error: Invalid set format. Use: set key=value");
 | 
				
			||||||
| 
						 | 
					@ -208,10 +208,10 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
			print_variables(members, values, variable_prefix);
 | 
								print_variables(members, values, variable_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (line.begins_with("p") || line.begins_with("print")) {
 | 
							} else if (line.begins_with("p") || line.begins_with("print")) {
 | 
				
			||||||
			if (line.get_slice_count(" ") <= 1) {
 | 
								if (line.find_char(' ') < 0) {
 | 
				
			||||||
				print_line("Usage: print <expre>");
 | 
									print_line("Usage: print <expression>");
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				String expr = line.get_slicec(' ', 2);
 | 
									String expr = line.split(" ", true, 1)[1];
 | 
				
			||||||
				String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
 | 
									String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
 | 
				
			||||||
				print_line(res);
 | 
									print_line(res);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -344,7 +344,7 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
 | 
				
			||||||
	String breakpoint_part = p_line.get_slicec(' ', 1);
 | 
						String breakpoint_part = p_line.get_slicec(' ', 1);
 | 
				
			||||||
	Pair<String, int> breakpoint;
 | 
						Pair<String, int> breakpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int last_colon = breakpoint_part.rfind(":");
 | 
						int last_colon = breakpoint_part.rfind_char(':');
 | 
				
			||||||
	if (last_colon < 0) {
 | 
						if (last_colon < 0) {
 | 
				
			||||||
		print_line("Error: Invalid breakpoint format. Expected [source:line]");
 | 
							print_line("Error: Invalid breakpoint format. Expected [source:line]");
 | 
				
			||||||
		return breakpoint;
 | 
							return breakpoint;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@
 | 
				
			||||||
#include "core/debugger/script_debugger.h"
 | 
					#include "core/debugger/script_debugger.h"
 | 
				
			||||||
#include "core/input/input.h"
 | 
					#include "core/input/input.h"
 | 
				
			||||||
#include "core/io/resource_loader.h"
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
 | 
					#include "core/math/expression.h"
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "core/os/os.h"
 | 
				
			||||||
#include "servers/display_server.h"
 | 
					#include "servers/display_server.h"
 | 
				
			||||||
| 
						 | 
					@ -78,7 +79,7 @@ public:
 | 
				
			||||||
		for (int i = 0; i < custom_monitor_names.size(); i++) {
 | 
							for (int i = 0; i < custom_monitor_names.size(); i++) {
 | 
				
			||||||
			Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]);
 | 
								Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]);
 | 
				
			||||||
			if (!monitor_value.is_num()) {
 | 
								if (!monitor_value.is_num()) {
 | 
				
			||||||
				ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number");
 | 
									ERR_PRINT(vformat("Value of custom monitor '%s' is not a number.", String(custom_monitor_names[i])));
 | 
				
			||||||
				arr[i + max] = Variant();
 | 
									arr[i + max] = Variant();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				arr[i + max] = monitor_value;
 | 
									arr[i + max] = monitor_value;
 | 
				
			||||||
| 
						 | 
					@ -337,7 +338,7 @@ void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_va
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
 | 
					Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
	const int idx = p_msg.find(":");
 | 
						const int idx = p_msg.find_char(':');
 | 
				
			||||||
	r_captured = false;
 | 
						r_captured = false;
 | 
				
			||||||
	if (idx < 0) { // No prefix, unknown message.
 | 
						if (idx < 0) { // No prefix, unknown message.
 | 
				
			||||||
		return OK;
 | 
							return OK;
 | 
				
			||||||
| 
						 | 
					@ -529,11 +530,46 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
			} else if (command == "set_skip_breakpoints") {
 | 
								} else if (command == "set_skip_breakpoints") {
 | 
				
			||||||
				ERR_FAIL_COND(data.is_empty());
 | 
									ERR_FAIL_COND(data.is_empty());
 | 
				
			||||||
				script_debugger->set_skip_breakpoints(data[0]);
 | 
									script_debugger->set_skip_breakpoints(data[0]);
 | 
				
			||||||
 | 
								} else if (command == "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 {
 | 
								} else {
 | 
				
			||||||
				bool captured = false;
 | 
									bool captured = false;
 | 
				
			||||||
				ERR_CONTINUE(_try_capture(command, data, captured) != OK);
 | 
									ERR_CONTINUE(_try_capture(command, data, captured) != OK);
 | 
				
			||||||
				if (!captured) {
 | 
									if (!captured) {
 | 
				
			||||||
					WARN_PRINT("Unknown message received from debugger: " + command);
 | 
										WARN_PRINT(vformat("Unknown message received from debugger: %s.", command));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -574,7 +610,7 @@ void RemoteDebugger::poll_events(bool p_is_idle) {
 | 
				
			||||||
		ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
 | 
							ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const String cmd = arr[0];
 | 
							const String cmd = arr[0];
 | 
				
			||||||
		const int idx = cmd.find(":");
 | 
							const int idx = cmd.find_char(':');
 | 
				
			||||||
		bool parsed = false;
 | 
							bool parsed = false;
 | 
				
			||||||
		if (idx < 0) { // Not prefix, use scripts capture.
 | 
							if (idx < 0) { // Not prefix, use scripts capture.
 | 
				
			||||||
			capture_parse("core", cmd, arr[1], parsed);
 | 
								capture_parse("core", cmd, arr[1], parsed);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,9 +144,8 @@ void RemoteDebuggerPeerTCP::_read_in() {
 | 
				
			||||||
			Error err = decode_variant(var, buf, in_pos, &read);
 | 
								Error err = decode_variant(var, buf, in_pos, &read);
 | 
				
			||||||
			ERR_CONTINUE(read != in_pos || err != OK);
 | 
								ERR_CONTINUE(read != in_pos || err != OK);
 | 
				
			||||||
			ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
 | 
								ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
 | 
				
			||||||
			mutex.lock();
 | 
								MutexLock lock(mutex);
 | 
				
			||||||
			in_queue.push_back(var);
 | 
								in_queue.push_back(var);
 | 
				
			||||||
			mutex.unlock();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -174,12 +173,12 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			const int ms = waits[i];
 | 
								const int ms = waits[i];
 | 
				
			||||||
			OS::get_singleton()->delay_usec(ms * 1000);
 | 
								OS::get_singleton()->delay_usec(ms * 1000);
 | 
				
			||||||
			print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec.");
 | 
								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) {
 | 
						if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
 | 
				
			||||||
		ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + ".");
 | 
							ERR_PRINT(vformat("Remote Debugger: Unable to connect. Status: %s.", String::num_int64(tcp_client->get_status())));
 | 
				
			||||||
		return FAILED;
 | 
							return FAILED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	connected = true;
 | 
						connected = true;
 | 
				
			||||||
| 
						 | 
					@ -224,8 +223,8 @@ RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
 | 
				
			||||||
	String debug_host = p_uri.replace("tcp://", "");
 | 
						String debug_host = p_uri.replace("tcp://", "");
 | 
				
			||||||
	uint16_t debug_port = 6007;
 | 
						uint16_t debug_port = 6007;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (debug_host.contains(":")) {
 | 
						if (debug_host.contains_char(':')) {
 | 
				
			||||||
		int sep_pos = debug_host.rfind(":");
 | 
							int sep_pos = debug_host.rfind_char(':');
 | 
				
			||||||
		debug_port = debug_host.substr(sep_pos + 1).to_int();
 | 
							debug_port = debug_host.substr(sep_pos + 1).to_int();
 | 
				
			||||||
		debug_host = debug_host.substr(0, sep_pos);
 | 
							debug_host = debug_host.substr(0, sep_pos);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,6 @@
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
#include "core/string/string_name.h"
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
#include "core/templates/hash_set.h"
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
#include "core/templates/rb_map.h"
 | 
					 | 
				
			||||||
#include "core/templates/vector.h"
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ScriptDebugger {
 | 
					class ScriptDebugger {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@
 | 
				
			||||||
String DocData::get_default_value_string(const Variant &p_value) {
 | 
					String DocData::get_default_value_string(const Variant &p_value) {
 | 
				
			||||||
	if (p_value.get_type() == Variant::ARRAY) {
 | 
						if (p_value.get_type() == Variant::ARRAY) {
 | 
				
			||||||
		return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
 | 
							return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
 | 
				
			||||||
 | 
						} else if (p_value.get_type() == Variant::DICTIONARY) {
 | 
				
			||||||
 | 
							return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return p_value.get_construct_string().replace("\n", " ");
 | 
							return p_value.get_construct_string().replace("\n", " ");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -57,6 +59,8 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper
 | 
				
			||||||
		p_method.return_type = p_retinfo.class_name;
 | 
							p_method.return_type = p_retinfo.class_name;
 | 
				
			||||||
	} else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
						} else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
				
			||||||
		p_method.return_type = p_retinfo.hint_string + "[]";
 | 
							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) {
 | 
						} else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
 | 
				
			||||||
		p_method.return_type = p_retinfo.hint_string;
 | 
							p_method.return_type = p_retinfo.hint_string;
 | 
				
			||||||
	} else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
 | 
						} else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
 | 
				
			||||||
| 
						 | 
					@ -89,6 +93,8 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const
 | 
				
			||||||
		p_argument.type = p_arginfo.class_name;
 | 
							p_argument.type = p_arginfo.class_name;
 | 
				
			||||||
	} else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
						} else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
				
			||||||
		p_argument.type = p_arginfo.hint_string + "[]";
 | 
							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) {
 | 
						} else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
 | 
				
			||||||
		p_argument.type = p_arginfo.hint_string;
 | 
							p_argument.type = p_arginfo.hint_string;
 | 
				
			||||||
	} else if (p_arginfo.type == Variant::NIL) {
 | 
						} else if (p_arginfo.type == Variant::NIL) {
 | 
				
			||||||
| 
						 | 
					@ -99,28 +105,6 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DocData::property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_property, const ScriptMemberInfo &p_memberinfo) {
 | 
					 | 
				
			||||||
	p_property.name = p_memberinfo.propinfo.name;
 | 
					 | 
				
			||||||
	p_property.description = p_memberinfo.doc_string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p_memberinfo.propinfo.type == Variant::OBJECT) {
 | 
					 | 
				
			||||||
		p_property.type = p_memberinfo.propinfo.class_name;
 | 
					 | 
				
			||||||
	} else if (p_memberinfo.propinfo.type == Variant::NIL && p_memberinfo.propinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
 | 
					 | 
				
			||||||
		p_property.type = "Variant";
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		p_property.type = Variant::get_type_name(p_memberinfo.propinfo.type);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p_property.setter = p_memberinfo.setter;
 | 
					 | 
				
			||||||
	p_property.getter = p_memberinfo.getter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p_memberinfo.has_default_value && p_memberinfo.default_value.get_type() != Variant::OBJECT) {
 | 
					 | 
				
			||||||
		p_property.default_value = get_default_value_string(p_memberinfo.default_value);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p_property.overridden = false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc) {
 | 
					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.name = p_methodinfo.name;
 | 
				
			||||||
	p_method.description = p_desc;
 | 
						p_method.description = p_desc;
 | 
				
			||||||
| 
						 | 
					@ -164,14 +148,3 @@ void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const Met
 | 
				
			||||||
		p_method.arguments.push_back(argument);
 | 
							p_method.arguments.push_back(argument);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void DocData::constant_doc_from_variant(DocData::ConstantDoc &p_const, const StringName &p_name, const Variant &p_value, const String &p_desc) {
 | 
					 | 
				
			||||||
	p_const.name = p_name;
 | 
					 | 
				
			||||||
	p_const.value = p_value;
 | 
					 | 
				
			||||||
	p_const.is_value_valid = (p_value.get_type() != Variant::OBJECT);
 | 
					 | 
				
			||||||
	p_const.description = p_desc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DocData::signal_doc_from_methodinfo(DocData::MethodDoc &p_signal, const MethodInfo &p_methodinfo, const String &p_desc) {
 | 
					 | 
				
			||||||
	return method_doc_from_methodinfo(p_signal, p_methodinfo, p_desc);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,16 +34,6 @@
 | 
				
			||||||
#include "core/io/xml_parser.h"
 | 
					#include "core/io/xml_parser.h"
 | 
				
			||||||
#include "core/variant/variant.h"
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ScriptMemberInfo {
 | 
					 | 
				
			||||||
	PropertyInfo propinfo;
 | 
					 | 
				
			||||||
	String doc_string;
 | 
					 | 
				
			||||||
	StringName setter;
 | 
					 | 
				
			||||||
	StringName getter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool has_default_value = false;
 | 
					 | 
				
			||||||
	Variant default_value;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DocData {
 | 
					class DocData {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	struct ArgumentDoc {
 | 
						struct ArgumentDoc {
 | 
				
			||||||
| 
						 | 
					@ -276,6 +266,7 @@ public:
 | 
				
			||||||
		String name;
 | 
							String name;
 | 
				
			||||||
		String value;
 | 
							String value;
 | 
				
			||||||
		bool is_value_valid = false;
 | 
							bool is_value_valid = false;
 | 
				
			||||||
 | 
							String type;
 | 
				
			||||||
		String enumeration;
 | 
							String enumeration;
 | 
				
			||||||
		bool is_bitfield = false;
 | 
							bool is_bitfield = false;
 | 
				
			||||||
		String description;
 | 
							String description;
 | 
				
			||||||
| 
						 | 
					@ -302,6 +293,10 @@ public:
 | 
				
			||||||
				doc.is_value_valid = p_dict["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")) {
 | 
								if (p_dict.has("enumeration")) {
 | 
				
			||||||
				doc.enumeration = p_dict["enumeration"];
 | 
									doc.enumeration = p_dict["enumeration"];
 | 
				
			||||||
				if (p_dict.has("is_bitfield")) {
 | 
									if (p_dict.has("is_bitfield")) {
 | 
				
			||||||
| 
						 | 
					@ -352,6 +347,8 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			dict["is_value_valid"] = p_doc.is_value_valid;
 | 
								dict["is_value_valid"] = p_doc.is_value_valid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dict["type"] = p_doc.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!p_doc.enumeration.is_empty()) {
 | 
								if (!p_doc.enumeration.is_empty()) {
 | 
				
			||||||
				dict["enumeration"] = p_doc.enumeration;
 | 
									dict["enumeration"] = p_doc.enumeration;
 | 
				
			||||||
				dict["is_bitfield"] = p_doc.is_bitfield;
 | 
									dict["is_bitfield"] = p_doc.is_bitfield;
 | 
				
			||||||
| 
						 | 
					@ -522,6 +519,10 @@ public:
 | 
				
			||||||
		String type;
 | 
							String type;
 | 
				
			||||||
		String data_type;
 | 
							String data_type;
 | 
				
			||||||
		String description;
 | 
							String description;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
		String default_value;
 | 
							String default_value;
 | 
				
			||||||
		String keywords;
 | 
							String keywords;
 | 
				
			||||||
		bool operator<(const ThemeItemDoc &p_theme_item) const {
 | 
							bool operator<(const ThemeItemDoc &p_theme_item) const {
 | 
				
			||||||
| 
						 | 
					@ -550,6 +551,16 @@ public:
 | 
				
			||||||
				doc.description = p_dict["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")) {
 | 
								if (p_dict.has("default_value")) {
 | 
				
			||||||
				doc.default_value = p_dict["default_value"];
 | 
									doc.default_value = p_dict["default_value"];
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -579,6 +590,14 @@ public:
 | 
				
			||||||
				dict["description"] = p_doc.description;
 | 
									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()) {
 | 
								if (!p_doc.default_value.is_empty()) {
 | 
				
			||||||
				dict["default_value"] = p_doc.default_value;
 | 
									dict["default_value"] = p_doc.default_value;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -959,10 +978,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
 | 
						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 argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo);
 | 
				
			||||||
	static void property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_property, const ScriptMemberInfo &p_memberinfo);
 | 
					 | 
				
			||||||
	static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc);
 | 
						static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc);
 | 
				
			||||||
	static void constant_doc_from_variant(DocData::ConstantDoc &p_const, const StringName &p_name, const Variant &p_value, const String &p_desc);
 | 
					 | 
				
			||||||
	static void signal_doc_from_methodinfo(DocData::MethodDoc &p_signal, const MethodInfo &p_methodinfo, const String &p_desc);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // DOC_DATA_H
 | 
					#endif // DOC_DATA_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,7 @@
 | 
				
			||||||
 * - Are added to the Error enum in core/error/error_list.h
 | 
					 * - 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
 | 
					 * - 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
 | 
					 * - 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 {
 | 
					enum Error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,12 @@
 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "core/os/os.h"
 | 
				
			||||||
#include "core/string/ustring.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;
 | 
					static ErrorHandlerList *error_handler_list = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void add_error_handler(ErrorHandlerList *p_handler) {
 | 
					void add_error_handler(ErrorHandlerList *p_handler) {
 | 
				
			||||||
| 
						 | 
					@ -101,6 +107,28 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
 | 
				
			||||||
	_global_unlock();
 | 
						_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*.)
 | 
					// 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) {
 | 
					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);
 | 
						_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_type);
 | 
				
			||||||
| 
						 | 
					@ -128,3 +156,48 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
 | 
				
			||||||
void _err_flush_stdout() {
 | 
					void _err_flush_stdout() {
 | 
				
			||||||
	fflush(stdout);
 | 
						fflush(stdout);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Prevent error spam by limiting the warnings to a certain frequency.
 | 
				
			||||||
 | 
					void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string) {
 | 
				
			||||||
 | 
					#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
 | 
				
			||||||
 | 
						const uint32_t warn_max = 2048;
 | 
				
			||||||
 | 
						const uint32_t warn_timeout_seconds = 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static uint32_t warn_count = warn_max;
 | 
				
			||||||
 | 
						static uint32_t warn_timeout = warn_timeout_seconds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t time_now = UINT32_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (warn_count) {
 | 
				
			||||||
 | 
							warn_count--;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!warn_count) {
 | 
				
			||||||
 | 
							time_now = OS::get_singleton()->get_ticks_msec() / 1000;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((warn_count == 0) && (time_now >= warn_timeout)) {
 | 
				
			||||||
 | 
							warn_count = warn_max;
 | 
				
			||||||
 | 
							warn_timeout = time_now + warn_timeout_seconds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
 | 
				
			||||||
 | 
								// UINT64_MAX means unused.
 | 
				
			||||||
 | 
								if (p_id.operator uint64_t() == UINT64_MAX) {
 | 
				
			||||||
 | 
									_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + " (possibly benign).", false, ERR_HANDLER_WARNING);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									String node_name;
 | 
				
			||||||
 | 
									if (p_id.is_valid()) {
 | 
				
			||||||
 | 
										Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id));
 | 
				
			||||||
 | 
										if (node && node->is_inside_tree()) {
 | 
				
			||||||
 | 
											node_name = "\"" + String(node->get_path()) + "\"";
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											node_name = "\"unknown\"";
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + ": " + node_name + " (possibly benign).", false, ERR_HANDLER_WARNING);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
#ifndef ERROR_MACROS_H
 | 
					#ifndef ERROR_MACROS_H
 | 
				
			||||||
#define ERROR_MACROS_H
 | 
					#define ERROR_MACROS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/object_id.h"
 | 
				
			||||||
#include "core/typedefs.h"
 | 
					#include "core/typedefs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes.
 | 
					#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes.
 | 
				
			||||||
| 
						 | 
					@ -67,10 +68,13 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
 | 
				
			||||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
 | 
				
			||||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
 | 
				
			||||||
void _err_flush_stdout();
 | 
					void _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__
 | 
					#ifdef __GNUC__
 | 
				
			||||||
//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
 | 
					//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
 | 
				
			||||||
#define FUNCTION_STR __FUNCTION__
 | 
					#define FUNCTION_STR __FUNCTION__
 | 
				
			||||||
| 
						 | 
					@ -832,4 +836,14 @@ void _err_flush_stdout();
 | 
				
			||||||
#define DEV_CHECK_ONCE(m_cond)
 | 
					#define DEV_CHECK_ONCE(m_cond)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Physics Interpolation warnings.
 | 
				
			||||||
 | 
					 * These are spam protection warnings.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define PHYSICS_INTERPOLATION_NODE_WARNING(m_object_id, m_string) \
 | 
				
			||||||
 | 
						_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, m_object_id, m_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PHYSICS_INTERPOLATION_WARNING(m_string) \
 | 
				
			||||||
 | 
						_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // ERROR_MACROS_H
 | 
					#endif // ERROR_MACROS_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/engine.h"
 | 
					#include "core/config/engine.h"
 | 
				
			||||||
#include "core/core_constants.h"
 | 
					#include "core/core_constants.h"
 | 
				
			||||||
#include "core/extension/gdextension_compat_hashes.h"
 | 
					#include "core/extension/gdextension_special_compat_hashes.h"
 | 
				
			||||||
#include "core/io/file_access.h"
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
#include "core/io/json.h"
 | 
					#include "core/io/json.h"
 | 
				
			||||||
#include "core/templates/pair.h"
 | 
					#include "core/templates/pair.h"
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,9 @@ static String get_property_info_type_name(const PropertyInfo &p_info) {
 | 
				
			||||||
	if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) {
 | 
						if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) {
 | 
				
			||||||
		return String("typedarray::") + p_info.hint_string;
 | 
							return String("typedarray::") + p_info.hint_string;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (p_info.type == Variant::DICTIONARY && (p_info.hint == PROPERTY_HINT_DICTIONARY_TYPE)) {
 | 
				
			||||||
 | 
							return String("typeddictionary::") + p_info.hint_string;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) {
 | 
						if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) {
 | 
				
			||||||
		return String("enum::") + String(p_info.class_name);
 | 
							return String("enum::") + String(p_info.class_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -85,7 +88,7 @@ static String get_property_info_type_name(const PropertyInfo &p_info) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static String get_type_meta_name(const GodotTypeInfo::Metadata metadata) {
 | 
					static String get_type_meta_name(const GodotTypeInfo::Metadata metadata) {
 | 
				
			||||||
	static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
 | 
						static const char *argmeta[13] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32" };
 | 
				
			||||||
	return argmeta[metadata];
 | 
						return argmeta[metadata];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1014,9 +1017,22 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
 | 
				
			||||||
						d2["name"] = String(method_name);
 | 
											d2["name"] = String(method_name);
 | 
				
			||||||
						d2["is_const"] = (F.flags & METHOD_FLAG_CONST) ? true : false;
 | 
											d2["is_const"] = (F.flags & METHOD_FLAG_CONST) ? true : false;
 | 
				
			||||||
						d2["is_static"] = (F.flags & METHOD_FLAG_STATIC) ? true : false;
 | 
											d2["is_static"] = (F.flags & METHOD_FLAG_STATIC) ? true : false;
 | 
				
			||||||
 | 
											d2["is_required"] = (F.flags & METHOD_FLAG_VIRTUAL_REQUIRED) ? true : false;
 | 
				
			||||||
						d2["is_vararg"] = false;
 | 
											d2["is_vararg"] = false;
 | 
				
			||||||
						d2["is_virtual"] = true;
 | 
											d2["is_virtual"] = true;
 | 
				
			||||||
						// virtual functions have no hash since no MethodBind is involved
 | 
											d2["hash"] = mi.get_compatibility_hash();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											Vector<uint32_t> compat_hashes = ClassDB::get_virtual_method_compatibility_hashes(class_name, method_name);
 | 
				
			||||||
 | 
											Array compatibility;
 | 
				
			||||||
 | 
											if (compat_hashes.size()) {
 | 
				
			||||||
 | 
												for (int i = 0; i < compat_hashes.size(); i++) {
 | 
				
			||||||
 | 
													compatibility.push_back(compat_hashes[i]);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if (compatibility.size() > 0) {
 | 
				
			||||||
 | 
												d2["hash_compatibility"] = compatibility;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
 | 
											bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
 | 
				
			||||||
						if (has_return) {
 | 
											if (has_return) {
 | 
				
			||||||
							PropertyInfo pinfo = mi.return_val;
 | 
												PropertyInfo pinfo = mi.return_val;
 | 
				
			||||||
| 
						 | 
					@ -1090,7 +1106,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
						GDExtensionCompatHashes::get_legacy_hashes(class_name, method_name, compatibility);
 | 
											GDExtensionSpecialCompatHashes::get_legacy_hashes(class_name, method_name, compatibility);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if (compatibility.size() > 0) {
 | 
											if (compatibility.size() > 0) {
 | 
				
			||||||
| 
						 | 
					@ -1201,7 +1217,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
 | 
				
			||||||
					if (F.name.begins_with("_")) {
 | 
										if (F.name.begins_with("_")) {
 | 
				
			||||||
						continue; //hidden property
 | 
											continue; //hidden property
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					if (F.name.contains("/")) {
 | 
										if (F.name.contains_char('/')) {
 | 
				
			||||||
						// Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
 | 
											// Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
 | 
				
			||||||
						continue;
 | 
											continue;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -1359,7 +1375,7 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
 | 
				
			||||||
		return true; // May just not have this array and its still good. Probably added recently.
 | 
							return true; // May just not have this array and its still good. Probably added recently.
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool failed = false;
 | 
						bool failed = false;
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!p_new_api.has(p_base_array), false, "New API lacks base array: " + p_base_array);
 | 
						ERR_FAIL_COND_V_MSG(!p_new_api.has(p_base_array), false, vformat("New API lacks base array: %s", p_base_array));
 | 
				
			||||||
	Array new_api = p_new_api[p_base_array];
 | 
						Array new_api = p_new_api[p_base_array];
 | 
				
			||||||
	HashMap<String, Dictionary> new_api_assoc;
 | 
						HashMap<String, Dictionary> new_api_assoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1367,6 +1383,9 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
 | 
				
			||||||
		Dictionary elem = var;
 | 
							Dictionary elem = var;
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(!elem.has(p_name_field), false, vformat("Validate extension JSON: Element of base_array '%s' is missing field '%s'. This is a bug.", base_array, p_name_field));
 | 
							ERR_FAIL_COND_V_MSG(!elem.has(p_name_field), false, vformat("Validate extension JSON: Element of base_array '%s' is missing field '%s'. This is a bug.", base_array, p_name_field));
 | 
				
			||||||
		String name = elem[p_name_field];
 | 
							String name = elem[p_name_field];
 | 
				
			||||||
 | 
							if (name.is_valid_float()) {
 | 
				
			||||||
 | 
								name = name.trim_suffix(".0"); // Make "integers" stringified as integers.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (p_compare_operators && elem.has("right_type")) {
 | 
							if (p_compare_operators && elem.has("right_type")) {
 | 
				
			||||||
			name += " " + String(elem["right_type"]);
 | 
								name += " " + String(elem["right_type"]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1382,6 +1401,9 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		String name = old_elem[p_name_field];
 | 
							String name = old_elem[p_name_field];
 | 
				
			||||||
 | 
							if (name.is_valid_float()) {
 | 
				
			||||||
 | 
								name = name.trim_suffix(".0"); // Make "integers" stringified as integers.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (p_compare_operators && old_elem.has("right_type")) {
 | 
							if (p_compare_operators && old_elem.has("right_type")) {
 | 
				
			||||||
			name += " " + String(old_elem["right_type"]);
 | 
								name += " " + String(old_elem["right_type"]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1463,8 +1485,8 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p_compare_hashes) {
 | 
							if (p_compare_hashes) {
 | 
				
			||||||
			if (!old_elem.has("hash")) {
 | 
								if (!old_elem.has("hash")) {
 | 
				
			||||||
				if (old_elem.has("is_virtual") && bool(old_elem["is_virtual"]) && !new_elem.has("hash")) {
 | 
									if (old_elem.has("is_virtual") && bool(old_elem["is_virtual"]) && !old_elem.has("hash")) {
 | 
				
			||||||
					continue; // No hash for virtual methods, go on.
 | 
										continue; // Virtual methods didn't use to have hashes, so skip check if it's missing in the old file.
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				failed = true;
 | 
									failed = true;
 | 
				
			||||||
| 
						 | 
					@ -1511,7 +1533,7 @@ static bool compare_sub_dict_array(HashSet<String> &r_removed_classes_registered
 | 
				
			||||||
		return true; // May just not have this array and its still good. Probably added recently or optional.
 | 
							return true; // May just not have this array and its still good. Probably added recently or optional.
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool failed = false;
 | 
						bool failed = false;
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!p_new_api.has(p_outer), false, "New API lacks base array: " + p_outer);
 | 
						ERR_FAIL_COND_V_MSG(!p_new_api.has(p_outer), false, vformat("New API lacks base array: %s", p_outer));
 | 
				
			||||||
	Array new_api = p_new_api[p_outer];
 | 
						Array new_api = p_new_api[p_outer];
 | 
				
			||||||
	HashMap<String, Dictionary> new_api_assoc;
 | 
						HashMap<String, Dictionary> new_api_assoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,11 +32,9 @@
 | 
				
			||||||
#include "gdextension.compat.inc"
 | 
					#include "gdextension.compat.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/io/dir_access.h"
 | 
					 | 
				
			||||||
#include "core/object/class_db.h"
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
#include "core/object/method_bind.h"
 | 
					#include "core/object/method_bind.h"
 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "gdextension_library_loader.h"
 | 
				
			||||||
#include "core/version.h"
 | 
					 | 
				
			||||||
#include "gdextension_manager.h"
 | 
					#include "gdextension_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void gdextension_setup_interface();
 | 
					extern void gdextension_setup_interface();
 | 
				
			||||||
| 
						 | 
					@ -48,146 +46,6 @@ String GDExtension::get_extension_list_config_file() {
 | 
				
			||||||
	return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
 | 
						return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector<SharedObject> GDExtension::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 GDExtension::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_valid(), 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();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GDExtensionMethodBind : public MethodBind {
 | 
					class GDExtensionMethodBind : public MethodBind {
 | 
				
			||||||
	GDExtensionClassMethodCall call_func;
 | 
						GDExtensionClassMethodCall call_func;
 | 
				
			||||||
	GDExtensionClassMethodValidatedCall validated_call_func;
 | 
						GDExtensionClassMethodValidatedCall validated_call_func;
 | 
				
			||||||
| 
						 | 
					@ -296,7 +154,7 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool is_vararg() const override {
 | 
						virtual bool is_vararg() const override {
 | 
				
			||||||
		return false;
 | 
							return vararg;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -382,11 +240,12 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
 | 
					void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
 | 
				
			||||||
	const GDExtensionClassCreationInfo3 class_info3 = {
 | 
						const GDExtensionClassCreationInfo4 class_info4 = {
 | 
				
			||||||
		p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
 | 
							p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
 | 
				
			||||||
		p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
 | 
							p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
 | 
				
			||||||
		true, // GDExtensionBool is_exposed;
 | 
							true, // GDExtensionBool is_exposed;
 | 
				
			||||||
		false, // GDExtensionBool is_runtime;
 | 
							false, // GDExtensionBool is_runtime;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionConstStringPtr icon_path;
 | 
				
			||||||
		p_extension_funcs->set_func, // GDExtensionClassSet set_func;
 | 
							p_extension_funcs->set_func, // GDExtensionClassSet set_func;
 | 
				
			||||||
		p_extension_funcs->get_func, // GDExtensionClassGet get_func;
 | 
							p_extension_funcs->get_func, // GDExtensionClassGet get_func;
 | 
				
			||||||
		p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
 | 
							p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
 | 
				
			||||||
| 
						 | 
					@ -398,29 +257,33 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
 | 
				
			||||||
		p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
 | 
							p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
 | 
				
			||||||
		p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
 | 
							p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
 | 
				
			||||||
		p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
 | 
							p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
 | 
				
			||||||
		p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
 | 
							nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
 | 
				
			||||||
		p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
 | 
							p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
 | 
				
			||||||
		nullptr, // GDExtensionClassRecreateInstance recreate_instance_func;
 | 
							nullptr, // GDExtensionClassRecreateInstance recreate_instance_func;
 | 
				
			||||||
		p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
							nullptr, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
		nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 | 
							nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 | 
				
			||||||
		nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
 | 
							nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
 | 
				
			||||||
		p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
 | 
					 | 
				
			||||||
		p_extension_funcs->class_userdata, // void *class_userdata;
 | 
							p_extension_funcs->class_userdata, // void *class_userdata;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const ClassCreationDeprecatedInfo legacy = {
 | 
						const ClassCreationDeprecatedInfo legacy = {
 | 
				
			||||||
		p_extension_funcs->notification_func, // GDExtensionClassNotification notification_func;
 | 
							p_extension_funcs->notification_func, // GDExtensionClassNotification notification_func;
 | 
				
			||||||
		p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
							p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
				
			||||||
 | 
							p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
 | 
				
			||||||
 | 
							p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
 | 
							nullptr,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy);
 | 
						_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs) {
 | 
					void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs) {
 | 
				
			||||||
	const GDExtensionClassCreationInfo3 class_info3 = {
 | 
						const GDExtensionClassCreationInfo4 class_info4 = {
 | 
				
			||||||
		p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
 | 
							p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
 | 
				
			||||||
		p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
 | 
							p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
 | 
				
			||||||
		p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
 | 
							p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
 | 
				
			||||||
		false, // GDExtensionBool is_runtime;
 | 
							false, // GDExtensionBool is_runtime;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionConstStringPtr icon_path;
 | 
				
			||||||
		p_extension_funcs->set_func, // GDExtensionClassSet set_func;
 | 
							p_extension_funcs->set_func, // GDExtensionClassSet set_func;
 | 
				
			||||||
		p_extension_funcs->get_func, // GDExtensionClassGet get_func;
 | 
							p_extension_funcs->get_func, // GDExtensionClassGet get_func;
 | 
				
			||||||
		p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
 | 
							p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
 | 
				
			||||||
| 
						 | 
					@ -432,35 +295,77 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
 | 
				
			||||||
		p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
 | 
							p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
 | 
				
			||||||
		p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
 | 
							p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
 | 
				
			||||||
		p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
 | 
							p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
 | 
				
			||||||
		p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
 | 
							nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
 | 
				
			||||||
		p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
 | 
							p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
 | 
				
			||||||
		p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
 | 
							p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
 | 
				
			||||||
		p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
							nullptr, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
		p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 | 
							nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 | 
				
			||||||
		p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
 | 
							p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
 | 
				
			||||||
		p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
 | 
					 | 
				
			||||||
		p_extension_funcs->class_userdata, // void *class_userdata;
 | 
							p_extension_funcs->class_userdata, // void *class_userdata;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const ClassCreationDeprecatedInfo legacy = {
 | 
						const ClassCreationDeprecatedInfo legacy = {
 | 
				
			||||||
		nullptr, // GDExtensionClassNotification notification_func;
 | 
							nullptr, // GDExtensionClassNotification notification_func;
 | 
				
			||||||
		p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
							p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
				
			||||||
 | 
							p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
 | 
				
			||||||
 | 
							p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy);
 | 
						_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs) {
 | 
					void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs) {
 | 
				
			||||||
 | 
						const GDExtensionClassCreationInfo4 class_info4 = {
 | 
				
			||||||
 | 
							p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
 | 
				
			||||||
 | 
							p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
 | 
				
			||||||
 | 
							p_extension_funcs->is_exposed, // GDExtensionBool is_exposed;
 | 
				
			||||||
 | 
							p_extension_funcs->is_runtime, // GDExtensionBool is_runtime;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionConstStringPtr icon_path;
 | 
				
			||||||
 | 
							p_extension_funcs->set_func, // GDExtensionClassSet set_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_func, // GDExtensionClassGet get_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
 | 
				
			||||||
 | 
							p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
				
			||||||
 | 
							p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
 | 
				
			||||||
 | 
							p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
 | 
				
			||||||
 | 
							p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func;
 | 
				
			||||||
 | 
							p_extension_funcs->notification_func, // GDExtensionClassNotification2 notification_func;
 | 
				
			||||||
 | 
							p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
 | 
				
			||||||
 | 
							p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
 | 
				
			||||||
 | 
							p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
 | 
				
			||||||
 | 
							p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
 | 
				
			||||||
 | 
							p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 | 
				
			||||||
 | 
							p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
 | 
				
			||||||
 | 
							p_extension_funcs->class_userdata, // void *class_userdata;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const ClassCreationDeprecatedInfo legacy = {
 | 
				
			||||||
 | 
							nullptr, // GDExtensionClassNotification notification_func;
 | 
				
			||||||
 | 
							nullptr, // GDExtensionClassFreePropertyList free_property_list_func;
 | 
				
			||||||
 | 
							p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance2 create_instance_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
 | 
				
			||||||
 | 
							p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
 | 
							p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtension::_register_extension_class4(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs) {
 | 
				
			||||||
	_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, p_extension_funcs);
 | 
						_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, p_extension_funcs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs) {
 | 
					void GDExtension::_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) {
 | 
				
			||||||
	GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
						GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	StringName parent_class_name = *reinterpret_cast<const StringName *>(p_parent_class_name);
 | 
						StringName parent_class_name = *reinterpret_cast<const StringName *>(p_parent_class_name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
 | 
						ERR_FAIL_COND_MSG(!String(class_name).is_valid_unicode_identifier(), vformat("Attempt to register extension class '%s', which is not a valid class identifier.", class_name));
 | 
				
			||||||
	ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
 | 
						ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), vformat("Attempt to register extension class '%s', which appears to be already registered.", class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Extension *parent_extension = nullptr;
 | 
						Extension *parent_extension = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -474,7 +379,7 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
 | 
				
			||||||
			//inheriting from engine class
 | 
								//inheriting from engine class
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'.");
 | 
							ERR_FAIL_MSG(vformat("Attempt to register an extension class '%s' using non-existing parent class '%s'.", String(class_name), String(parent_class_name)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -530,6 +435,10 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
 | 
				
			||||||
	if (p_deprecated_funcs) {
 | 
						if (p_deprecated_funcs) {
 | 
				
			||||||
		extension->gdextension.notification = p_deprecated_funcs->notification_func;
 | 
							extension->gdextension.notification = p_deprecated_funcs->notification_func;
 | 
				
			||||||
		extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func;
 | 
							extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func;
 | 
				
			||||||
 | 
							extension->gdextension.create_instance = p_deprecated_funcs->create_instance_func;
 | 
				
			||||||
 | 
							extension->gdextension.get_rid = p_deprecated_funcs->get_rid_func;
 | 
				
			||||||
 | 
							extension->gdextension.get_virtual = p_deprecated_funcs->get_virtual_func;
 | 
				
			||||||
 | 
							extension->gdextension.get_virtual_call_data = p_deprecated_funcs->get_virtual_call_data_func;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
	extension->gdextension.notification2 = p_extension_funcs->notification_func;
 | 
						extension->gdextension.notification2 = p_extension_funcs->notification_func;
 | 
				
			||||||
| 
						 | 
					@ -537,13 +446,12 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
 | 
				
			||||||
	extension->gdextension.reference = p_extension_funcs->reference_func;
 | 
						extension->gdextension.reference = p_extension_funcs->reference_func;
 | 
				
			||||||
	extension->gdextension.unreference = p_extension_funcs->unreference_func;
 | 
						extension->gdextension.unreference = p_extension_funcs->unreference_func;
 | 
				
			||||||
	extension->gdextension.class_userdata = p_extension_funcs->class_userdata;
 | 
						extension->gdextension.class_userdata = p_extension_funcs->class_userdata;
 | 
				
			||||||
	extension->gdextension.create_instance = p_extension_funcs->create_instance_func;
 | 
						extension->gdextension.create_instance2 = p_extension_funcs->create_instance_func;
 | 
				
			||||||
	extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
 | 
						extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
 | 
				
			||||||
	extension->gdextension.recreate_instance = p_extension_funcs->recreate_instance_func;
 | 
						extension->gdextension.recreate_instance = p_extension_funcs->recreate_instance_func;
 | 
				
			||||||
	extension->gdextension.get_virtual = p_extension_funcs->get_virtual_func;
 | 
						extension->gdextension.get_virtual2 = p_extension_funcs->get_virtual_func;
 | 
				
			||||||
	extension->gdextension.get_virtual_call_data = p_extension_funcs->get_virtual_call_data_func;
 | 
						extension->gdextension.get_virtual_call_data2 = p_extension_funcs->get_virtual_call_data_func;
 | 
				
			||||||
	extension->gdextension.call_virtual_with_data = p_extension_funcs->call_virtual_with_data_func;
 | 
						extension->gdextension.call_virtual_with_data = p_extension_funcs->call_virtual_with_data_func;
 | 
				
			||||||
	extension->gdextension.get_rid = p_extension_funcs->get_rid_func;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	extension->gdextension.reloadable = self->reloadable;
 | 
						extension->gdextension.reloadable = self->reloadable;
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -559,6 +467,13 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::register_extension_class(&extension->gdextension);
 | 
						ClassDB::register_extension_class(&extension->gdextension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_extension_funcs->icon_path != nullptr) {
 | 
				
			||||||
 | 
							const String icon_path = *reinterpret_cast<const String *>(p_extension_funcs->icon_path);
 | 
				
			||||||
 | 
							if (!icon_path.is_empty()) {
 | 
				
			||||||
 | 
								self->class_icon_paths[class_name] = icon_path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) {
 | 
					void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) {
 | 
				
			||||||
| 
						 | 
					@ -566,7 +481,7 @@ void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	StringName method_name = *reinterpret_cast<const StringName *>(p_method_info->name);
 | 
						StringName method_name = *reinterpret_cast<const StringName *>(p_method_info->name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension method '%s' for unexisting class '%s'.", String(method_name), class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	Extension *extension = &self->extension_classes[class_name];
 | 
						Extension *extension = &self->extension_classes[class_name];
 | 
				
			||||||
| 
						 | 
					@ -616,7 +531,7 @@ void GDExtension::_register_extension_class_integer_constant(GDExtensionClassLib
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	StringName enum_name = *reinterpret_cast<const StringName *>(p_enum_name);
 | 
						StringName enum_name = *reinterpret_cast<const StringName *>(p_enum_name);
 | 
				
			||||||
	StringName constant_name = *reinterpret_cast<const StringName *>(p_constant_name);
 | 
						StringName constant_name = *reinterpret_cast<const StringName *>(p_constant_name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + constant_name + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension constant '%s' for unexisting class '%s'.", constant_name, class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	// If the extension is still marked as reloading, that means it failed to register again.
 | 
						// If the extension is still marked as reloading, that means it failed to register again.
 | 
				
			||||||
| 
						 | 
					@ -640,7 +555,7 @@ void GDExtension::_register_extension_class_property_indexed(GDExtensionClassLib
 | 
				
			||||||
	StringName setter = *reinterpret_cast<const StringName *>(p_setter);
 | 
						StringName setter = *reinterpret_cast<const StringName *>(p_setter);
 | 
				
			||||||
	StringName getter = *reinterpret_cast<const StringName *>(p_getter);
 | 
						StringName getter = *reinterpret_cast<const StringName *>(p_getter);
 | 
				
			||||||
	String property_name = *reinterpret_cast<const StringName *>(p_info->name);
 | 
						String property_name = *reinterpret_cast<const StringName *>(p_info->name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property '%s' for unexisting class '%s'.", property_name, class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	// If the extension is still marked as reloading, that means it failed to register again.
 | 
						// If the extension is still marked as reloading, that means it failed to register again.
 | 
				
			||||||
| 
						 | 
					@ -661,7 +576,7 @@ void GDExtension::_register_extension_class_property_group(GDExtensionClassLibra
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	String group_name = *reinterpret_cast<const String *>(p_group_name);
 | 
						String group_name = *reinterpret_cast<const String *>(p_group_name);
 | 
				
			||||||
	String prefix = *reinterpret_cast<const String *>(p_prefix);
 | 
						String prefix = *reinterpret_cast<const String *>(p_prefix);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + group_name + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property group '%s' for unexisting class '%s'.", group_name, class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	// If the extension is still marked as reloading, that means it failed to register again.
 | 
						// If the extension is still marked as reloading, that means it failed to register again.
 | 
				
			||||||
| 
						 | 
					@ -680,7 +595,7 @@ void GDExtension::_register_extension_class_property_subgroup(GDExtensionClassLi
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	String subgroup_name = *reinterpret_cast<const String *>(p_subgroup_name);
 | 
						String subgroup_name = *reinterpret_cast<const String *>(p_subgroup_name);
 | 
				
			||||||
	String prefix = *reinterpret_cast<const String *>(p_prefix);
 | 
						String prefix = *reinterpret_cast<const String *>(p_prefix);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + subgroup_name + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property subgroup '%s' for unexisting class '%s'.", subgroup_name, class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	// If the extension is still marked as reloading, that means it failed to register again.
 | 
						// If the extension is still marked as reloading, that means it failed to register again.
 | 
				
			||||||
| 
						 | 
					@ -698,7 +613,7 @@ void GDExtension::_register_extension_class_signal(GDExtensionClassLibraryPtr p_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	StringName signal_name = *reinterpret_cast<const StringName *>(p_signal_name);
 | 
						StringName signal_name = *reinterpret_cast<const StringName *>(p_signal_name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + signal_name + "' for unexisting class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class signal '%s' for unexisting class '%s'.", signal_name, class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	// If the extension is still marked as reloading, that means it failed to register again.
 | 
						// If the extension is still marked as reloading, that means it failed to register again.
 | 
				
			||||||
| 
						 | 
					@ -721,7 +636,7 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra
 | 
				
			||||||
	GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
						GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
						StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
 | 
						ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to unregister unexisting extension class '%s'.", class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Extension *ext = &self->extension_classes[class_name];
 | 
						Extension *ext = &self->extension_classes[class_name];
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -729,7 +644,7 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra
 | 
				
			||||||
		self->_clear_extension(ext);
 | 
							self->_clear_extension(ext);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	ERR_FAIL_COND_MSG(ext->gdextension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
 | 
						ERR_FAIL_COND_MSG(ext->gdextension.children.size(), vformat("Attempt to unregister class '%s' while other extension classes inherit from it.", class_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	ClassDB::unregister_extension_class(class_name, !ext->is_reloading);
 | 
						ClassDB::unregister_extension_class(class_name, !ext->is_reloading);
 | 
				
			||||||
| 
						 | 
					@ -755,80 +670,54 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra
 | 
				
			||||||
void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringPtr r_path) {
 | 
					void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringPtr r_path) {
 | 
				
			||||||
	GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
						GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memnew_placement(r_path, String(self->library_path));
 | 
						Ref<GDExtensionLibraryLoader> library_loader = self->loader;
 | 
				
			||||||
 | 
						String library_path;
 | 
				
			||||||
 | 
						if (library_loader.is_valid()) {
 | 
				
			||||||
 | 
							library_path = library_loader->library_path;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memnew_placement(r_path, String(library_path));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions;
 | 
					HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
 | 
					void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), "Attempt to register interface function '" + p_function_name + "', which appears to be already registered.");
 | 
						ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), vformat("Attempt to register interface function '%s', which appears to be already registered.", p_function_name));
 | 
				
			||||||
	gdextension_interface_functions.insert(p_function_name, p_function_pointer);
 | 
						gdextension_interface_functions.insert(p_function_name, p_function_pointer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const StringName &p_function_name) {
 | 
					GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const StringName &p_function_name) {
 | 
				
			||||||
	GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
 | 
						GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
 | 
				
			||||||
	ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + ".");
 | 
						ERR_FAIL_NULL_V_MSG(function, nullptr, vformat("Attempt to get non-existent interface function: '%s'.", String(p_function_name)));
 | 
				
			||||||
	return *function;
 | 
						return *function;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies) {
 | 
					Error GDExtension::open_library(const String &p_path, const Ref<GDExtensionLoader> &p_loader) {
 | 
				
			||||||
	String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path);
 | 
						ERR_FAIL_COND_V_MSG(p_loader.is_null(), FAILED, "Can't open GDExtension without a loader.");
 | 
				
			||||||
 | 
						loader = p_loader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Vector<String> abs_dependencies_paths;
 | 
						Error err = loader->open_library(p_path);
 | 
				
			||||||
	if (p_dependencies != nullptr && !p_dependencies->is_empty()) {
 | 
					 | 
				
			||||||
		for (const SharedObject &dependency : *p_dependencies) {
 | 
					 | 
				
			||||||
			abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String actual_lib_path;
 | 
						ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, vformat("GDExtension dynamic library not found: '%s'.", p_path));
 | 
				
			||||||
	OS::GDExtensionData data = {
 | 
						ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Can't open GDExtension dynamic library: '%s'.", p_path));
 | 
				
			||||||
		true, // also_set_library_path
 | 
					 | 
				
			||||||
		&actual_lib_path, // r_resolved_path
 | 
					 | 
				
			||||||
		Engine::get_singleton()->is_editor_hint(), // generate_temp_files
 | 
					 | 
				
			||||||
		&abs_dependencies_paths, // library_dependencies
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (actual_lib_path.get_file() != abs_path.get_file()) {
 | 
						err = loader->initialize(&gdextension_get_proc_address, this, &initialization);
 | 
				
			||||||
		// If temporary files are generated, let's change the library path to point at the original,
 | 
					 | 
				
			||||||
		// because that's what we want to check to see if it's changed.
 | 
					 | 
				
			||||||
		library_path = actual_lib_path.get_base_dir().path_join(p_path.get_file());
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		library_path = actual_lib_path;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path);
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + abs_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *entry_funcptr = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err != OK) {
 | 
						if (err != OK) {
 | 
				
			||||||
		ERR_PRINT("GDExtension entry point '" + p_entry_symbol + "' not found in library " + abs_path);
 | 
							// Errors already logged in initialize().
 | 
				
			||||||
		OS::get_singleton()->close_dynamic_library(library);
 | 
							loader->close_library();
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
 | 
						level_initialized = -1;
 | 
				
			||||||
	GDExtensionBool ret = initialization_function(&gdextension_get_proc_address, this, &initialization);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret) {
 | 
						return OK;
 | 
				
			||||||
		level_initialized = -1;
 | 
					 | 
				
			||||||
		return OK;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ERR_PRINT("GDExtension initialization function '" + p_entry_symbol + "' returned an error.");
 | 
					 | 
				
			||||||
		OS::get_singleton()->close_dynamic_library(library);
 | 
					 | 
				
			||||||
		return FAILED;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::close_library() {
 | 
					void GDExtension::close_library() {
 | 
				
			||||||
	ERR_FAIL_NULL(library);
 | 
						ERR_FAIL_COND(!is_library_open());
 | 
				
			||||||
	OS::get_singleton()->close_dynamic_library(library);
 | 
						loader->close_library();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	library = nullptr;
 | 
					 | 
				
			||||||
	class_icon_paths.clear();
 | 
						class_icon_paths.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -837,16 +726,16 @@ void GDExtension::close_library() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool GDExtension::is_library_open() const {
 | 
					bool GDExtension::is_library_open() const {
 | 
				
			||||||
	return library != nullptr;
 | 
						return loader.is_valid() && loader->is_library_open();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const {
 | 
					GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const {
 | 
				
			||||||
	ERR_FAIL_NULL_V(library, INITIALIZATION_LEVEL_CORE);
 | 
						ERR_FAIL_COND_V(!is_library_open(), INITIALIZATION_LEVEL_CORE);
 | 
				
			||||||
	return InitializationLevel(initialization.minimum_initialization_level);
 | 
						return InitializationLevel(initialization.minimum_initialization_level);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::initialize_library(InitializationLevel p_level) {
 | 
					void GDExtension::initialize_library(InitializationLevel p_level) {
 | 
				
			||||||
	ERR_FAIL_NULL(library);
 | 
						ERR_FAIL_COND(!is_library_open());
 | 
				
			||||||
	ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
 | 
						ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	level_initialized = int32_t(p_level);
 | 
						level_initialized = int32_t(p_level);
 | 
				
			||||||
| 
						 | 
					@ -856,7 +745,7 @@ void GDExtension::initialize_library(InitializationLevel p_level) {
 | 
				
			||||||
	initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level));
 | 
						initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void GDExtension::deinitialize_library(InitializationLevel p_level) {
 | 
					void GDExtension::deinitialize_library(InitializationLevel p_level) {
 | 
				
			||||||
	ERR_FAIL_NULL(library);
 | 
						ERR_FAIL_COND(!is_library_open());
 | 
				
			||||||
	ERR_FAIL_COND(p_level > int32_t(level_initialized));
 | 
						ERR_FAIL_COND(p_level > int32_t(level_initialized));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	level_initialized = int32_t(p_level) - 1;
 | 
						level_initialized = int32_t(p_level) - 1;
 | 
				
			||||||
| 
						 | 
					@ -880,7 +769,7 @@ GDExtension::GDExtension() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtension::~GDExtension() {
 | 
					GDExtension::~GDExtension() {
 | 
				
			||||||
	if (library != nullptr) {
 | 
						if (is_library_open()) {
 | 
				
			||||||
		close_library();
 | 
							close_library();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -897,8 +786,9 @@ void GDExtension::initialize_gdextensions() {
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
	register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class);
 | 
						register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class);
 | 
				
			||||||
	register_interface_function("classdb_register_extension_class2", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class2);
 | 
						register_interface_function("classdb_register_extension_class2", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class2);
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					 | 
				
			||||||
	register_interface_function("classdb_register_extension_class3", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class3);
 | 
						register_interface_function("classdb_register_extension_class3", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class3);
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						register_interface_function("classdb_register_extension_class4", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class4);
 | 
				
			||||||
	register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
 | 
						register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
 | 
				
			||||||
	register_interface_function("classdb_register_extension_class_virtual_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_virtual_method);
 | 
						register_interface_function("classdb_register_extension_class_virtual_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_virtual_method);
 | 
				
			||||||
	register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
 | 
						register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
 | 
				
			||||||
| 
						 | 
					@ -918,142 +808,15 @@ void GDExtension::finalize_gdextensions() {
 | 
				
			||||||
Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension) {
 | 
					Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension) {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(p_extension.is_valid() && p_extension->is_library_open(), ERR_ALREADY_IN_USE, "Cannot load GDExtension resource into already opened library.");
 | 
						ERR_FAIL_COND_V_MSG(p_extension.is_valid() && p_extension->is_library_open(), ERR_ALREADY_IN_USE, "Cannot load GDExtension resource into already opened library.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<ConfigFile> config;
 | 
						GDExtensionManager *extension_manager = GDExtensionManager::get_singleton();
 | 
				
			||||||
	config.instantiate();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = config->load(p_path);
 | 
						GDExtensionManager::LoadStatus status = extension_manager->load_extension(p_path);
 | 
				
			||||||
 | 
						if (status != GDExtensionManager::LOAD_STATUS_OK && status != GDExtensionManager::LOAD_STATUS_ALREADY_LOADED) {
 | 
				
			||||||
	if (err != OK) {
 | 
							// Errors already logged in load_extension().
 | 
				
			||||||
		ERR_PRINT("Error loading GDExtension configuration file: " + p_path);
 | 
							return FAILED;
 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!config->has_section_key("configuration", "entry_symbol")) {
 | 
					 | 
				
			||||||
		ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path);
 | 
					 | 
				
			||||||
		return ERR_INVALID_DATA;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String 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("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: " + p_path);
 | 
					 | 
				
			||||||
		return ERR_INVALID_DATA;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) {
 | 
					 | 
				
			||||||
		ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
 | 
					 | 
				
			||||||
		return ERR_INVALID_DATA;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool compatible = true;
 | 
					 | 
				
			||||||
	// Check version lexicographically.
 | 
					 | 
				
			||||||
	if (VERSION_MAJOR != compatibility_minimum[0]) {
 | 
					 | 
				
			||||||
		compatible = VERSION_MAJOR > compatibility_minimum[0];
 | 
					 | 
				
			||||||
	} else if (VERSION_MINOR != compatibility_minimum[1]) {
 | 
					 | 
				
			||||||
		compatible = VERSION_MINOR > compatibility_minimum[1];
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		compatible = VERSION_PATCH >= compatibility_minimum[2];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compatible) {
 | 
					 | 
				
			||||||
		ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
 | 
					 | 
				
			||||||
		return ERR_INVALID_DATA;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Optionally check maximum compatibility.
 | 
					 | 
				
			||||||
	if (config->has_section_key("configuration", "compatibility_maximum")) {
 | 
					 | 
				
			||||||
		uint32_t compatibility_maximum[3] = { 0, 0, 0 };
 | 
					 | 
				
			||||||
		String compat_string = config->get_value("configuration", "compatibility_maximum");
 | 
					 | 
				
			||||||
		Vector<int> parts = compat_string.split_ints(".");
 | 
					 | 
				
			||||||
		for (int i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
			if (i < parts.size() && parts[i] >= 0) {
 | 
					 | 
				
			||||||
				compatibility_maximum[i] = parts[i];
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				// If a version part is missing, set the maximum to an arbitrary high value.
 | 
					 | 
				
			||||||
				compatibility_maximum[i] = 9999;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		compatible = true;
 | 
					 | 
				
			||||||
		if (VERSION_MAJOR != compatibility_maximum[0]) {
 | 
					 | 
				
			||||||
			compatible = VERSION_MAJOR < compatibility_maximum[0];
 | 
					 | 
				
			||||||
		} else if (VERSION_MINOR != compatibility_maximum[1]) {
 | 
					 | 
				
			||||||
			compatible = VERSION_MINOR < compatibility_maximum[1];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#if VERSION_PATCH
 | 
					 | 
				
			||||||
		// #if check to avoid -Wtype-limits warning when 0.
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			compatible = VERSION_PATCH <= compatibility_maximum[2];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!compatible) {
 | 
					 | 
				
			||||||
			ERR_PRINT(vformat("GDExtension only compatible with Godot version %s or earlier: %s", compat_string, p_path));
 | 
					 | 
				
			||||||
			return ERR_INVALID_DATA;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String library_path = GDExtension::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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool 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);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p_extension.is_null()) {
 | 
					 | 
				
			||||||
		p_extension.instantiate();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					 | 
				
			||||||
	p_extension->set_reloadable(config->get_value("configuration", "reloadable", false) && Engine::get_singleton()->is_extension_reloading_enabled());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p_extension->update_last_modified_time(
 | 
					 | 
				
			||||||
			FileAccess::get_modified_time(p_path),
 | 
					 | 
				
			||||||
			FileAccess::get_modified_time(library_path));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Vector<SharedObject> library_dependencies = GDExtension::find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
 | 
					 | 
				
			||||||
	err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol, &library_dependencies);
 | 
					 | 
				
			||||||
	if (err != OK) {
 | 
					 | 
				
			||||||
		// Unreference the extension so that this loading can be considered a failure.
 | 
					 | 
				
			||||||
		p_extension.unref();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Errors already logged in open_library()
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 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);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			p_extension->class_icon_paths[key] = icon_path;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p_extension = extension_manager->get_extension(p_path);
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1094,16 +857,7 @@ String GDExtensionResourceLoader::get_resource_type(const String &p_path) const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
bool GDExtension::has_library_changed() const {
 | 
					bool GDExtension::has_library_changed() const {
 | 
				
			||||||
	// Check only that the last modified time is different (rather than checking
 | 
						return loader->has_library_changed();
 | 
				
			||||||
	// 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(get_path()) != resource_last_modified_time) {
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtension::prepare_reload() {
 | 
					void GDExtension::prepare_reload() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,13 +31,11 @@
 | 
				
			||||||
#ifndef GDEXTENSION_H
 | 
					#ifndef GDEXTENSION_H
 | 
				
			||||||
#define GDEXTENSION_H
 | 
					#define GDEXTENSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core/extension/gdextension_interface.h"
 | 
					#include "core/extension/gdextension_interface.h"
 | 
				
			||||||
 | 
					#include "core/extension/gdextension_loader.h"
 | 
				
			||||||
#include "core/io/config_file.h"
 | 
					#include "core/io/config_file.h"
 | 
				
			||||||
#include "core/io/resource_loader.h"
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
#include "core/object/ref_counted.h"
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
#include "core/os/shared_object.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GDExtensionMethodBind;
 | 
					class GDExtensionMethodBind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,8 +44,8 @@ class GDExtension : public Resource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	friend class GDExtensionManager;
 | 
						friend class GDExtensionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *library = nullptr; // pointer if valid,
 | 
						Ref<GDExtensionLoader> loader;
 | 
				
			||||||
	String library_path;
 | 
					
 | 
				
			||||||
	bool reloadable = false;
 | 
						bool reloadable = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Extension {
 | 
						struct Extension {
 | 
				
			||||||
| 
						 | 
					@ -72,15 +70,20 @@ class GDExtension : public Resource {
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
		GDExtensionClassNotification notification_func = nullptr;
 | 
							GDExtensionClassNotification notification_func = nullptr;
 | 
				
			||||||
		GDExtensionClassFreePropertyList free_property_list_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
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef 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_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_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					 | 
				
			||||||
	static void _register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *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);
 | 
				
			||||||
	static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr);
 | 
					#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_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_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_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);
 | 
				
			||||||
| 
						 | 
					@ -96,8 +99,6 @@ class GDExtension : public Resource {
 | 
				
			||||||
	int32_t level_initialized = -1;
 | 
						int32_t level_initialized = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	uint64_t resource_last_modified_time = 0;
 | 
					 | 
				
			||||||
	uint64_t library_last_modified_time = 0;
 | 
					 | 
				
			||||||
	bool is_reloading = false;
 | 
						bool is_reloading = false;
 | 
				
			||||||
	Vector<GDExtensionMethodBind *> invalid_methods;
 | 
						Vector<GDExtensionMethodBind *> invalid_methods;
 | 
				
			||||||
	Vector<ObjectID> instance_bindings;
 | 
						Vector<ObjectID> instance_bindings;
 | 
				
			||||||
| 
						 | 
					@ -124,11 +125,12 @@ public:
 | 
				
			||||||
	virtual bool editor_can_reload_from_file() override { return false; } // Reloading is handled in a special way.
 | 
						virtual bool editor_can_reload_from_file() override { return false; } // Reloading is handled in a special way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static String get_extension_list_config_file();
 | 
						static String get_extension_list_config_file();
 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies = nullptr);
 | 
						const Ref<GDExtensionLoader> get_loader() const { return loader; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error open_library(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
 | 
				
			||||||
	void close_library();
 | 
						void close_library();
 | 
				
			||||||
 | 
						bool is_library_open() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum InitializationLevel {
 | 
						enum InitializationLevel {
 | 
				
			||||||
		INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
 | 
							INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
 | 
				
			||||||
| 
						 | 
					@ -146,17 +148,11 @@ protected:
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	bool is_library_open() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	bool is_reloadable() const { return reloadable; }
 | 
						bool is_reloadable() const { return reloadable; }
 | 
				
			||||||
	void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
 | 
						void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_library_changed() const;
 | 
						bool has_library_changed() const;
 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void track_instance_binding(Object *p_object);
 | 
						void track_instance_binding(Object *p_object);
 | 
				
			||||||
	void untrack_instance_binding(Object *p_object);
 | 
						void untrack_instance_binding(Object *p_object);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +32,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/engine.h"
 | 
					#include "core/config/engine.h"
 | 
				
			||||||
#include "core/extension/gdextension.h"
 | 
					#include "core/extension/gdextension.h"
 | 
				
			||||||
#include "core/extension/gdextension_compat_hashes.h"
 | 
					#include "core/extension/gdextension_special_compat_hashes.h"
 | 
				
			||||||
#include "core/io/file_access.h"
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
 | 
					#include "core/io/image.h"
 | 
				
			||||||
#include "core/io/xml_parser.h"
 | 
					#include "core/io/xml_parser.h"
 | 
				
			||||||
#include "core/object/class_db.h"
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
#include "core/object/script_language_extension.h"
 | 
					#include "core/object/script_language_extension.h"
 | 
				
			||||||
| 
						 | 
					@ -507,6 +508,14 @@ static GDExtensionBool gdextension_variant_has_key(GDExtensionConstVariantPtr p_
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDObjectInstanceID gdextension_variant_get_object_instance_id(GDExtensionConstVariantPtr p_self) {
 | 
				
			||||||
 | 
						const Variant *self = (const Variant *)p_self;
 | 
				
			||||||
 | 
						if (likely(self->get_type() == Variant::OBJECT)) {
 | 
				
			||||||
 | 
							return self->operator ObjectID();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gdextension_variant_get_type_name(GDExtensionVariantType p_type, GDExtensionUninitializedVariantPtr r_ret) {
 | 
					static void gdextension_variant_get_type_name(GDExtensionVariantType p_type, GDExtensionUninitializedVariantPtr r_ret) {
 | 
				
			||||||
	String name = Variant::get_type_name((Variant::Type)p_type);
 | 
						String name = Variant::get_type_name((Variant::Type)p_type);
 | 
				
			||||||
	memnew_placement(r_ret, String(name));
 | 
						memnew_placement(r_ret, String(name));
 | 
				
			||||||
| 
						 | 
					@ -691,6 +700,91 @@ static GDExtensionTypeFromVariantConstructorFunc gdextension_get_variant_to_type
 | 
				
			||||||
	ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
 | 
						ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDExtensionVariantGetInternalPtrFunc gdextension_variant_get_ptr_internal_getter(GDExtensionVariantType p_type) {
 | 
				
			||||||
 | 
						switch (p_type) {
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_BOOL:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<bool *(*)(Variant *)>(VariantInternal::get_bool));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_INT:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<int64_t *(*)(Variant *)>(VariantInternal::get_int));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_FLOAT:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<double *(*)(Variant *)>(VariantInternal::get_float));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_STRING:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<String *(*)(Variant *)>(VariantInternal::get_string));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR2:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector2 *(*)(Variant *)>(VariantInternal::get_vector2));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR2I:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector2i *(*)(Variant *)>(VariantInternal::get_vector2i));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_RECT2:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Rect2 *(*)(Variant *)>(VariantInternal::get_rect2));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_RECT2I:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Rect2i *(*)(Variant *)>(VariantInternal::get_rect2i));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR3:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector3 *(*)(Variant *)>(VariantInternal::get_vector3));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR3I:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector3i *(*)(Variant *)>(VariantInternal::get_vector3i));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_TRANSFORM2D:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Transform2D *(*)(Variant *)>(VariantInternal::get_transform2d));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR4:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector4 *(*)(Variant *)>(VariantInternal::get_vector4));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VECTOR4I:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector4i *(*)(Variant *)>(VariantInternal::get_vector4i));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PLANE:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Plane *(*)(Variant *)>(VariantInternal::get_plane));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_QUATERNION:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Quaternion *(*)(Variant *)>(VariantInternal::get_quaternion));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_AABB:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<AABB *(*)(Variant *)>(VariantInternal::get_aabb));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_BASIS:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Basis *(*)(Variant *)>(VariantInternal::get_basis));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_TRANSFORM3D:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Transform3D *(*)(Variant *)>(VariantInternal::get_transform));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PROJECTION:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Projection *(*)(Variant *)>(VariantInternal::get_projection));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_COLOR:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Color *(*)(Variant *)>(VariantInternal::get_color));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_STRING_NAME:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<StringName *(*)(Variant *)>(VariantInternal::get_string_name));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_NODE_PATH:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<NodePath *(*)(Variant *)>(VariantInternal::get_node_path));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_RID:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<RID *(*)(Variant *)>(VariantInternal::get_rid));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_OBJECT:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Object **(*)(Variant *)>(VariantInternal::get_object));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_CALLABLE:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Callable *(*)(Variant *)>(VariantInternal::get_callable));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_SIGNAL:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Signal *(*)(Variant *)>(VariantInternal::get_signal));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_DICTIONARY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Dictionary *(*)(Variant *)>(VariantInternal::get_dictionary));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Array *(*)(Variant *)>(VariantInternal::get_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedByteArray *(*)(Variant *)>(VariantInternal::get_byte_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedInt32Array *(*)(Variant *)>(VariantInternal::get_int32_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedInt64Array *(*)(Variant *)>(VariantInternal::get_int64_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedFloat32Array *(*)(Variant *)>(VariantInternal::get_float32_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedFloat64Array *(*)(Variant *)>(VariantInternal::get_float64_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedStringArray *(*)(Variant *)>(VariantInternal::get_string_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector2Array *(*)(Variant *)>(VariantInternal::get_vector2_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector3Array *(*)(Variant *)>(VariantInternal::get_vector3_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedColorArray *(*)(Variant *)>(VariantInternal::get_color_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY:
 | 
				
			||||||
 | 
								return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector4Array *(*)(Variant *)>(VariantInternal::get_vector4_array));
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_NIL:
 | 
				
			||||||
 | 
							case GDEXTENSION_VARIANT_TYPE_VARIANT_MAX:
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(nullptr, "Getting Variant get internal pointer function with invalid type.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ERR_FAIL_V_MSG(nullptr, "Getting Variant get internal pointer function with invalid type.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ptrcalls
 | 
					// ptrcalls
 | 
				
			||||||
static GDExtensionPtrOperatorEvaluator gdextension_variant_get_ptr_operator_evaluator(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b) {
 | 
					static GDExtensionPtrOperatorEvaluator gdextension_variant_get_ptr_operator_evaluator(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b) {
 | 
				
			||||||
	return (GDExtensionPtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
 | 
						return (GDExtensionPtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
 | 
				
			||||||
| 
						 | 
					@ -1199,6 +1293,15 @@ static GDExtensionVariantPtr gdextension_dictionary_operator_index_const(GDExten
 | 
				
			||||||
	return (GDExtensionVariantPtr)&self->operator[](*(const Variant *)p_key);
 | 
						return (GDExtensionVariantPtr)&self->operator[](*(const Variant *)p_key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gdextension_dictionary_set_typed(GDExtensionTypePtr p_self, GDExtensionVariantType p_key_type, GDExtensionConstStringNamePtr p_key_class_name, GDExtensionConstVariantPtr p_key_script, GDExtensionVariantType p_value_type, GDExtensionConstStringNamePtr p_value_class_name, GDExtensionConstVariantPtr p_value_script) {
 | 
				
			||||||
 | 
						Dictionary *self = reinterpret_cast<Dictionary *>(p_self);
 | 
				
			||||||
 | 
						const StringName *key_class_name = reinterpret_cast<const StringName *>(p_key_class_name);
 | 
				
			||||||
 | 
						const Variant *key_script = reinterpret_cast<const Variant *>(p_key_script);
 | 
				
			||||||
 | 
						const StringName *value_class_name = reinterpret_cast<const StringName *>(p_value_class_name);
 | 
				
			||||||
 | 
						const Variant *value_script = reinterpret_cast<const Variant *>(p_value_script);
 | 
				
			||||||
 | 
						self->set_typed((uint32_t)p_key_type, *key_class_name, *key_script, (uint32_t)p_value_type, *value_class_name, *value_script);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* OBJECT API */
 | 
					/* OBJECT API */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gdextension_object_method_bind_call(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error) {
 | 
					static void gdextension_object_method_bind_call(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error) {
 | 
				
			||||||
| 
						 | 
					@ -1299,7 +1402,7 @@ static void gdextension_object_call_script_method(GDExtensionObjectPtr p_object,
 | 
				
			||||||
	const StringName method = *reinterpret_cast<const StringName *>(p_method);
 | 
						const StringName method = *reinterpret_cast<const StringName *>(p_method);
 | 
				
			||||||
	const Variant **args = (const Variant **)p_args;
 | 
						const Variant **args = (const Variant **)p_args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Callable::CallError error;
 | 
						Callable::CallError error; // TODO: Check `error`?
 | 
				
			||||||
	memnew_placement(r_return, Variant);
 | 
						memnew_placement(r_return, Variant);
 | 
				
			||||||
	*(Variant *)r_return = o->callp(method, args, p_argument_count, error);
 | 
						*(Variant *)r_return = o->callp(method, args, p_argument_count, error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1501,24 +1604,31 @@ static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionC
 | 
				
			||||||
	// If lookup failed, see if this is one of the broken hashes from issue #81386.
 | 
						// If lookup failed, see if this is one of the broken hashes from issue #81386.
 | 
				
			||||||
	if (!mb && exists) {
 | 
						if (!mb && exists) {
 | 
				
			||||||
		uint32_t mapped_hash;
 | 
							uint32_t mapped_hash;
 | 
				
			||||||
		if (GDExtensionCompatHashes::lookup_current_hash(classname, methodname, p_hash, &mapped_hash)) {
 | 
							if (GDExtensionSpecialCompatHashes::lookup_current_hash(classname, methodname, p_hash, &mapped_hash)) {
 | 
				
			||||||
			mb = ClassDB::get_method_with_compatibility(classname, methodname, mapped_hash, &exists);
 | 
								mb = ClassDB::get_method_with_compatibility(classname, methodname, mapped_hash, &exists);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mb && exists) {
 | 
						if (!mb && exists) {
 | 
				
			||||||
		ERR_PRINT("Method '" + classname + "." + methodname + "' has changed and no compatibility fallback has been provided. Please open an issue.");
 | 
							ERR_PRINT(vformat("Method '%s.%s' has changed and no compatibility fallback has been provided. Please open an issue.", classname, methodname));
 | 
				
			||||||
		return nullptr;
 | 
							return nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ERR_FAIL_NULL_V(mb, nullptr);
 | 
						ERR_FAIL_NULL_V(mb, nullptr);
 | 
				
			||||||
	return (GDExtensionMethodBindPtr)mb;
 | 
						return (GDExtensionMethodBindPtr)mb;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
static GDExtensionObjectPtr gdextension_classdb_construct_object(GDExtensionConstStringNamePtr p_classname) {
 | 
					static GDExtensionObjectPtr gdextension_classdb_construct_object(GDExtensionConstStringNamePtr p_classname) {
 | 
				
			||||||
	const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
 | 
						const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
 | 
				
			||||||
	return (GDExtensionObjectPtr)ClassDB::instantiate_no_placeholders(classname);
 | 
						return (GDExtensionObjectPtr)ClassDB::instantiate_no_placeholders(classname);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDExtensionObjectPtr gdextension_classdb_construct_object2(GDExtensionConstStringNamePtr p_classname) {
 | 
				
			||||||
 | 
						const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
 | 
				
			||||||
 | 
						return (GDExtensionObjectPtr)ClassDB::instantiate_without_postinitialization(classname);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *gdextension_classdb_get_class_tag(GDExtensionConstStringNamePtr p_classname) {
 | 
					static void *gdextension_classdb_get_class_tag(GDExtensionConstStringNamePtr p_classname) {
 | 
				
			||||||
	const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
 | 
						const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
 | 
				
			||||||
| 
						 | 
					@ -1594,11 +1704,13 @@ void gdextension_setup_interface() {
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_has_method);
 | 
						REGISTER_INTERFACE_FUNC(variant_has_method);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_has_member);
 | 
						REGISTER_INTERFACE_FUNC(variant_has_member);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_has_key);
 | 
						REGISTER_INTERFACE_FUNC(variant_has_key);
 | 
				
			||||||
 | 
						REGISTER_INTERFACE_FUNC(variant_get_object_instance_id);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_get_type_name);
 | 
						REGISTER_INTERFACE_FUNC(variant_get_type_name);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_can_convert);
 | 
						REGISTER_INTERFACE_FUNC(variant_can_convert);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_can_convert_strict);
 | 
						REGISTER_INTERFACE_FUNC(variant_can_convert_strict);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(get_variant_from_type_constructor);
 | 
						REGISTER_INTERFACE_FUNC(get_variant_from_type_constructor);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(get_variant_to_type_constructor);
 | 
						REGISTER_INTERFACE_FUNC(get_variant_to_type_constructor);
 | 
				
			||||||
 | 
						REGISTER_INTERFACE_FUNC(variant_get_ptr_internal_getter);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_get_ptr_operator_evaluator);
 | 
						REGISTER_INTERFACE_FUNC(variant_get_ptr_operator_evaluator);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_get_ptr_builtin_method);
 | 
						REGISTER_INTERFACE_FUNC(variant_get_ptr_builtin_method);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(variant_get_ptr_constructor);
 | 
						REGISTER_INTERFACE_FUNC(variant_get_ptr_constructor);
 | 
				
			||||||
| 
						 | 
					@ -1672,6 +1784,7 @@ void gdextension_setup_interface() {
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(array_set_typed);
 | 
						REGISTER_INTERFACE_FUNC(array_set_typed);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(dictionary_operator_index);
 | 
						REGISTER_INTERFACE_FUNC(dictionary_operator_index);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(dictionary_operator_index_const);
 | 
						REGISTER_INTERFACE_FUNC(dictionary_operator_index_const);
 | 
				
			||||||
 | 
						REGISTER_INTERFACE_FUNC(dictionary_set_typed);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(object_method_bind_call);
 | 
						REGISTER_INTERFACE_FUNC(object_method_bind_call);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(object_method_bind_ptrcall);
 | 
						REGISTER_INTERFACE_FUNC(object_method_bind_ptrcall);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(object_destroy);
 | 
						REGISTER_INTERFACE_FUNC(object_destroy);
 | 
				
			||||||
| 
						 | 
					@ -1701,7 +1814,10 @@ void gdextension_setup_interface() {
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(callable_custom_create2);
 | 
						REGISTER_INTERFACE_FUNC(callable_custom_create2);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
 | 
						REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(classdb_construct_object);
 | 
						REGISTER_INTERFACE_FUNC(classdb_construct_object);
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						REGISTER_INTERFACE_FUNC(classdb_construct_object2);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
 | 
						REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
 | 
						REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
 | 
				
			||||||
	REGISTER_INTERFACE_FUNC(editor_add_plugin);
 | 
						REGISTER_INTERFACE_FUNC(editor_add_plugin);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,6 +198,7 @@ typedef struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
 | 
					typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
 | 
				
			||||||
typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
 | 
					typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
 | 
				
			||||||
 | 
					typedef void *(*GDExtensionVariantGetInternalPtrFunc)(GDExtensionVariantPtr);
 | 
				
			||||||
typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
 | 
					typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
 | 
				
			||||||
typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
 | 
					typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
 | 
				
			||||||
typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
 | 
					typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
 | 
				
			||||||
| 
						 | 
					@ -268,10 +269,13 @@ typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance
 | 
				
			||||||
typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
 | 
					typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
 | 
				
			||||||
typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
 | 
					typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
 | 
				
			||||||
typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_class_userdata);
 | 
					typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_class_userdata);
 | 
				
			||||||
 | 
					typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance2)(void *p_class_userdata, GDExtensionBool p_notify_postinitialize);
 | 
				
			||||||
typedef void (*GDExtensionClassFreeInstance)(void *p_class_userdata, GDExtensionClassInstancePtr p_instance);
 | 
					typedef void (*GDExtensionClassFreeInstance)(void *p_class_userdata, GDExtensionClassInstancePtr p_instance);
 | 
				
			||||||
typedef GDExtensionClassInstancePtr (*GDExtensionClassRecreateInstance)(void *p_class_userdata, GDExtensionObjectPtr p_object);
 | 
					typedef GDExtensionClassInstancePtr (*GDExtensionClassRecreateInstance)(void *p_class_userdata, GDExtensionObjectPtr p_object);
 | 
				
			||||||
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
 | 
					typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
 | 
				
			||||||
 | 
					typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
 | 
				
			||||||
typedef void *(*GDExtensionClassGetVirtualCallData)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
 | 
					typedef void *(*GDExtensionClassGetVirtualCallData)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
 | 
				
			||||||
 | 
					typedef void *(*GDExtensionClassGetVirtualCallData2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
 | 
				
			||||||
typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_virtual_call_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
 | 
					typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_virtual_call_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
| 
						 | 
					@ -292,7 +296,7 @@ typedef struct {
 | 
				
			||||||
	GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
 | 
						GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
 | 
				
			||||||
	GDExtensionClassGetRID get_rid_func;
 | 
						GDExtensionClassGetRID get_rid_func;
 | 
				
			||||||
	void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
						void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
				
			||||||
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
 | 
					} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	GDExtensionBool is_virtual;
 | 
						GDExtensionBool is_virtual;
 | 
				
			||||||
| 
						 | 
					@ -325,7 +329,7 @@ typedef struct {
 | 
				
			||||||
	GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
 | 
						GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
 | 
				
			||||||
	GDExtensionClassGetRID get_rid_func;
 | 
						GDExtensionClassGetRID get_rid_func;
 | 
				
			||||||
	void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
						void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
				
			||||||
} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
 | 
					} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	GDExtensionBool is_virtual;
 | 
						GDExtensionBool is_virtual;
 | 
				
			||||||
| 
						 | 
					@ -359,7 +363,41 @@ typedef struct {
 | 
				
			||||||
	GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
 | 
						GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
 | 
				
			||||||
	GDExtensionClassGetRID get_rid_func;
 | 
						GDExtensionClassGetRID get_rid_func;
 | 
				
			||||||
	void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
						void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
				
			||||||
} GDExtensionClassCreationInfo3;
 | 
					} GDExtensionClassCreationInfo3; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						GDExtensionBool is_virtual;
 | 
				
			||||||
 | 
						GDExtensionBool is_abstract;
 | 
				
			||||||
 | 
						GDExtensionBool is_exposed;
 | 
				
			||||||
 | 
						GDExtensionBool is_runtime;
 | 
				
			||||||
 | 
						GDExtensionConstStringPtr icon_path;
 | 
				
			||||||
 | 
						GDExtensionClassSet set_func;
 | 
				
			||||||
 | 
						GDExtensionClassGet get_func;
 | 
				
			||||||
 | 
						GDExtensionClassGetPropertyList get_property_list_func;
 | 
				
			||||||
 | 
						GDExtensionClassFreePropertyList2 free_property_list_func;
 | 
				
			||||||
 | 
						GDExtensionClassPropertyCanRevert property_can_revert_func;
 | 
				
			||||||
 | 
						GDExtensionClassPropertyGetRevert property_get_revert_func;
 | 
				
			||||||
 | 
						GDExtensionClassValidateProperty validate_property_func;
 | 
				
			||||||
 | 
						GDExtensionClassNotification2 notification_func;
 | 
				
			||||||
 | 
						GDExtensionClassToString to_string_func;
 | 
				
			||||||
 | 
						GDExtensionClassReference reference_func;
 | 
				
			||||||
 | 
						GDExtensionClassUnreference unreference_func;
 | 
				
			||||||
 | 
						GDExtensionClassCreateInstance2 create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
 | 
				
			||||||
 | 
						GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
 | 
				
			||||||
 | 
						GDExtensionClassRecreateInstance recreate_instance_func;
 | 
				
			||||||
 | 
						// Queries a virtual function by name and returns a callback to invoke the requested virtual function.
 | 
				
			||||||
 | 
						GDExtensionClassGetVirtual2 get_virtual_func;
 | 
				
			||||||
 | 
						// Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
 | 
				
			||||||
 | 
						// need or benefit from extra data when calling virtual functions.
 | 
				
			||||||
 | 
						// Returns user data that will be passed to `call_virtual_with_data_func`.
 | 
				
			||||||
 | 
						// Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
 | 
				
			||||||
 | 
						// Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
 | 
				
			||||||
 | 
						// You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
 | 
				
			||||||
 | 
						GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
 | 
				
			||||||
 | 
						// Used to call virtual functions when `get_virtual_call_data_func` is not null.
 | 
				
			||||||
 | 
						GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
 | 
				
			||||||
 | 
						void *class_userdata; // Per-class user data, later accessible in instance bindings.
 | 
				
			||||||
 | 
					} GDExtensionClassCreationInfo4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void *GDExtensionClassLibraryPtr;
 | 
					typedef void *GDExtensionClassLibraryPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -386,7 +424,9 @@ typedef enum {
 | 
				
			||||||
	GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
 | 
				
			||||||
	GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
 | 
				
			||||||
	GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
 | 
				
			||||||
	GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE,
 | 
				
			||||||
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16,
 | 
				
			||||||
 | 
						GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32,
 | 
				
			||||||
} GDExtensionClassMethodArgumentMetadata;
 | 
					} GDExtensionClassMethodArgumentMetadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
 | 
					typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
 | 
				
			||||||
| 
						 | 
					@ -805,7 +845,7 @@ typedef void (*GDExtensionInterfaceMemFree)(void *p_ptr);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs an error to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs an error to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the error.
 | 
					 * @param p_description The code triggering the error.
 | 
				
			||||||
 * @param p_function The function name where the error occurred.
 | 
					 * @param p_function The function name where the error occurred.
 | 
				
			||||||
 * @param p_file The file where the error occurred.
 | 
					 * @param p_file The file where the error occurred.
 | 
				
			||||||
 * @param p_line The line where the error occurred.
 | 
					 * @param p_line The line where the error occurred.
 | 
				
			||||||
| 
						 | 
					@ -819,7 +859,7 @@ typedef void (*GDExtensionInterfacePrintError)(const char *p_description, const
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs an error with a message to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs an error with a message to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the error.
 | 
					 * @param p_description The code triggering the error.
 | 
				
			||||||
 * @param p_message The message to show along with the error.
 | 
					 * @param p_message The message to show along with the error.
 | 
				
			||||||
 * @param p_function The function name where the error occurred.
 | 
					 * @param p_function The function name where the error occurred.
 | 
				
			||||||
 * @param p_file The file where the error occurred.
 | 
					 * @param p_file The file where the error occurred.
 | 
				
			||||||
| 
						 | 
					@ -834,7 +874,7 @@ typedef void (*GDExtensionInterfacePrintErrorWithMessage)(const char *p_descript
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs a warning to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs a warning to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the warning.
 | 
					 * @param p_description The code triggering the warning.
 | 
				
			||||||
 * @param p_function The function name where the warning occurred.
 | 
					 * @param p_function The function name where the warning occurred.
 | 
				
			||||||
 * @param p_file The file where the warning occurred.
 | 
					 * @param p_file The file where the warning occurred.
 | 
				
			||||||
 * @param p_line The line where the warning occurred.
 | 
					 * @param p_line The line where the warning occurred.
 | 
				
			||||||
| 
						 | 
					@ -848,7 +888,7 @@ typedef void (*GDExtensionInterfacePrintWarning)(const char *p_description, cons
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs a warning with a message to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs a warning with a message to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the warning.
 | 
					 * @param p_description The code triggering the warning.
 | 
				
			||||||
 * @param p_message The message to show along with the warning.
 | 
					 * @param p_message The message to show along with the warning.
 | 
				
			||||||
 * @param p_function The function name where the warning occurred.
 | 
					 * @param p_function The function name where the warning occurred.
 | 
				
			||||||
 * @param p_file The file where the warning occurred.
 | 
					 * @param p_file The file where the warning occurred.
 | 
				
			||||||
| 
						 | 
					@ -863,7 +903,7 @@ typedef void (*GDExtensionInterfacePrintWarningWithMessage)(const char *p_descri
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs a script error to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs a script error to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the error.
 | 
					 * @param p_description The code triggering the error.
 | 
				
			||||||
 * @param p_function The function name where the error occurred.
 | 
					 * @param p_function The function name where the error occurred.
 | 
				
			||||||
 * @param p_file The file where the error occurred.
 | 
					 * @param p_file The file where the error occurred.
 | 
				
			||||||
 * @param p_line The line where the error occurred.
 | 
					 * @param p_line The line where the error occurred.
 | 
				
			||||||
| 
						 | 
					@ -877,7 +917,7 @@ typedef void (*GDExtensionInterfacePrintScriptError)(const char *p_description,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Logs a script error with a message to Godot's built-in debugger and to the OS terminal.
 | 
					 * Logs a script error with a message to Godot's built-in debugger and to the OS terminal.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param p_description The code trigging the error.
 | 
					 * @param p_description The code triggering the error.
 | 
				
			||||||
 * @param p_message The message to show along with the error.
 | 
					 * @param p_message The message to show along with the error.
 | 
				
			||||||
 * @param p_function The function name where the error occurred.
 | 
					 * @param p_function The function name where the error occurred.
 | 
				
			||||||
 * @param p_file The file where the error occurred.
 | 
					 * @param p_file The file where the error occurred.
 | 
				
			||||||
| 
						 | 
					@ -1271,6 +1311,21 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid);
 | 
					typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @name variant_get_object_instance_id
 | 
				
			||||||
 | 
					 * @since 4.4
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Gets the object instance ID from a variant of type GDEXTENSION_VARIANT_TYPE_OBJECT.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the variant isn't of type GDEXTENSION_VARIANT_TYPE_OBJECT, then zero will be returned.
 | 
				
			||||||
 | 
					 * The instance ID will be returned even if the object is no longer valid - use `object_get_instance_by_id()` to check if the object is still valid.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p_self A pointer to the Variant.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return The instance ID for the contained object.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef GDObjectInstanceID (*GDExtensionInterfaceVariantGetObjectInstanceId)(GDExtensionConstVariantPtr p_self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name variant_get_type_name
 | 
					 * @name variant_get_type_name
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
| 
						 | 
					@ -1332,6 +1387,23 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVariantToTypeConstructor)(GDExtensionVariantType p_type);
 | 
					typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVariantToTypeConstructor)(GDExtensionVariantType p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @name variant_get_ptr_internal_getter
 | 
				
			||||||
 | 
					 * @since 4.4
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Provides a function pointer for retrieving a pointer to a variant's internal value.
 | 
				
			||||||
 | 
					 * Access to a variant's internal value can be used to modify it in-place, or to retrieve its value without the overhead of variant conversion functions.
 | 
				
			||||||
 | 
					 * It is recommended to cache the getter for all variant types in a function table to avoid retrieval overhead upon use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @note Each function assumes the variant's type has already been determined and matches the function.
 | 
				
			||||||
 | 
					 * Invoking the function with a variant of a mismatched type has undefined behavior, and may lead to a segmentation fault.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p_type The Variant type.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return A pointer to a type-specific function that returns a pointer to the internal value of a variant. Check the implementation of this function (gdextension_variant_get_ptr_internal_getter) for pointee type info of each variant type.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef GDExtensionVariantGetInternalPtrFunc (*GDExtensionInterfaceGetVariantGetInternalPtrFunc)(GDExtensionVariantType p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name variant_get_ptr_operator_evaluator
 | 
					 * @name variant_get_ptr_operator_evaluator
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
| 
						 | 
					@ -2337,6 +2409,22 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndex)(GDE
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key);
 | 
					typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @name dictionary_set_typed
 | 
				
			||||||
 | 
					 * @since 4.4
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Makes a Dictionary into a typed Dictionary.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p_self A pointer to the Dictionary.
 | 
				
			||||||
 | 
					 * @param p_key_type The type of Variant the Dictionary key will store.
 | 
				
			||||||
 | 
					 * @param p_key_class_name A pointer to a StringName with the name of the object (if p_key_type is GDEXTENSION_VARIANT_TYPE_OBJECT).
 | 
				
			||||||
 | 
					 * @param p_key_script A pointer to a Script object (if p_key_type is GDEXTENSION_VARIANT_TYPE_OBJECT and the base class is extended by a script).
 | 
				
			||||||
 | 
					 * @param p_value_type The type of Variant the Dictionary value will store.
 | 
				
			||||||
 | 
					 * @param p_value_class_name A pointer to a StringName with the name of the object (if p_value_type is GDEXTENSION_VARIANT_TYPE_OBJECT).
 | 
				
			||||||
 | 
					 * @param p_value_script A pointer to a Script object (if p_value_type is GDEXTENSION_VARIANT_TYPE_OBJECT and the base class is extended by a script).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef void (*GDExtensionInterfaceDictionarySetTyped)(GDExtensionTypePtr p_self, GDExtensionVariantType p_key_type, GDExtensionConstStringNamePtr p_key_class_name, GDExtensionConstVariantPtr p_key_script, GDExtensionVariantType p_value_type, GDExtensionConstStringNamePtr p_value_class_name, GDExtensionConstVariantPtr p_value_script);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* INTERFACE: Object */
 | 
					/* INTERFACE: Object */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -2680,6 +2768,7 @@ typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstT
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_construct_object
 | 
					 * @name classdb_construct_object
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
 | 
					 * @deprecated in Godot 4.4. Use `classdb_construct_object2` instead.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Constructs an Object of the requested class.
 | 
					 * Constructs an Object of the requested class.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -2691,6 +2780,22 @@ typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstT
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject)(GDExtensionConstStringNamePtr p_classname);
 | 
					typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject)(GDExtensionConstStringNamePtr p_classname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @name classdb_construct_object2
 | 
				
			||||||
 | 
					 * @since 4.4
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Constructs an Object of the requested class.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The passed class must be a built-in godot class, or an already-registered extension class. In both cases, object_set_instance() should be called to fully initialize the object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * "NOTIFICATION_POSTINITIALIZE" must be sent after construction.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p_classname A pointer to a StringName with the class name.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return A pointer to the newly created Object.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject2)(GDExtensionConstStringNamePtr p_classname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_get_method_bind
 | 
					 * @name classdb_get_method_bind
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
| 
						 | 
					@ -2722,7 +2827,7 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_register_extension_class
 | 
					 * @name classdb_register_extension_class
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
 * @deprecated in Godot 4.2. Use `classdb_register_extension_class3` instead.
 | 
					 * @deprecated in Godot 4.2. Use `classdb_register_extension_class4` instead.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Registers an extension class in the ClassDB.
 | 
					 * Registers an extension class in the ClassDB.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -2738,7 +2843,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_register_extension_class2
 | 
					 * @name classdb_register_extension_class2
 | 
				
			||||||
 * @since 4.2
 | 
					 * @since 4.2
 | 
				
			||||||
 * @deprecated in Godot 4.3. Use `classdb_register_extension_class3` instead.
 | 
					 * @deprecated in Godot 4.3. Use `classdb_register_extension_class4` instead.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Registers an extension class in the ClassDB.
 | 
					 * Registers an extension class in the ClassDB.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -2754,6 +2859,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_register_extension_class3
 | 
					 * @name classdb_register_extension_class3
 | 
				
			||||||
 * @since 4.3
 | 
					 * @since 4.3
 | 
				
			||||||
 | 
					 * @deprecated in Godot 4.4. Use `classdb_register_extension_class4` instead.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Registers an extension class in the ClassDB.
 | 
					 * Registers an extension class in the ClassDB.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -2766,6 +2872,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
 | 
					typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @name classdb_register_extension_class4
 | 
				
			||||||
 | 
					 * @since 4.4
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Registers an extension class in the ClassDB.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Provided struct can be safely freed once the function returns.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p_library A pointer the library received by the GDExtension's entry point function.
 | 
				
			||||||
 | 
					 * @param p_class_name A pointer to a StringName with the class name.
 | 
				
			||||||
 | 
					 * @param p_parent_class_name A pointer to a StringName with the parent class name.
 | 
				
			||||||
 | 
					 * @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass4)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @name classdb_register_extension_class_method
 | 
					 * @name classdb_register_extension_class_method
 | 
				
			||||||
 * @since 4.1
 | 
					 * @since 4.1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										394
									
								
								engine/core/extension/gdextension_library_loader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								engine/core/extension/gdextension_library_loader.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,394 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_library_loader.cpp                                        */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gdextension_library_loader.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/io/dir_access.h"
 | 
				
			||||||
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					#include "gdextension.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vector<SharedObject> GDExtensionLibraryLoader::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) {
 | 
				
			||||||
 | 
						Vector<SharedObject> dependencies_shared_objects;
 | 
				
			||||||
 | 
						if (p_config->has_section("dependencies")) {
 | 
				
			||||||
 | 
							List<String> config_dependencies;
 | 
				
			||||||
 | 
							p_config->get_section_keys("dependencies", &config_dependencies);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const String &dependency : config_dependencies) {
 | 
				
			||||||
 | 
								Vector<String> dependency_tags = dependency.split(".");
 | 
				
			||||||
 | 
								bool all_tags_met = true;
 | 
				
			||||||
 | 
								for (int i = 0; i < dependency_tags.size(); i++) {
 | 
				
			||||||
 | 
									String tag = dependency_tags[i].strip_edges();
 | 
				
			||||||
 | 
									if (!p_has_feature(tag)) {
 | 
				
			||||||
 | 
										all_tags_met = false;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (all_tags_met) {
 | 
				
			||||||
 | 
									Dictionary dependency_value = p_config->get_value("dependencies", dependency);
 | 
				
			||||||
 | 
									for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) {
 | 
				
			||||||
 | 
										String dependency_path = *key;
 | 
				
			||||||
 | 
										String target_path = dependency_value[*key];
 | 
				
			||||||
 | 
										if (dependency_path.is_relative_path()) {
 | 
				
			||||||
 | 
											dependency_path = p_path.get_base_dir().path_join(dependency_path);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dependencies_shared_objects;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String GDExtensionLibraryLoader::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) {
 | 
				
			||||||
 | 
						// First, check the explicit libraries.
 | 
				
			||||||
 | 
						if (p_config->has_section("libraries")) {
 | 
				
			||||||
 | 
							List<String> libraries;
 | 
				
			||||||
 | 
							p_config->get_section_keys("libraries", &libraries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Iterate the libraries, finding the best matching tags.
 | 
				
			||||||
 | 
							String best_library_path;
 | 
				
			||||||
 | 
							Vector<String> best_library_tags;
 | 
				
			||||||
 | 
							for (const String &E : libraries) {
 | 
				
			||||||
 | 
								Vector<String> tags = E.split(".");
 | 
				
			||||||
 | 
								bool all_tags_met = true;
 | 
				
			||||||
 | 
								for (int i = 0; i < tags.size(); i++) {
 | 
				
			||||||
 | 
									String tag = tags[i].strip_edges();
 | 
				
			||||||
 | 
									if (!p_has_feature(tag)) {
 | 
				
			||||||
 | 
										all_tags_met = false;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (all_tags_met && tags.size() > best_library_tags.size()) {
 | 
				
			||||||
 | 
									best_library_path = p_config->get_value("libraries", E);
 | 
				
			||||||
 | 
									best_library_tags = tags;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!best_library_path.is_empty()) {
 | 
				
			||||||
 | 
								if (best_library_path.is_relative_path()) {
 | 
				
			||||||
 | 
									best_library_path = p_path.get_base_dir().path_join(best_library_path);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (r_tags != nullptr) {
 | 
				
			||||||
 | 
									r_tags->append_array(best_library_tags);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return best_library_path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Second, try to autodetect.
 | 
				
			||||||
 | 
						String autodetect_library_prefix;
 | 
				
			||||||
 | 
						if (p_config->has_section_key("configuration", "autodetect_library_prefix")) {
 | 
				
			||||||
 | 
							autodetect_library_prefix = p_config->get_value("configuration", "autodetect_library_prefix");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!autodetect_library_prefix.is_empty()) {
 | 
				
			||||||
 | 
							String autodetect_path = autodetect_library_prefix;
 | 
				
			||||||
 | 
							if (autodetect_path.is_relative_path()) {
 | 
				
			||||||
 | 
								autodetect_path = p_path.get_base_dir().path_join(autodetect_path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Find the folder and file parts of the prefix.
 | 
				
			||||||
 | 
							String folder;
 | 
				
			||||||
 | 
							String file_prefix;
 | 
				
			||||||
 | 
							if (DirAccess::dir_exists_absolute(autodetect_path)) {
 | 
				
			||||||
 | 
								folder = autodetect_path;
 | 
				
			||||||
 | 
							} else if (DirAccess::dir_exists_absolute(autodetect_path.get_base_dir())) {
 | 
				
			||||||
 | 
								folder = autodetect_path.get_base_dir();
 | 
				
			||||||
 | 
								file_prefix = autodetect_path.get_file();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(String(), vformat("Error in extension: %s. Could not find folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Open the folder.
 | 
				
			||||||
 | 
							Ref<DirAccess> dir = DirAccess::open(folder);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(dir.is_null(), String(), vformat("Error in extension: %s. Could not open folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Iterate the files and check the prefixes, finding the best matching file.
 | 
				
			||||||
 | 
							String best_file;
 | 
				
			||||||
 | 
							Vector<String> best_file_tags;
 | 
				
			||||||
 | 
							dir->list_dir_begin();
 | 
				
			||||||
 | 
							String file_name = dir->_get_next();
 | 
				
			||||||
 | 
							while (file_name != "") {
 | 
				
			||||||
 | 
								if (!dir->current_is_dir() && file_name.begins_with(file_prefix)) {
 | 
				
			||||||
 | 
									// Check if the files matches all requested feature tags.
 | 
				
			||||||
 | 
									String tags_str = file_name.trim_prefix(file_prefix);
 | 
				
			||||||
 | 
									tags_str = tags_str.trim_suffix(tags_str.get_extension());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Vector<String> tags = tags_str.split(".", false);
 | 
				
			||||||
 | 
									bool all_tags_met = true;
 | 
				
			||||||
 | 
									for (int i = 0; i < tags.size(); i++) {
 | 
				
			||||||
 | 
										String tag = tags[i].strip_edges();
 | 
				
			||||||
 | 
										if (!p_has_feature(tag)) {
 | 
				
			||||||
 | 
											all_tags_met = false;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// If all tags are found in the feature list, and we found more tags than before, use this file.
 | 
				
			||||||
 | 
									if (all_tags_met && tags.size() > best_file_tags.size()) {
 | 
				
			||||||
 | 
										best_file_tags = tags;
 | 
				
			||||||
 | 
										best_file = file_name;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								file_name = dir->_get_next();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!best_file.is_empty()) {
 | 
				
			||||||
 | 
								String library_path = folder.path_join(best_file);
 | 
				
			||||||
 | 
								if (r_tags != nullptr) {
 | 
				
			||||||
 | 
									r_tags->append_array(best_file_tags);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return library_path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return String();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error GDExtensionLibraryLoader::open_library(const String &p_path) {
 | 
				
			||||||
 | 
						Error err = parse_gdextension_file(p_path);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<String> abs_dependencies_paths;
 | 
				
			||||||
 | 
						if (!library_dependencies.is_empty()) {
 | 
				
			||||||
 | 
							for (const SharedObject &dependency : library_dependencies) {
 | 
				
			||||||
 | 
								abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OS::GDExtensionData data = {
 | 
				
			||||||
 | 
							true, // also_set_library_path
 | 
				
			||||||
 | 
							&library_path, // r_resolved_path
 | 
				
			||||||
 | 
							Engine::get_singleton()->is_editor_hint(), // generate_temp_files
 | 
				
			||||||
 | 
							&abs_dependencies_paths, // library_dependencies
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = OS::get_singleton()->open_dynamic_library(is_static_library ? String() : abs_path, library, &data);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error GDExtensionLibraryLoader::initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) {
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						p_extension->set_reloadable(is_reloadable && Engine::get_singleton()->is_extension_reloading_enabled());
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, String> &icon : class_icon_paths) {
 | 
				
			||||||
 | 
							p_extension->class_icon_paths[icon.key] = icon.value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *entry_funcptr = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, entry_symbol, entry_funcptr, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension entry point '%s' not found in library %s.", entry_symbol, library_path));
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDExtensionBool ret = initialization_function(p_get_proc_address, p_extension.ptr(), r_initialization);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							return OK;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension initialization function '%s' returned an error.", entry_symbol));
 | 
				
			||||||
 | 
							return FAILED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionLibraryLoader::close_library() {
 | 
				
			||||||
 | 
						OS::get_singleton()->close_dynamic_library(library);
 | 
				
			||||||
 | 
						library = nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionLibraryLoader::is_library_open() const {
 | 
				
			||||||
 | 
						return library != nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionLibraryLoader::has_library_changed() const {
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						// Check only that the last modified time is different (rather than checking
 | 
				
			||||||
 | 
						// that it's newer) since some OS's (namely Windows) will preserve the modified
 | 
				
			||||||
 | 
						// time by default when copying files.
 | 
				
			||||||
 | 
						if (FileAccess::get_modified_time(resource_path) != resource_last_modified_time) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionLibraryLoader::library_exists() const {
 | 
				
			||||||
 | 
						return FileAccess::exists(resource_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
 | 
				
			||||||
 | 
						resource_path = p_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<ConfigFile> config;
 | 
				
			||||||
 | 
						config.instantiate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err = config->load(p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("Error loading GDExtension configuration file: '%s'.", p_path));
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!config->has_section_key("configuration", "entry_symbol")) {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: '%s'.", p_path));
 | 
				
			||||||
 | 
							return ERR_INVALID_DATA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						entry_symbol = config->get_value("configuration", "entry_symbol");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t compatibility_minimum[3] = { 0, 0, 0 };
 | 
				
			||||||
 | 
						if (config->has_section_key("configuration", "compatibility_minimum")) {
 | 
				
			||||||
 | 
							String compat_string = config->get_value("configuration", "compatibility_minimum");
 | 
				
			||||||
 | 
							Vector<int> parts = compat_string.split_ints(".");
 | 
				
			||||||
 | 
							for (int i = 0; i < parts.size(); i++) {
 | 
				
			||||||
 | 
								if (i >= 3) {
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (parts[i] >= 0) {
 | 
				
			||||||
 | 
									compatibility_minimum[i] = parts[i];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: '%s'.", p_path));
 | 
				
			||||||
 | 
							return ERR_INVALID_DATA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
 | 
				
			||||||
 | 
							return ERR_INVALID_DATA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool compatible = true;
 | 
				
			||||||
 | 
						// Check version lexicographically.
 | 
				
			||||||
 | 
						if (VERSION_MAJOR != compatibility_minimum[0]) {
 | 
				
			||||||
 | 
							compatible = VERSION_MAJOR > compatibility_minimum[0];
 | 
				
			||||||
 | 
						} else if (VERSION_MINOR != compatibility_minimum[1]) {
 | 
				
			||||||
 | 
							compatible = VERSION_MINOR > compatibility_minimum[1];
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							compatible = VERSION_PATCH >= compatibility_minimum[2];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!compatible) {
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
 | 
				
			||||||
 | 
							return ERR_INVALID_DATA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Optionally check maximum compatibility.
 | 
				
			||||||
 | 
						if (config->has_section_key("configuration", "compatibility_maximum")) {
 | 
				
			||||||
 | 
							uint32_t compatibility_maximum[3] = { 0, 0, 0 };
 | 
				
			||||||
 | 
							String compat_string = config->get_value("configuration", "compatibility_maximum");
 | 
				
			||||||
 | 
							Vector<int> parts = compat_string.split_ints(".");
 | 
				
			||||||
 | 
							for (int i = 0; i < 3; i++) {
 | 
				
			||||||
 | 
								if (i < parts.size() && parts[i] >= 0) {
 | 
				
			||||||
 | 
									compatibility_maximum[i] = parts[i];
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									// If a version part is missing, set the maximum to an arbitrary high value.
 | 
				
			||||||
 | 
									compatibility_maximum[i] = 9999;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							compatible = true;
 | 
				
			||||||
 | 
							if (VERSION_MAJOR != compatibility_maximum[0]) {
 | 
				
			||||||
 | 
								compatible = VERSION_MAJOR < compatibility_maximum[0];
 | 
				
			||||||
 | 
							} else if (VERSION_MINOR != compatibility_maximum[1]) {
 | 
				
			||||||
 | 
								compatible = VERSION_MINOR < compatibility_maximum[1];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#if VERSION_PATCH
 | 
				
			||||||
 | 
							// #if check to avoid -Wtype-limits warning when 0.
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								compatible = VERSION_PATCH <= compatibility_maximum[2];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!compatible) {
 | 
				
			||||||
 | 
								ERR_PRINT(vformat("GDExtension only compatible with Godot version %s or earlier: %s", compat_string, p_path));
 | 
				
			||||||
 | 
								return ERR_INVALID_DATA;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						library_path = find_extension_library(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (library_path.is_empty()) {
 | 
				
			||||||
 | 
							const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
 | 
				
			||||||
 | 
							ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
 | 
				
			||||||
 | 
							return ERR_FILE_NOT_FOUND;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
 | 
				
			||||||
 | 
							library_path = p_path.get_base_dir().path_join(library_path);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						is_reloadable = config->get_value("configuration", "reloadable", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update_last_modified_time(
 | 
				
			||||||
 | 
								FileAccess::get_modified_time(resource_path),
 | 
				
			||||||
 | 
								FileAccess::get_modified_time(library_path));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						library_dependencies = find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Handle icons if any are specified.
 | 
				
			||||||
 | 
						if (config->has_section("icons")) {
 | 
				
			||||||
 | 
							List<String> keys;
 | 
				
			||||||
 | 
							config->get_section_keys("icons", &keys);
 | 
				
			||||||
 | 
							for (const String &key : keys) {
 | 
				
			||||||
 | 
								String icon_path = config->get_value("icons", key);
 | 
				
			||||||
 | 
								if (icon_path.is_relative_path()) {
 | 
				
			||||||
 | 
									icon_path = p_path.get_base_dir().path_join(icon_path);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								class_icon_paths[key] = icon_path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										85
									
								
								engine/core/extension/gdextension_library_loader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								engine/core/extension/gdextension_library_loader.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_library_loader.h                                          */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_LIBRARY_LOADER_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_LIBRARY_LOADER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/extension/gdextension_loader.h"
 | 
				
			||||||
 | 
					#include "core/io/config_file.h"
 | 
				
			||||||
 | 
					#include "core/os/shared_object.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionLibraryLoader : public GDExtensionLoader {
 | 
				
			||||||
 | 
						friend class GDExtensionManager;
 | 
				
			||||||
 | 
						friend class GDExtension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						String resource_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *library = nullptr; // pointer if valid.
 | 
				
			||||||
 | 
						String library_path;
 | 
				
			||||||
 | 
						String entry_symbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_static_library = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						bool is_reloadable = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<SharedObject> library_dependencies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<String, String> class_icon_paths;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						uint64_t resource_last_modified_time = 0;
 | 
				
			||||||
 | 
						uint64_t library_last_modified_time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void update_last_modified_time(uint64_t p_resource_last_modified_time, uint64_t p_library_last_modified_time) {
 | 
				
			||||||
 | 
							resource_last_modified_time = p_resource_last_modified_time;
 | 
				
			||||||
 | 
							library_last_modified_time = p_library_last_modified_time;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
 | 
				
			||||||
 | 
						static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Error open_library(const String &p_path) override;
 | 
				
			||||||
 | 
						virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) override;
 | 
				
			||||||
 | 
						virtual void close_library() override;
 | 
				
			||||||
 | 
						virtual bool is_library_open() const override;
 | 
				
			||||||
 | 
						virtual bool has_library_changed() const override;
 | 
				
			||||||
 | 
						virtual bool library_exists() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error parse_gdextension_file(const String &p_path);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_LIBRARY_LOADER_H
 | 
				
			||||||
							
								
								
									
										48
									
								
								engine/core/extension/gdextension_loader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								engine/core/extension/gdextension_loader.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_loader.h                                                  */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_LOADER_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_LOADER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionLoader : public RefCounted {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual Error open_library(const String &p_path) = 0;
 | 
				
			||||||
 | 
						virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) = 0;
 | 
				
			||||||
 | 
						virtual void close_library() = 0;
 | 
				
			||||||
 | 
						virtual bool is_library_open() const = 0;
 | 
				
			||||||
 | 
						virtual bool has_library_changed() const = 0;
 | 
				
			||||||
 | 
						virtual bool library_exists() const = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_LOADER_H
 | 
				
			||||||
| 
						 | 
					@ -30,15 +30,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gdextension_manager.h"
 | 
					#include "gdextension_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/extension/gdextension_compat_hashes.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/io/file_access.h"
 | 
				
			||||||
#include "core/object/script_language.h"
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension) {
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load) {
 | 
				
			||||||
	if (level >= 0) { // Already initialized up to some level.
 | 
						if (level >= 0) { // Already initialized up to some level.
 | 
				
			||||||
		int32_t minimum_level = p_extension->get_minimum_library_initialization_level();
 | 
							int32_t minimum_level = 0;
 | 
				
			||||||
		if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
 | 
							if (!p_first_load) {
 | 
				
			||||||
			return LOAD_STATUS_NEEDS_RESTART;
 | 
								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.
 | 
							// Initialize up to current level.
 | 
				
			||||||
		for (int32_t i = minimum_level; i <= level; i++) {
 | 
							for (int32_t i = minimum_level; i <= level; i++) {
 | 
				
			||||||
| 
						 | 
					@ -50,10 +55,20 @@ GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(cons
 | 
				
			||||||
		gdextension_class_icon_paths[kv.key] = kv.value;
 | 
							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;
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(const Ref<GDExtension> &p_extension) {
 | 
					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.
 | 
						if (level >= 0) { // Already initialized up to some level.
 | 
				
			||||||
		// Deinitialize down from current level.
 | 
							// Deinitialize down from current level.
 | 
				
			||||||
		for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
 | 
							for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
 | 
				
			||||||
| 
						 | 
					@ -69,19 +84,35 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
 | 
				
			||||||
	if (gdextension_map.has(p_path)) {
 | 
						if (Engine::get_singleton()->is_recovery_mode_hint()) {
 | 
				
			||||||
		return LOAD_STATUS_ALREADY_LOADED;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	Ref<GDExtension> extension = ResourceLoader::load(p_path);
 | 
					 | 
				
			||||||
	if (extension.is_null()) {
 | 
					 | 
				
			||||||
		return LOAD_STATUS_FAILED;
 | 
							return LOAD_STATUS_FAILED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LoadStatus status = _load_extension_internal(extension);
 | 
						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) {
 | 
						if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						extension->set_path(p_path);
 | 
				
			||||||
	gdextension_map[p_path] = extension;
 | 
						gdextension_map[p_path] = extension;
 | 
				
			||||||
	return LOAD_STATUS_OK;
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -92,6 +123,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled.");
 | 
						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)) {
 | 
						if (!gdextension_map.has(p_path)) {
 | 
				
			||||||
		return LOAD_STATUS_NOT_LOADED;
 | 
							return LOAD_STATUS_NOT_LOADED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -117,12 +152,12 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String
 | 
				
			||||||
		extension->close_library();
 | 
							extension->close_library();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = GDExtensionResourceLoader::load_gdextension_resource(p_path, extension);
 | 
						Error err = extension->open_library(p_path, extension->loader);
 | 
				
			||||||
	if (err != OK) {
 | 
						if (err != OK) {
 | 
				
			||||||
		return LOAD_STATUS_FAILED;
 | 
							return LOAD_STATUS_FAILED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = _load_extension_internal(extension);
 | 
						status = _load_extension_internal(extension, false);
 | 
				
			||||||
	if (status != LOAD_STATUS_OK) {
 | 
						if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -134,6 +169,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
 | 
					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)) {
 | 
						if (!gdextension_map.has(p_path)) {
 | 
				
			||||||
		return LOAD_STATUS_NOT_LOADED;
 | 
							return LOAD_STATUS_NOT_LOADED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -180,14 +219,28 @@ String GDExtensionManager::class_get_icon_path(const String &p_class) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
 | 
					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);
 | 
						ERR_FAIL_COND(int32_t(p_level) - 1 != level);
 | 
				
			||||||
	for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
		E.value->initialize_library(p_level);
 | 
							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;
 | 
						level = p_level;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel 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);
 | 
						ERR_FAIL_COND(int32_t(p_level) != level);
 | 
				
			||||||
	for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
		E.value->deinitialize_library(p_level);
 | 
							E.value->deinitialize_library(p_level);
 | 
				
			||||||
| 
						 | 
					@ -226,12 +279,16 @@ void GDExtensionManager::_reload_all_scripts() {
 | 
				
			||||||
#endif // TOOLS_ENABLED
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionManager::load_extensions() {
 | 
					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);
 | 
						Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
 | 
				
			||||||
	while (f.is_valid() && !f->eof_reached()) {
 | 
						while (f.is_valid() && !f->eof_reached()) {
 | 
				
			||||||
		String s = f->get_line().strip_edges();
 | 
							String s = f->get_line().strip_edges();
 | 
				
			||||||
		if (!s.is_empty()) {
 | 
							if (!s.is_empty()) {
 | 
				
			||||||
			LoadStatus err = load_extension(s);
 | 
								LoadStatus err = load_extension(s);
 | 
				
			||||||
			ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, "Error loading extension: " + s);
 | 
								ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, vformat("Error loading extension: '%s'.", s));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,6 +297,9 @@ void GDExtensionManager::load_extensions() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionManager::reload_extensions() {
 | 
					void GDExtensionManager::reload_extensions() {
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						if (Engine::get_singleton()->is_recovery_mode_hint()) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	bool reloaded = false;
 | 
						bool reloaded = false;
 | 
				
			||||||
	for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
						for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
		if (!E.value->is_reloadable()) {
 | 
							if (!E.value->is_reloadable()) {
 | 
				
			||||||
| 
						 | 
					@ -261,6 +321,72 @@ void GDExtensionManager::reload_extensions() {
 | 
				
			||||||
#endif
 | 
					#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() {
 | 
					GDExtensionManager *GDExtensionManager::get_singleton() {
 | 
				
			||||||
	return singleton;
 | 
						return singleton;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -281,6 +407,8 @@ void GDExtensionManager::_bind_methods() {
 | 
				
			||||||
	BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ADD_SIGNAL(MethodInfo("extensions_reloaded"));
 | 
						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::singleton = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -290,7 +418,7 @@ GDExtensionManager::GDExtensionManager() {
 | 
				
			||||||
	singleton = this;
 | 
						singleton = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
	GDExtensionCompatHashes::initialize();
 | 
						GDExtensionSpecialCompatHashes::initialize();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -299,6 +427,6 @@ GDExtensionManager::~GDExtensionManager() {
 | 
				
			||||||
		singleton = nullptr;
 | 
							singleton = nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
	GDExtensionCompatHashes::finalize();
 | 
						GDExtensionSpecialCompatHashes::finalize();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ public:
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	LoadStatus _load_extension_internal(const Ref<GDExtension> &p_extension);
 | 
						LoadStatus _load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load);
 | 
				
			||||||
	LoadStatus _unload_extension_internal(const Ref<GDExtension> &p_extension);
 | 
						LoadStatus _unload_extension_internal(const Ref<GDExtension> &p_extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TOOLS_ENABLED
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -63,6 +63,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	LoadStatus load_extension(const String &p_path);
 | 
						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 reload_extension(const String &p_path);
 | 
				
			||||||
	LoadStatus unload_extension(const String &p_path);
 | 
						LoadStatus unload_extension(const String &p_path);
 | 
				
			||||||
	bool is_extension_loaded(const String &p_path) const;
 | 
						bool is_extension_loaded(const String &p_path) const;
 | 
				
			||||||
| 
						 | 
					@ -84,6 +85,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void load_extensions();
 | 
						void load_extensions();
 | 
				
			||||||
	void reload_extensions();
 | 
						void reload_extensions();
 | 
				
			||||||
 | 
						bool ensure_extensions_loaded(const HashSet<String> &p_extensions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GDExtensionManager();
 | 
						GDExtensionManager();
 | 
				
			||||||
	~GDExtensionManager();
 | 
						~GDExtensionManager();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
/*  gdextension_compat_hashes.cpp                                         */
 | 
					/*  gdextension_special_compat_hashes.cpp                                 */
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
/*                         This file is part of:                          */
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
/*                             GODOT ENGINE                               */
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
| 
						 | 
					@ -28,16 +28,16 @@
 | 
				
			||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gdextension_compat_hashes.h"
 | 
					#include "gdextension_special_compat_hashes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/object/class_db.h"
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
#include "core/variant/variant.h"
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HashMap<StringName, LocalVector<GDExtensionCompatHashes::Mapping>> GDExtensionCompatHashes::mappings;
 | 
					HashMap<StringName, LocalVector<GDExtensionSpecialCompatHashes::Mapping>> GDExtensionSpecialCompatHashes::mappings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool GDExtensionCompatHashes::lookup_current_hash(const StringName &p_class, const StringName &p_method, uint32_t p_legacy_hash, uint32_t *r_current_hash) {
 | 
					bool GDExtensionSpecialCompatHashes::lookup_current_hash(const StringName &p_class, const StringName &p_method, uint32_t p_legacy_hash, uint32_t *r_current_hash) {
 | 
				
			||||||
	LocalVector<Mapping> *methods = mappings.getptr(p_class);
 | 
						LocalVector<Mapping> *methods = mappings.getptr(p_class);
 | 
				
			||||||
	if (!methods) {
 | 
						if (!methods) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ bool GDExtensionCompatHashes::lookup_current_hash(const StringName &p_class, con
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool GDExtensionCompatHashes::get_legacy_hashes(const StringName &p_class, const StringName &p_method, Array &r_hashes, bool p_check_valid) {
 | 
					bool GDExtensionSpecialCompatHashes::get_legacy_hashes(const StringName &p_class, const StringName &p_method, Array &r_hashes, bool p_check_valid) {
 | 
				
			||||||
	LocalVector<Mapping> *methods = mappings.getptr(p_class);
 | 
						LocalVector<Mapping> *methods = mappings.getptr(p_class);
 | 
				
			||||||
	if (!methods) {
 | 
						if (!methods) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,7 @@ bool GDExtensionCompatHashes::get_legacy_hashes(const StringName &p_class, const
 | 
				
			||||||
			if (p_check_valid) {
 | 
								if (p_check_valid) {
 | 
				
			||||||
				MethodBind *mb = ClassDB::get_method_with_compatibility(p_class, p_method, mapping.current_hash);
 | 
									MethodBind *mb = ClassDB::get_method_with_compatibility(p_class, p_method, mapping.current_hash);
 | 
				
			||||||
				if (!mb) {
 | 
									if (!mb) {
 | 
				
			||||||
					WARN_PRINT(vformat("Compatibility hash %d for %s::%s() mapped to non-existent hash %d. Please update gdextension_compat_hashes.cpp.", mapping.legacy_hash, p_class, p_method, mapping.current_hash));
 | 
										WARN_PRINT(vformat("Compatibility hash %d for %s::%s() mapped to non-existent hash %d. Please update gdextension_special_compat_hashes.cpp.", mapping.legacy_hash, p_class, p_method, mapping.current_hash));
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ bool GDExtensionCompatHashes::get_legacy_hashes(const StringName &p_class, const
 | 
				
			||||||
	return found;
 | 
						return found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionCompatHashes::initialize() {
 | 
					void GDExtensionSpecialCompatHashes::initialize() {
 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
	mappings.insert("AESContext", {
 | 
						mappings.insert("AESContext", {
 | 
				
			||||||
		{ "start", 3167574919, 3122411423 },
 | 
							{ "start", 3167574919, 3122411423 },
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,14 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
	mappings.insert("AcceptDialog", {
 | 
						mappings.insert("AcceptDialog", {
 | 
				
			||||||
		{ "add_button", 4158837846, 3328440682 },
 | 
							{ "add_button", 4158837846, 3328440682 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimatedSprite2D", {
 | 
				
			||||||
 | 
							{ "play", 2372066587, 3269405555 },
 | 
				
			||||||
 | 
							{ "play_backwards", 1421762485, 3323268493 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimatedSprite3D", {
 | 
				
			||||||
 | 
							{ "play", 2372066587, 3269405555 },
 | 
				
			||||||
 | 
							{ "play_backwards", 1421762485, 3323268493 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("Animation", {
 | 
						mappings.insert("Animation", {
 | 
				
			||||||
		{ "add_track", 2393815928, 3843682357 },
 | 
							{ "add_track", 2393815928, 3843682357 },
 | 
				
			||||||
		{ "track_insert_key", 1985425300, 808952278 },
 | 
							{ "track_insert_key", 1985425300, 808952278 },
 | 
				
			||||||
| 
						 | 
					@ -146,6 +154,12 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
		{ "travel", 3683006648, 3823612587 },
 | 
							{ "travel", 3683006648, 3823612587 },
 | 
				
			||||||
		{ "start", 3683006648, 3823612587 },
 | 
							{ "start", 3683006648, 3823612587 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationPlayer", {
 | 
				
			||||||
 | 
							{ "play", 3697947785, 3118260607 },
 | 
				
			||||||
 | 
							{ "play", 2221377757, 3118260607 },
 | 
				
			||||||
 | 
							{ "play_backwards", 3890664824, 2787282401 },
 | 
				
			||||||
 | 
							{ "play_with_capture", 3180464118, 1572969103 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("ArrayMesh", {
 | 
						mappings.insert("ArrayMesh", {
 | 
				
			||||||
		{ "add_surface_from_arrays", 172284304, 1796411378 },
 | 
							{ "add_surface_from_arrays", 172284304, 1796411378 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
| 
						 | 
					@ -241,22 +255,31 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	mappings.insert("DirAccess", {
 | 
						mappings.insert("DirAccess", {
 | 
				
			||||||
		{ "list_dir_begin", 2018049411, 2610976713 },
 | 
							{ "list_dir_begin", 2018049411, 166280745 },
 | 
				
			||||||
 | 
							{ "list_dir_begin", 2610976713, 166280745 },
 | 
				
			||||||
		{ "copy", 198434953, 1063198817 },
 | 
							{ "copy", 198434953, 1063198817 },
 | 
				
			||||||
		{ "copy_absolute", 198434953, 1063198817 },
 | 
							{ "copy_absolute", 198434953, 1063198817 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	mappings.insert("DisplayServer", {
 | 
						mappings.insert("DisplayServer", {
 | 
				
			||||||
		{ "global_menu_add_submenu_item", 3806306913, 2828985934 },
 | 
							{ "global_menu_add_submenu_item", 3806306913, 2828985934 },
 | 
				
			||||||
		{ "global_menu_add_item", 3415468211, 3401266716 },
 | 
							{ "global_menu_add_item", 3415468211, 3616842746 },
 | 
				
			||||||
		{ "global_menu_add_check_item", 3415468211, 3401266716 },
 | 
							{ "global_menu_add_item", 3401266716, 3616842746 },
 | 
				
			||||||
		{ "global_menu_add_icon_item", 1700867534, 4245856523 },
 | 
							{ "global_menu_add_check_item", 3415468211, 3616842746 },
 | 
				
			||||||
		{ "global_menu_add_icon_check_item", 1700867534, 4245856523 },
 | 
							{ "global_menu_add_check_item", 3401266716, 3616842746 },
 | 
				
			||||||
		{ "global_menu_add_radio_check_item", 3415468211, 3401266716 },
 | 
							{ "global_menu_add_icon_item", 1700867534, 3867083847 },
 | 
				
			||||||
		{ "global_menu_add_icon_radio_check_item", 1700867534, 4245856523 },
 | 
							{ "global_menu_add_icon_item", 4245856523, 3867083847 },
 | 
				
			||||||
		{ "global_menu_add_multistate_item", 635750054, 3431222859 },
 | 
							{ "global_menu_add_icon_check_item", 1700867534, 3867083847 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_check_item", 4245856523, 3867083847 },
 | 
				
			||||||
 | 
							{ "global_menu_add_radio_check_item", 3415468211, 3616842746 },
 | 
				
			||||||
 | 
							{ "global_menu_add_radio_check_item", 3401266716, 3616842746 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_radio_check_item", 1700867534, 3867083847 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_radio_check_item", 4245856523, 3867083847 },
 | 
				
			||||||
 | 
							{ "global_menu_add_multistate_item", 635750054, 3297554655 },
 | 
				
			||||||
 | 
							{ "global_menu_add_multistate_item", 3431222859, 3297554655 },
 | 
				
			||||||
		{ "global_menu_add_separator", 1041533178, 3214812433 },
 | 
							{ "global_menu_add_separator", 1041533178, 3214812433 },
 | 
				
			||||||
		{ "tts_speak", 3741216677, 903992738 },
 | 
							{ "tts_speak", 3741216677, 903992738 },
 | 
				
			||||||
		{ "is_touchscreen_available", 4162880507, 3323674545 },
 | 
							{ "is_touchscreen_available", 4162880507, 36873697 },
 | 
				
			||||||
 | 
							{ "is_touchscreen_available", 3323674545, 36873697 },
 | 
				
			||||||
		{ "screen_set_orientation", 2629526904, 2211511631 },
 | 
							{ "screen_set_orientation", 2629526904, 2211511631 },
 | 
				
			||||||
		{ "window_get_native_handle", 2709193271, 1096425680 },
 | 
							{ "window_get_native_handle", 2709193271, 1096425680 },
 | 
				
			||||||
		{ "window_set_title", 3043792800, 441246282 },
 | 
							{ "window_set_title", 3043792800, 441246282 },
 | 
				
			||||||
| 
						 | 
					@ -286,6 +309,12 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
		{ "virtual_keyboard_show", 860410478, 3042891259 },
 | 
							{ "virtual_keyboard_show", 860410478, 3042891259 },
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorExportPlatform", {
 | 
				
			||||||
 | 
							{ "export_project_files", 425454869, 1063735070 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorProperty", {
 | 
				
			||||||
 | 
							{ "emit_changed", 3069422438, 1822500399 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("ENetConnection", {
 | 
						mappings.insert("ENetConnection", {
 | 
				
			||||||
		{ "create_host_bound", 866250949, 1515002313 },
 | 
							{ "create_host_bound", 866250949, 1515002313 },
 | 
				
			||||||
		{ "connect_to_host", 385984708, 2171300490 },
 | 
							{ "connect_to_host", 385984708, 2171300490 },
 | 
				
			||||||
| 
						 | 
					@ -453,18 +482,35 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
	mappings.insert("MultiplayerAPI", {
 | 
						mappings.insert("MultiplayerAPI", {
 | 
				
			||||||
		{ "rpc", 1833408346, 2077486355 },
 | 
							{ "rpc", 1833408346, 2077486355 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("NativeMenu", {
 | 
				
			||||||
 | 
							{ "add_item", 2553375659, 980552939 },
 | 
				
			||||||
 | 
							{ "add_check_item", 2553375659, 980552939 },
 | 
				
			||||||
 | 
							{ "add_icon_item", 2987595282, 1372188274 },
 | 
				
			||||||
 | 
							{ "add_icon_check_item", 2987595282, 1372188274 },
 | 
				
			||||||
 | 
							{ "add_radio_check_item", 2553375659, 980552939 },
 | 
				
			||||||
 | 
							{ "add_icon_radio_check_item", 2987595282, 1372188274 },
 | 
				
			||||||
 | 
							{ "add_multistate_item", 1558592568, 2674635658 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("NavigationMeshGenerator", {
 | 
						mappings.insert("NavigationMeshGenerator", {
 | 
				
			||||||
		{ "parse_source_geometry_data", 3703028813, 685862123 },
 | 
							{ "parse_source_geometry_data", 3703028813, 3172802542 },
 | 
				
			||||||
		{ "bake_from_source_geometry_data", 3669016597, 2469318639 },
 | 
							{ "parse_source_geometry_data", 685862123, 3172802542 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 3669016597, 1286748856 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 2469318639, 1286748856 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	mappings.insert("NavigationServer2D", {
 | 
						mappings.insert("NavigationServer2D", {
 | 
				
			||||||
		{ "map_get_path", 56240621, 3146466012 },
 | 
							{ "map_get_path", 56240621, 3146466012 },
 | 
				
			||||||
 | 
							{ "parse_source_geometry_data", 1176164995, 1766905497 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 2909414286, 2179660022 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data_async", 2909414286, 2179660022 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	mappings.insert("NavigationServer3D", {
 | 
						mappings.insert("NavigationServer3D", {
 | 
				
			||||||
		{ "map_get_path", 2121045993, 1187418690 },
 | 
							{ "map_get_path", 2121045993, 1187418690 },
 | 
				
			||||||
		{ "parse_source_geometry_data", 3703028813, 685862123 },
 | 
							{ "parse_source_geometry_data", 3703028813, 3172802542 },
 | 
				
			||||||
		{ "bake_from_source_geometry_data", 3669016597, 2469318639 },
 | 
							{ "parse_source_geometry_data", 685862123, 3172802542 },
 | 
				
			||||||
		{ "bake_from_source_geometry_data_async", 3669016597, 2469318639 },
 | 
							{ "bake_from_source_geometry_data", 3669016597, 1286748856 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 2469318639, 1286748856 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data_async", 3669016597, 1286748856 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data_async", 2469318639, 1286748856 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	mappings.insert("Node", {
 | 
						mappings.insert("Node", {
 | 
				
			||||||
		{ "add_child", 3070154285, 3863233950 },
 | 
							{ "add_child", 3070154285, 3863233950 },
 | 
				
			||||||
| 
						 | 
					@ -504,6 +550,9 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
		{ "tr", 2475554935, 1195764410 },
 | 
							{ "tr", 2475554935, 1195764410 },
 | 
				
			||||||
		{ "tr_n", 4021311862, 162698058 },
 | 
							{ "tr_n", 4021311862, 162698058 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("OpenXRAPIExtension", {
 | 
				
			||||||
 | 
							{ "transform_from_pose", 3255299855, 2963875352 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("OptionButton", {
 | 
						mappings.insert("OptionButton", {
 | 
				
			||||||
		{ "add_item", 3043792800, 2697778442 },
 | 
							{ "add_item", 3043792800, 2697778442 },
 | 
				
			||||||
		{ "add_icon_item", 3944051090, 3781678508 },
 | 
							{ "add_icon_item", 3944051090, 3781678508 },
 | 
				
			||||||
| 
						 | 
					@ -631,6 +680,11 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
	mappings.insert("ProjectSettings", {
 | 
						mappings.insert("ProjectSettings", {
 | 
				
			||||||
		{ "load_resource_pack", 3001721055, 708980503 },
 | 
							{ "load_resource_pack", 3001721055, 708980503 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RDShaderFile", {
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data_async", 2469318639, 1286748856 },
 | 
				
			||||||
 | 
							{ "set_bytecode", 1558064255, 1526857008 },
 | 
				
			||||||
 | 
							{ "get_spirv", 3340165340, 2689310080 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("RegEx", {
 | 
						mappings.insert("RegEx", {
 | 
				
			||||||
		{ "search", 4087180739, 3365977994 },
 | 
							{ "search", 4087180739, 3365977994 },
 | 
				
			||||||
		{ "search_all", 3354100289, 849021363 },
 | 
							{ "search_all", 3354100289, 849021363 },
 | 
				
			||||||
| 
						 | 
					@ -722,7 +776,7 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
		{ "push_paragraph", 3218895358, 3089306873 },
 | 
							{ "push_paragraph", 3218895358, 3089306873 },
 | 
				
			||||||
		{ "push_list", 4036303897, 3017143144 },
 | 
							{ "push_list", 4036303897, 3017143144 },
 | 
				
			||||||
		{ "push_table", 1125058220, 2623499273 },
 | 
							{ "push_table", 1125058220, 2623499273 },
 | 
				
			||||||
		{ "set_table_column_expand", 4132157579, 2185176273 },
 | 
							{ "set_table_column_expand", 4258957458, 2185176273 },
 | 
				
			||||||
#ifdef REAL_T_IS_DOUBLE
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
		{ "add_image", 3346058748, 1507062345 },
 | 
							{ "add_image", 3346058748, 1507062345 },
 | 
				
			||||||
		{ "push_dropcap", 981432822, 763534173 },
 | 
							{ "push_dropcap", 981432822, 763534173 },
 | 
				
			||||||
| 
						 | 
					@ -863,6 +917,9 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
		{ "set_cells_terrain_path", 3072115677, 3578627656 },
 | 
							{ "set_cells_terrain_path", 3072115677, 3578627656 },
 | 
				
			||||||
		{ "get_used_cells_by_id", 4152068407, 2931012785 },
 | 
							{ "get_used_cells_by_id", 4152068407, 2931012785 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileMapLayer", {
 | 
				
			||||||
 | 
							{ "notify_runtime_tile_data_update", 2275361663, 3218959716 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
	mappings.insert("TileMapPattern", {
 | 
						mappings.insert("TileMapPattern", {
 | 
				
			||||||
		{ "set_cell", 634000503, 2224802556 },
 | 
							{ "set_cell", 634000503, 2224802556 },
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
| 
						 | 
					@ -964,7 +1021,7 @@ void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
	// clang-format on
 | 
						// clang-format on
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GDExtensionCompatHashes::finalize() {
 | 
					void GDExtensionSpecialCompatHashes::finalize() {
 | 
				
			||||||
	mappings.clear();
 | 
						mappings.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
/*  gdextension_compat_hashes.h                                           */
 | 
					/*  gdextension_special_compat_hashes.h                                   */
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
/*                         This file is part of:                          */
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
/*                             GODOT ENGINE                               */
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
| 
						 | 
					@ -28,8 +28,8 @@
 | 
				
			||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef GDEXTENSION_COMPAT_HASHES_H
 | 
					#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H
 | 
				
			||||||
#define GDEXTENSION_COMPAT_HASHES_H
 | 
					#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef DISABLE_DEPRECATED
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,11 @@
 | 
				
			||||||
#include "core/templates/hash_map.h"
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
#include "core/templates/local_vector.h"
 | 
					#include "core/templates/local_vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GDExtensionCompatHashes {
 | 
					// 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 {
 | 
						struct Mapping {
 | 
				
			||||||
		StringName method;
 | 
							StringName method;
 | 
				
			||||||
		uint32_t legacy_hash;
 | 
							uint32_t legacy_hash;
 | 
				
			||||||
| 
						 | 
					@ -55,4 +59,4 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // DISABLE_DEPRECATED
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // GDEXTENSION_COMPAT_HASHES_H
 | 
					#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H
 | 
				
			||||||
| 
						 | 
					@ -55,10 +55,10 @@ def generate_mod_version(argcount, const=False, returns=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proto_ex = """
 | 
					proto_ex = """
 | 
				
			||||||
#define EXBIND$VER($RETTYPE m_name$ARG) \\
 | 
					#define EXBIND$VER($RETTYPE m_name$ARG) \\
 | 
				
			||||||
GDVIRTUAL$VER($RETTYPE_##m_name$ARG)\\
 | 
					GDVIRTUAL$VER_REQUIRED($RETTYPE_##m_name$ARG)\\
 | 
				
			||||||
virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
 | 
					virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
 | 
				
			||||||
    $RETPRE\\
 | 
					    $RETPRE\\
 | 
				
			||||||
    GDVIRTUAL_REQUIRED_CALL(_##m_name$CALLARGS$RETREF);\\
 | 
					    GDVIRTUAL_CALL(_##m_name$CALLARGS$RETREF);\\
 | 
				
			||||||
    $RETPOST\\
 | 
					    $RETPOST\\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -8,7 +8,7 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back
 | 
				
			||||||
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,
 | 
					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
 | 
					# Web
 | 
				
			||||||
standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,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,
 | 
					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,
 | 
					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,
 | 
					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,
 | 
					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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,10 @@ Input *Input::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
 | 
					void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
 | 
				
			||||||
Input::MouseMode (*Input::get_mouse_mode_func)() = nullptr;
 | 
					Input::MouseMode (*Input::get_mouse_mode_func)() = nullptr;
 | 
				
			||||||
 | 
					void (*Input::set_mouse_mode_override_func)(Input::MouseMode) = nullptr;
 | 
				
			||||||
 | 
					Input::MouseMode (*Input::get_mouse_mode_override_func)() = nullptr;
 | 
				
			||||||
 | 
					void (*Input::set_mouse_mode_override_enabled_func)(bool) = nullptr;
 | 
				
			||||||
 | 
					bool (*Input::is_mouse_mode_override_enabled_func)() = nullptr;
 | 
				
			||||||
void (*Input::warp_mouse_func)(const Vector2 &p_position) = nullptr;
 | 
					void (*Input::warp_mouse_func)(const Vector2 &p_position) = nullptr;
 | 
				
			||||||
Input::CursorShape (*Input::get_current_cursor_shape_func)() = nullptr;
 | 
					Input::CursorShape (*Input::get_current_cursor_shape_func)() = nullptr;
 | 
				
			||||||
void (*Input::set_custom_mouse_cursor_func)(const Ref<Resource> &, Input::CursorShape, const Vector2 &) = nullptr;
 | 
					void (*Input::set_custom_mouse_cursor_func)(const Ref<Resource> &, Input::CursorShape, const Vector2 &) = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -86,7 +90,7 @@ Input *Input::get_singleton() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Input::set_mouse_mode(MouseMode p_mode) {
 | 
					void Input::set_mouse_mode(MouseMode p_mode) {
 | 
				
			||||||
	ERR_FAIL_INDEX((int)p_mode, 5);
 | 
						ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
 | 
				
			||||||
	set_mouse_mode_func(p_mode);
 | 
						set_mouse_mode_func(p_mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +98,23 @@ Input::MouseMode Input::get_mouse_mode() const {
 | 
				
			||||||
	return get_mouse_mode_func();
 | 
						return get_mouse_mode_func();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::set_mouse_mode_override(MouseMode p_mode) {
 | 
				
			||||||
 | 
						ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
 | 
				
			||||||
 | 
						set_mouse_mode_override_func(p_mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Input::MouseMode Input::get_mouse_mode_override() const {
 | 
				
			||||||
 | 
						return get_mouse_mode_override_func();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::set_mouse_mode_override_enabled(bool p_override_enabled) {
 | 
				
			||||||
 | 
						set_mouse_mode_override_enabled_func(p_override_enabled);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Input::is_mouse_mode_override_enabled() {
 | 
				
			||||||
 | 
						return is_mouse_mode_override_enabled_func();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Input::_bind_methods() {
 | 
					void Input::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
 | 
						ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
 | 
						ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
 | 
				
			||||||
| 
						 | 
					@ -160,6 +181,7 @@ void Input::_bind_methods() {
 | 
				
			||||||
	BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
 | 
						BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
 | 
						BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
 | 
						BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MOUSE_MODE_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIND_ENUM_CONSTANT(CURSOR_ARROW);
 | 
						BIND_ENUM_CONSTANT(CURSOR_ARROW);
 | 
				
			||||||
	BIND_ENUM_CONSTANT(CURSOR_IBEAM);
 | 
						BIND_ENUM_CONSTANT(CURSOR_IBEAM);
 | 
				
			||||||
| 
						 | 
					@ -197,7 +219,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
 | 
								String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
 | 
				
			||||||
			r_options->push_back(name.quote());
 | 
								r_options->push_back(name.quote());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -252,6 +274,10 @@ Input::VelocityTrack::VelocityTrack() {
 | 
				
			||||||
bool Input::is_anything_pressed() const {
 | 
					bool Input::is_anything_pressed() const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) {
 | 
						if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) {
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -265,23 +291,63 @@ bool Input::is_anything_pressed() const {
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Input::is_anything_pressed_except_mouse() const {
 | 
				
			||||||
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty()) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<StringName, Input::ActionState> &E : action_states) {
 | 
				
			||||||
 | 
							if (E.value.cache.pressed) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_key_pressed(Key p_keycode) const {
 | 
					bool Input::is_key_pressed(Key p_keycode) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return keys_pressed.has(p_keycode);
 | 
						return keys_pressed.has(p_keycode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_physical_key_pressed(Key p_keycode) const {
 | 
					bool Input::is_physical_key_pressed(Key p_keycode) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return physical_keys_pressed.has(p_keycode);
 | 
						return physical_keys_pressed.has(p_keycode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_key_label_pressed(Key p_keycode) const {
 | 
					bool Input::is_key_label_pressed(Key p_keycode) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return key_label_pressed.has(p_keycode);
 | 
						return key_label_pressed.has(p_keycode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_mouse_button_pressed(MouseButton p_button) const {
 | 
					bool Input::is_mouse_button_pressed(MouseButton p_button) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
 | 
						return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -295,11 +361,21 @@ static JoyButton _combine_device(JoyButton p_value, int p_device) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
 | 
					bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return joy_buttons_pressed.has(_combine_device(p_button, p_device));
 | 
						return joy_buttons_pressed.has(_combine_device(p_button, p_device));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
 | 
					bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
						ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
						HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -310,6 +386,11 @@ bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
 | 
					bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
						ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
						HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -331,6 +412,11 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
 | 
					bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
						ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
						HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -352,6 +438,11 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
 | 
					float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
 | 
						ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return 0.0f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
						HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return 0.0f;
 | 
							return 0.0f;
 | 
				
			||||||
| 
						 | 
					@ -366,6 +457,11 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
 | 
					float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
 | 
						ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return 0.0f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
						HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return 0.0f;
 | 
							return 0.0f;
 | 
				
			||||||
| 
						 | 
					@ -410,6 +506,11 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
 | 
					float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (disable_input) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	JoyAxis c = _combine_device(p_axis, p_device);
 | 
						JoyAxis c = _combine_device(p_axis, p_device);
 | 
				
			||||||
	if (_joy_axis.has(c)) {
 | 
						if (_joy_axis.has(c)) {
 | 
				
			||||||
		return _joy_axis[c];
 | 
							return _joy_axis[c];
 | 
				
			||||||
| 
						 | 
					@ -491,10 +592,9 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_
 | 
				
			||||||
		for (int i = 0; i < map_db.size(); i++) {
 | 
							for (int i = 0; i < map_db.size(); i++) {
 | 
				
			||||||
			if (js.uid == map_db[i].uid) {
 | 
								if (js.uid == map_db[i].uid) {
 | 
				
			||||||
				mapping = i;
 | 
									mapping = i;
 | 
				
			||||||
				js.name = map_db[i].name;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		js.mapping = mapping;
 | 
							_set_joypad_mapping(js, mapping);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		js.connected = false;
 | 
							js.connected = false;
 | 
				
			||||||
		for (int i = 0; i < (int)JoyButton::MAX; i++) {
 | 
							for (int i = 0; i < (int)JoyButton::MAX; i++) {
 | 
				
			||||||
| 
						 | 
					@ -513,21 +613,49 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector3 Input::get_gravity() const {
 | 
					Vector3 Input::get_gravity() const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						if (!gravity_enabled) {
 | 
				
			||||||
 | 
							WARN_PRINT_ONCE("`input_devices/sensors/enable_gravity` is not enabled in project settings.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return gravity;
 | 
						return gravity;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector3 Input::get_accelerometer() const {
 | 
					Vector3 Input::get_accelerometer() const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						if (!accelerometer_enabled) {
 | 
				
			||||||
 | 
							WARN_PRINT_ONCE("`input_devices/sensors/enable_accelerometer` is not enabled in project settings.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return accelerometer;
 | 
						return accelerometer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector3 Input::get_magnetometer() const {
 | 
					Vector3 Input::get_magnetometer() const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						if (!magnetometer_enabled) {
 | 
				
			||||||
 | 
							WARN_PRINT_ONCE("`input_devices/sensors/enable_magnetometer` is not enabled in project settings.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return magnetometer;
 | 
						return magnetometer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector3 Input::get_gyroscope() const {
 | 
					Vector3 Input::get_gyroscope() const {
 | 
				
			||||||
	_THREAD_SAFE_METHOD_
 | 
						_THREAD_SAFE_METHOD_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						if (!gyroscope_enabled) {
 | 
				
			||||||
 | 
							WARN_PRINT_ONCE("`input_devices/sensors/enable_gyroscope` is not enabled in project settings.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return gyroscope;
 | 
						return gyroscope;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -662,6 +790,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
 | 
				
			||||||
				button_event->set_canceled(st->is_canceled());
 | 
									button_event->set_canceled(st->is_canceled());
 | 
				
			||||||
				button_event->set_button_index(MouseButton::LEFT);
 | 
									button_event->set_button_index(MouseButton::LEFT);
 | 
				
			||||||
				button_event->set_double_click(st->is_double_tap());
 | 
									button_event->set_double_click(st->is_double_tap());
 | 
				
			||||||
 | 
									button_event->set_window_id(st->get_window_id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				BitField<MouseButtonMask> ev_bm = mouse_button_mask;
 | 
									BitField<MouseButtonMask> ev_bm = mouse_button_mask;
 | 
				
			||||||
				if (st->is_pressed()) {
 | 
									if (st->is_pressed()) {
 | 
				
			||||||
| 
						 | 
					@ -699,6 +828,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
 | 
				
			||||||
			motion_event->set_velocity(sd->get_velocity());
 | 
								motion_event->set_velocity(sd->get_velocity());
 | 
				
			||||||
			motion_event->set_screen_velocity(sd->get_screen_velocity());
 | 
								motion_event->set_screen_velocity(sd->get_screen_velocity());
 | 
				
			||||||
			motion_event->set_button_mask(mouse_button_mask);
 | 
								motion_event->set_button_mask(mouse_button_mask);
 | 
				
			||||||
 | 
								motion_event->set_window_id(sd->get_window_id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_parse_input_event_impl(motion_event, true);
 | 
								_parse_input_event_impl(motion_event, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -906,7 +1036,7 @@ void Input::action_release(const StringName &p_action) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create or retrieve existing action.
 | 
						// Create or retrieve existing action.
 | 
				
			||||||
	ActionState &action_state = action_states[p_action];
 | 
						ActionState &action_state = action_states[p_action];
 | 
				
			||||||
	action_state.cache.pressed = 0;
 | 
						action_state.cache.pressed = false;
 | 
				
			||||||
	action_state.cache.strength = 0.0;
 | 
						action_state.cache.strength = 0.0;
 | 
				
			||||||
	action_state.cache.raw_strength = 0.0;
 | 
						action_state.cache.raw_strength = 0.0;
 | 
				
			||||||
	// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
 | 
						// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
 | 
				
			||||||
| 
						 | 
					@ -1455,9 +1585,6 @@ void Input::parse_mapping(const String &p_mapping) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CharString uid;
 | 
					 | 
				
			||||||
	uid.resize(17);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mapping.uid = entry[0];
 | 
						mapping.uid = entry[0];
 | 
				
			||||||
	mapping.name = entry[1];
 | 
						mapping.name = entry[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1558,26 +1685,94 @@ void Input::add_joy_mapping(const String &p_mapping, bool p_update_existing) {
 | 
				
			||||||
		for (KeyValue<int, Joypad> &E : joy_names) {
 | 
							for (KeyValue<int, Joypad> &E : joy_names) {
 | 
				
			||||||
			Joypad &joy = E.value;
 | 
								Joypad &joy = E.value;
 | 
				
			||||||
			if (joy.uid == uid) {
 | 
								if (joy.uid == uid) {
 | 
				
			||||||
				joy.mapping = map_db.size() - 1;
 | 
									_set_joypad_mapping(joy, map_db.size() - 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Input::remove_joy_mapping(const String &p_guid) {
 | 
					void Input::remove_joy_mapping(const String &p_guid) {
 | 
				
			||||||
 | 
						// One GUID can exist multiple times in `map_db`, and
 | 
				
			||||||
 | 
						// `add_joy_mapping` can choose not to update the existing mapping,
 | 
				
			||||||
 | 
						// so the indices can be all over the place. Therefore we need to remember them.
 | 
				
			||||||
 | 
						Vector<int> removed_idx;
 | 
				
			||||||
 | 
						int min_removed_idx = -1;
 | 
				
			||||||
 | 
						int max_removed_idx = -1;
 | 
				
			||||||
 | 
						int fallback_mapping_offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = map_db.size() - 1; i >= 0; i--) {
 | 
						for (int i = map_db.size() - 1; i >= 0; i--) {
 | 
				
			||||||
		if (p_guid == map_db[i].uid) {
 | 
							if (p_guid == map_db[i].uid) {
 | 
				
			||||||
			map_db.remove_at(i);
 | 
								map_db.remove_at(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (max_removed_idx == -1) {
 | 
				
			||||||
 | 
									max_removed_idx = i;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								min_removed_idx = i;
 | 
				
			||||||
 | 
								removed_idx.push_back(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (i < fallback_mapping) {
 | 
				
			||||||
 | 
									fallback_mapping_offset++;
 | 
				
			||||||
 | 
								} else if (i == fallback_mapping) {
 | 
				
			||||||
 | 
									fallback_mapping = -1;
 | 
				
			||||||
 | 
									WARN_PRINT_ONCE(vformat("Removed fallback joypad input mapping \"%s\". This could lead to joypads not working as intended.", p_guid));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (min_removed_idx == -1) {
 | 
				
			||||||
 | 
							return; // Nothing removed.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fallback_mapping > 0) {
 | 
				
			||||||
 | 
							// Fix the shifted index.
 | 
				
			||||||
 | 
							fallback_mapping -= fallback_mapping_offset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int removed_idx_size = removed_idx.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Update joypad mapping references: some
 | 
				
			||||||
 | 
						// * should use the fallback_mapping (if set; if not, they get unmapped), or
 | 
				
			||||||
 | 
						// * need their mapping reference fixed, because the deletion(s) offset them.
 | 
				
			||||||
	for (KeyValue<int, Joypad> &E : joy_names) {
 | 
						for (KeyValue<int, Joypad> &E : joy_names) {
 | 
				
			||||||
		Joypad &joy = E.value;
 | 
							Joypad &joy = E.value;
 | 
				
			||||||
		if (joy.uid == p_guid) {
 | 
							if (joy.mapping < min_removed_idx) {
 | 
				
			||||||
			joy.mapping = -1;
 | 
								continue; // Not affected.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (joy.mapping > max_removed_idx) {
 | 
				
			||||||
 | 
								_set_joypad_mapping(joy, joy.mapping - removed_idx_size);
 | 
				
			||||||
 | 
								continue; // Simple offset fix.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// removed_idx is in reverse order (ie. high to low), because the first loop is in reverse order.
 | 
				
			||||||
 | 
							for (int i = 0; i < removed_idx.size(); i++) {
 | 
				
			||||||
 | 
								if (removed_idx[i] == joy.mapping) {
 | 
				
			||||||
 | 
									// Set to fallback_mapping, if defined, else unmap the joypad.
 | 
				
			||||||
 | 
									// Currently, the fallback_mapping is only set internally, and only for Android.
 | 
				
			||||||
 | 
									_set_joypad_mapping(joy, fallback_mapping);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (removed_idx[i] < joy.mapping) {
 | 
				
			||||||
 | 
									// Complex offset fix:
 | 
				
			||||||
 | 
									// This mapping was shifted by `(removed_idx_size - i)` deletions.
 | 
				
			||||||
 | 
									_set_joypad_mapping(joy, joy.mapping - (removed_idx_size - i));
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::_set_joypad_mapping(Joypad &p_js, int p_map_index) {
 | 
				
			||||||
 | 
						if (p_map_index != fallback_mapping && p_map_index >= 0 && p_map_index < map_db.size() && p_js.uid != "__XINPUT_DEVICE__") {
 | 
				
			||||||
 | 
							// Prefer the joypad name defined in the mapping.
 | 
				
			||||||
 | 
							// Exceptions:
 | 
				
			||||||
 | 
							// * On Windows for XInput devices the mapping would change the joypad's name to a collective name.
 | 
				
			||||||
 | 
							// * A fallback mapping is not allowed to override the joypad's name.
 | 
				
			||||||
 | 
							p_js.name = map_db[p_map_index].name;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p_js.mapping = p_map_index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Input::set_fallback_mapping(const String &p_guid) {
 | 
					void Input::set_fallback_mapping(const String &p_guid) {
 | 
				
			||||||
	for (int i = 0; i < map_db.size(); i++) {
 | 
						for (int i = 0; i < map_db.size(); i++) {
 | 
				
			||||||
		if (map_db[i].uid == p_guid) {
 | 
							if (map_db[i].uid == p_guid) {
 | 
				
			||||||
| 
						 | 
					@ -1634,6 +1829,14 @@ int Input::get_unused_joy_id() {
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::set_disable_input(bool p_disable) {
 | 
				
			||||||
 | 
						disable_input = p_disable;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Input::is_input_disabled() const {
 | 
				
			||||||
 | 
						return disable_input;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Input::Input() {
 | 
					Input::Input() {
 | 
				
			||||||
	singleton = this;
 | 
						singleton = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1683,6 +1886,11 @@ Input::Input() {
 | 
				
			||||||
		// Always use standard behavior in the editor.
 | 
							// Always use standard behavior in the editor.
 | 
				
			||||||
		legacy_just_pressed_behavior = false;
 | 
							legacy_just_pressed_behavior = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						accelerometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_accelerometer", false);
 | 
				
			||||||
 | 
						gravity_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gravity", false);
 | 
				
			||||||
 | 
						gyroscope_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gyroscope", false);
 | 
				
			||||||
 | 
						magnetometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_magnetometer", false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Input::~Input() {
 | 
					Input::~Input() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,12 +47,14 @@ class Input : public Object {
 | 
				
			||||||
	static constexpr uint64_t MAX_EVENT = 32;
 | 
						static constexpr uint64_t MAX_EVENT = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
						// Keep synced with "DisplayServer::MouseMode" enum.
 | 
				
			||||||
	enum MouseMode {
 | 
						enum MouseMode {
 | 
				
			||||||
		MOUSE_MODE_VISIBLE,
 | 
							MOUSE_MODE_VISIBLE,
 | 
				
			||||||
		MOUSE_MODE_HIDDEN,
 | 
							MOUSE_MODE_HIDDEN,
 | 
				
			||||||
		MOUSE_MODE_CAPTURED,
 | 
							MOUSE_MODE_CAPTURED,
 | 
				
			||||||
		MOUSE_MODE_CONFINED,
 | 
							MOUSE_MODE_CONFINED,
 | 
				
			||||||
		MOUSE_MODE_CONFINED_HIDDEN,
 | 
							MOUSE_MODE_CONFINED_HIDDEN,
 | 
				
			||||||
 | 
							MOUSE_MODE_MAX,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef CursorShape
 | 
					#undef CursorShape
 | 
				
			||||||
| 
						 | 
					@ -92,13 +94,18 @@ private:
 | 
				
			||||||
	RBSet<JoyButton> joy_buttons_pressed;
 | 
						RBSet<JoyButton> joy_buttons_pressed;
 | 
				
			||||||
	RBMap<JoyAxis, float> _joy_axis;
 | 
						RBMap<JoyAxis, float> _joy_axis;
 | 
				
			||||||
	//RBMap<StringName,int> custom_action_press;
 | 
						//RBMap<StringName,int> custom_action_press;
 | 
				
			||||||
 | 
						bool gravity_enabled = false;
 | 
				
			||||||
	Vector3 gravity;
 | 
						Vector3 gravity;
 | 
				
			||||||
 | 
						bool accelerometer_enabled = false;
 | 
				
			||||||
	Vector3 accelerometer;
 | 
						Vector3 accelerometer;
 | 
				
			||||||
 | 
						bool magnetometer_enabled = false;
 | 
				
			||||||
	Vector3 magnetometer;
 | 
						Vector3 magnetometer;
 | 
				
			||||||
 | 
						bool gyroscope_enabled = false;
 | 
				
			||||||
	Vector3 gyroscope;
 | 
						Vector3 gyroscope;
 | 
				
			||||||
	Vector2 mouse_pos;
 | 
						Vector2 mouse_pos;
 | 
				
			||||||
	int64_t mouse_window = 0;
 | 
						int64_t mouse_window = 0;
 | 
				
			||||||
	bool legacy_just_pressed_behavior = false;
 | 
						bool legacy_just_pressed_behavior = false;
 | 
				
			||||||
 | 
						bool disable_input = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ActionState {
 | 
						struct ActionState {
 | 
				
			||||||
		uint64_t pressed_physics_frame = UINT64_MAX;
 | 
							uint64_t pressed_physics_frame = UINT64_MAX;
 | 
				
			||||||
| 
						 | 
					@ -175,7 +182,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashSet<uint32_t> ignored_device_ids;
 | 
						HashSet<uint32_t> ignored_device_ids;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fallback_mapping = -1;
 | 
						int fallback_mapping = -1; // Index of the guid in map_db.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CursorShape default_shape = CURSOR_ARROW;
 | 
						CursorShape default_shape = CURSOR_ARROW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,6 +243,8 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Vector<JoyDeviceMapping> map_db;
 | 
						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_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);
 | 
						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]);
 | 
						void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
 | 
				
			||||||
| 
						 | 
					@ -257,6 +266,10 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void (*set_mouse_mode_func)(MouseMode);
 | 
						static void (*set_mouse_mode_func)(MouseMode);
 | 
				
			||||||
	static MouseMode (*get_mouse_mode_func)();
 | 
						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 void (*warp_mouse_func)(const Vector2 &p_position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static CursorShape (*get_current_cursor_shape_func)();
 | 
						static CursorShape (*get_current_cursor_shape_func)();
 | 
				
			||||||
| 
						 | 
					@ -275,6 +288,10 @@ protected:
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	void set_mouse_mode(MouseMode p_mode);
 | 
						void set_mouse_mode(MouseMode p_mode);
 | 
				
			||||||
	MouseMode get_mouse_mode() const;
 | 
						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
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
						void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
| 
						 | 
					@ -283,6 +300,7 @@ public:
 | 
				
			||||||
	static Input *get_singleton();
 | 
						static Input *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool is_anything_pressed() const;
 | 
						bool is_anything_pressed() const;
 | 
				
			||||||
 | 
						bool is_anything_pressed_except_mouse() const;
 | 
				
			||||||
	bool is_key_pressed(Key p_keycode) const;
 | 
						bool is_key_pressed(Key p_keycode) const;
 | 
				
			||||||
	bool is_physical_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_key_label_pressed(Key p_keycode) const;
 | 
				
			||||||
| 
						 | 
					@ -376,6 +394,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_event_dispatch_function(EventDispatchFunc p_function);
 | 
						void set_event_dispatch_function(EventDispatchFunc p_function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_disable_input(bool p_disable);
 | 
				
			||||||
 | 
						bool is_input_disabled() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Input();
 | 
						Input();
 | 
				
			||||||
	~Input();
 | 
						~Input();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@ def make_default_controller_mappings(target, source, env):
 | 
				
			||||||
                    guid = line_parts[0]
 | 
					                    guid = line_parts[0]
 | 
				
			||||||
                    if guid in platform_mappings[current_platform]:
 | 
					                    if guid in platform_mappings[current_platform]:
 | 
				
			||||||
                        g.write(
 | 
					                        g.write(
 | 
				
			||||||
                            "// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
 | 
					                            "// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
 | 
				
			||||||
                                src_path, current_platform, platform_mappings[current_platform][guid]
 | 
					                                src_path, current_platform, platform_mappings[current_platform][guid]
 | 
				
			||||||
                            )
 | 
					                            )
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,8 @@
 | 
				
			||||||
#ifndef INPUT_ENUMS_H
 | 
					#ifndef INPUT_ENUMS_H
 | 
				
			||||||
#define INPUT_ENUMS_H
 | 
					#define INPUT_ENUMS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/error/error_macros.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class HatDir {
 | 
					enum class HatDir {
 | 
				
			||||||
	UP = 0,
 | 
						UP = 0,
 | 
				
			||||||
	RIGHT = 1,
 | 
						RIGHT = 1,
 | 
				
			||||||
| 
						 | 
					@ -131,6 +133,8 @@ enum class MouseButtonMask {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
 | 
					inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(button == MouseButton::NONE, MouseButtonMask::NONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return MouseButtonMask(1 << ((int)button - 1));
 | 
						return MouseButtonMask(1 << ((int)button - 1));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -754,6 +754,8 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
 | 
				
			||||||
	mb->set_factor(factor);
 | 
						mb->set_factor(factor);
 | 
				
			||||||
	mb->set_button_index(button_index);
 | 
						mb->set_button_index(button_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mb->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mb;
 | 
						return mb;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -974,6 +976,8 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
 | 
				
			||||||
	mm->set_velocity(p_xform.basis_xform(get_velocity()));
 | 
						mm->set_velocity(p_xform.basis_xform(get_velocity()));
 | 
				
			||||||
	mm->set_screen_velocity(get_screen_velocity());
 | 
						mm->set_screen_velocity(get_screen_velocity());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mm->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mm;
 | 
						return mm;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1088,7 +1092,7 @@ void InputEventMouseMotion::_bind_methods() {
 | 
				
			||||||
///////////////////////////////////
 | 
					///////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InputEventJoypadMotion::set_axis(JoyAxis p_axis) {
 | 
					void InputEventJoypadMotion::set_axis(JoyAxis p_axis) {
 | 
				
			||||||
	ERR_FAIL_COND(p_axis < JoyAxis::LEFT_X || p_axis > JoyAxis::MAX);
 | 
						ERR_FAIL_COND(p_axis < JoyAxis::INVALID || p_axis > JoyAxis::MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	axis = p_axis;
 | 
						axis = p_axis;
 | 
				
			||||||
	emit_changed();
 | 
						emit_changed();
 | 
				
			||||||
| 
						 | 
					@ -1100,7 +1104,7 @@ JoyAxis InputEventJoypadMotion::get_axis() const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InputEventJoypadMotion::set_axis_value(float p_value) {
 | 
					void InputEventJoypadMotion::set_axis_value(float p_value) {
 | 
				
			||||||
	axis_value = p_value;
 | 
						axis_value = p_value;
 | 
				
			||||||
	pressed = Math::abs(axis_value) >= 0.5f;
 | 
						pressed = Math::abs(axis_value) >= InputMap::DEFAULT_DEADZONE;
 | 
				
			||||||
	emit_changed();
 | 
						emit_changed();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1366,6 +1370,8 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
 | 
				
			||||||
	st->set_canceled(canceled);
 | 
						st->set_canceled(canceled);
 | 
				
			||||||
	st->set_double_tap(double_tap);
 | 
						st->set_double_tap(double_tap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						st->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return st;
 | 
						return st;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1494,6 +1500,8 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con
 | 
				
			||||||
	sd->set_velocity(p_xform.basis_xform(velocity));
 | 
						sd->set_velocity(p_xform.basis_xform(velocity));
 | 
				
			||||||
	sd->set_screen_velocity(get_screen_velocity());
 | 
						sd->set_screen_velocity(get_screen_velocity());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sd->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sd;
 | 
						return sd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1705,6 +1713,8 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform,
 | 
				
			||||||
	ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 | 
						ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 | 
				
			||||||
	ev->set_factor(get_factor());
 | 
						ev->set_factor(get_factor());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ev->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ev;
 | 
						return ev;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1745,6 +1755,8 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con
 | 
				
			||||||
	ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 | 
						ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 | 
				
			||||||
	ev->set_delta(get_delta());
 | 
						ev->set_delta(get_delta());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ev->merge_meta_from(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ev;
 | 
						return ev;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								engine/core/input/input_map.compat.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								engine/core/input/input_map.compat.inc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  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
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "input_map.h"
 | 
					#include "input_map.h"
 | 
				
			||||||
 | 
					#include "input_map.compat.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/input/input.h"
 | 
					#include "core/input/input.h"
 | 
				
			||||||
| 
						 | 
					@ -43,7 +44,7 @@ int InputMap::ALL_DEVICES = -1;
 | 
				
			||||||
void InputMap::_bind_methods() {
 | 
					void InputMap::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
 | 
						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("get_actions"), &InputMap::_get_actions);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f));
 | 
						ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
 | 
						ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
 | 
						ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
 | 
				
			||||||
| 
						 | 
					@ -105,7 +106,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
 | 
								String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
 | 
				
			||||||
			r_options->push_back(name.quote());
 | 
								r_options->push_back(name.quote());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -115,7 +116,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
 | 
					void InputMap::add_action(const StringName &p_action, float p_deadzone) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\".");
 | 
						ERR_FAIL_COND_MSG(input_map.has(p_action), vformat("InputMap already has action \"%s\".", String(p_action)));
 | 
				
			||||||
	input_map[p_action] = Action();
 | 
						input_map[p_action] = Action();
 | 
				
			||||||
	static int last_id = 1;
 | 
						static int last_id = 1;
 | 
				
			||||||
	input_map[p_action].id = last_id;
 | 
						input_map[p_action].id = last_id;
 | 
				
			||||||
| 
						 | 
					@ -157,7 +158,7 @@ List<StringName> InputMap::get_actions() const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
					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_valid(), nullptr);
 | 
						ERR_FAIL_COND_V(p_event.is_null(), nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int i = 0;
 | 
						int i = 0;
 | 
				
			||||||
	for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
 | 
						for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
 | 
				
			||||||
| 
						 | 
					@ -253,8 +254,8 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
 | 
					int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
 | 
				
			||||||
	int index = -1;
 | 
						int index = -1;
 | 
				
			||||||
	event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
 | 
						bool valid = event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
 | 
				
			||||||
	return 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 {
 | 
					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 {
 | 
				
			||||||
| 
						 | 
					@ -303,10 +304,10 @@ void InputMap::load_from_project_settings() {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
 | 
							String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Dictionary action = GLOBAL_GET(pi.name);
 | 
							Dictionary action = GLOBAL_GET(pi.name);
 | 
				
			||||||
		float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
 | 
							float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
 | 
				
			||||||
		Array events = action["events"];
 | 
							Array events = action["events"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		add_action(name, deadzone);
 | 
							add_action(name, deadzone);
 | 
				
			||||||
| 
						 | 
					@ -400,6 +401,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
 | 
				
			||||||
    { "ui_filedialog_refresh",                         TTRC("Refresh") },
 | 
					    { "ui_filedialog_refresh",                         TTRC("Refresh") },
 | 
				
			||||||
    { "ui_filedialog_show_hidden",                     TTRC("Show Hidden") },
 | 
					    { "ui_filedialog_show_hidden",                     TTRC("Show Hidden") },
 | 
				
			||||||
    { "ui_swap_input_direction ",                      TTRC("Swap Input Direction") },
 | 
					    { "ui_swap_input_direction ",                      TTRC("Swap Input Direction") },
 | 
				
			||||||
 | 
					    { "ui_unicode_start",                              TTRC("Start Unicode Character Input") },
 | 
				
			||||||
    { "",                                              ""}
 | 
					    { "",                                              ""}
 | 
				
			||||||
	/* clang-format on */
 | 
						/* clang-format on */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -517,12 +519,15 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
 | 
				
			||||||
	default_builtin_cache.insert("ui_text_completion_query", inputs);
 | 
						default_builtin_cache.insert("ui_text_completion_query", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::ENTER));
 | 
						inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::TAB));
 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
						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);
 | 
						default_builtin_cache.insert("ui_text_completion_accept", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::TAB));
 | 
						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);
 | 
						default_builtin_cache.insert("ui_text_completion_replace", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Newlines
 | 
						// Newlines
 | 
				
			||||||
| 
						 | 
					@ -532,7 +537,6 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
 | 
				
			||||||
	default_builtin_cache.insert("ui_text_newline", inputs);
 | 
						default_builtin_cache.insert("ui_text_newline", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD_OR_CTRL));
 | 
						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));
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
	default_builtin_cache.insert("ui_text_newline_blank", inputs);
 | 
						default_builtin_cache.insert("ui_text_newline_blank", inputs);
 | 
				
			||||||
| 
						 | 
					@ -754,6 +758,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
 | 
				
			||||||
	inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
				
			||||||
	default_builtin_cache.insert("ui_text_submit", inputs);
 | 
						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 /////
 | 
						// ///// UI Graph Shortcuts /////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inputs = List<Ref<InputEvent>>();
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,8 @@ public:
 | 
				
			||||||
		List<Ref<InputEvent>> inputs;
 | 
							List<Ref<InputEvent>> inputs;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr float DEFAULT_DEADZONE = 0.2f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	static InputMap *singleton;
 | 
						static InputMap *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,12 +71,17 @@ private:
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						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:
 | 
					public:
 | 
				
			||||||
	static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
 | 
						static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_action(const StringName &p_action) const;
 | 
						bool has_action(const StringName &p_action) const;
 | 
				
			||||||
	List<StringName> get_actions() const;
 | 
						List<StringName> get_actions() const;
 | 
				
			||||||
	void add_action(const StringName &p_action, float p_deadzone = 0.5);
 | 
						void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE);
 | 
				
			||||||
	void erase_action(const StringName &p_action);
 | 
						void erase_action(const StringName &p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float action_get_deadzone(const StringName &p_action);
 | 
						float action_get_deadzone(const StringName &p_action);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,6 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "shortcut.h"
 | 
					#include "shortcut.h"
 | 
				
			||||||
#include "core/os/keyboard.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Shortcut::set_events(const Array &p_events) {
 | 
					void Shortcut::set_events(const Array &p_events) {
 | 
				
			||||||
	for (int i = 0; i < p_events.size(); i++) {
 | 
						for (int i = 0; i < p_events.size(); i++) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					from misc.utility.scons_hints import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ public:
 | 
				
			||||||
	static int zstd_window_log_size;
 | 
						static int zstd_window_log_size;
 | 
				
			||||||
	static int gzip_chunk;
 | 
						static int gzip_chunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum Mode {
 | 
						enum Mode : int32_t {
 | 
				
			||||||
		MODE_FASTLZ,
 | 
							MODE_FASTLZ,
 | 
				
			||||||
		MODE_DEFLATE,
 | 
							MODE_DEFLATE,
 | 
				
			||||||
		MODE_ZSTD,
 | 
							MODE_ZSTD,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,6 @@
 | 
				
			||||||
#include "config_file.h"
 | 
					#include "config_file.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/io/file_access_encrypted.h"
 | 
					#include "core/io/file_access_encrypted.h"
 | 
				
			||||||
#include "core/os/keyboard.h"
 | 
					 | 
				
			||||||
#include "core/string/string_builder.h"
 | 
					#include "core/string/string_builder.h"
 | 
				
			||||||
#include "core/variant/variant_parser.h"
 | 
					#include "core/variant/variant_parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +32,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/io/file_access.h"
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
#include "core/os/memory.h"
 | 
					 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "core/os/time.h"
 | 
				
			||||||
#include "core/templates/local_vector.h"
 | 
					#include "core/templates/local_vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
thread_local Error DirAccess::last_dir_open_error = OK;
 | 
					thread_local Error DirAccess::last_dir_open_error = OK;
 | 
				
			||||||
| 
						 | 
					@ -155,9 +155,9 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
 | 
				
			||||||
	} else if (full_dir.begins_with("user://")) {
 | 
						} else if (full_dir.begins_with("user://")) {
 | 
				
			||||||
		base = "user://";
 | 
							base = "user://";
 | 
				
			||||||
	} else if (full_dir.is_network_share_path()) {
 | 
						} else if (full_dir.is_network_share_path()) {
 | 
				
			||||||
		int pos = full_dir.find("/", 2);
 | 
							int pos = full_dir.find_char('/', 2);
 | 
				
			||||||
		ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
							ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
				
			||||||
		pos = full_dir.find("/", pos + 1);
 | 
							pos = full_dir.find_char('/', pos + 1);
 | 
				
			||||||
		ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
							ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
				
			||||||
		base = full_dir.substr(0, pos + 1);
 | 
							base = full_dir.substr(0, pos + 1);
 | 
				
			||||||
	} else if (full_dir.begins_with("/")) {
 | 
						} else if (full_dir.begins_with("/")) {
 | 
				
			||||||
| 
						 | 
					@ -177,7 +177,7 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
 | 
				
			||||||
		curpath = curpath.path_join(subdirs[i]);
 | 
							curpath = curpath.path_join(subdirs[i]);
 | 
				
			||||||
		Error err = make_dir(curpath);
 | 
							Error err = make_dir(curpath);
 | 
				
			||||||
		if (err != OK && err != ERR_ALREADY_EXISTS) {
 | 
							if (err != OK && err != ERR_ALREADY_EXISTS) {
 | 
				
			||||||
			ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
 | 
								ERR_FAIL_V_MSG(err, vformat("Could not create directory: '%s'.", curpath));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,7 +239,7 @@ Ref<DirAccess> DirAccess::create_for_path(const String &p_path) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
 | 
					Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
 | 
				
			||||||
	Ref<DirAccess> da = create_for_path(p_path);
 | 
						Ref<DirAccess> da = create_for_path(p_path);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'.");
 | 
						ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, vformat("Cannot create DirAccess for path '%s'.", p_path));
 | 
				
			||||||
	Error err = da->change_dir(p_path);
 | 
						Error err = da->change_dir(p_path);
 | 
				
			||||||
	if (r_error) {
 | 
						if (r_error) {
 | 
				
			||||||
		*r_error = err;
 | 
							*r_error = err;
 | 
				
			||||||
| 
						 | 
					@ -323,6 +323,80 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
 | 
				
			||||||
	return da;
 | 
						return da;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::create_temp(const String &p_prefix, bool p_keep, Error *r_error) {
 | 
				
			||||||
 | 
						const String ERROR_COMMON_PREFIX = "Error while creating temporary directory";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p_prefix.is_valid_filename()) {
 | 
				
			||||||
 | 
							*r_error = ERR_FILE_BAD_PATH;
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<DirAccess> dir_access = DirAccess::open(OS::get_singleton()->get_temp_path());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t suffix_i = 0;
 | 
				
			||||||
 | 
						String path;
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", "");
 | 
				
			||||||
 | 
							datetime += itos(Time::get_singleton()->get_ticks_usec());
 | 
				
			||||||
 | 
							String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
 | 
				
			||||||
 | 
							path = (p_prefix.is_empty() ? "" : p_prefix + "-") + suffix;
 | 
				
			||||||
 | 
							if (!path.is_valid_filename()) {
 | 
				
			||||||
 | 
								*r_error = ERR_FILE_BAD_PATH;
 | 
				
			||||||
 | 
								return Ref<DirAccess>();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!DirAccess::exists(path)) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							suffix_i += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err = dir_access->make_dir(path);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							*r_error = err;
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" couldn't create directory "%s".)", ERROR_COMMON_PREFIX, path));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = dir_access->change_dir(path);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							*r_error = err;
 | 
				
			||||||
 | 
							return Ref<DirAccess>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dir_access->_is_temp = true;
 | 
				
			||||||
 | 
						dir_access->_temp_keep_after_free = p_keep;
 | 
				
			||||||
 | 
						dir_access->_temp_path = dir_access->get_current_dir();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*r_error = OK;
 | 
				
			||||||
 | 
						return dir_access;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::_create_temp(const String &p_prefix, bool p_keep) {
 | 
				
			||||||
 | 
						return create_temp(p_prefix, p_keep, &last_dir_open_error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DirAccess::_delete_temp() {
 | 
				
			||||||
 | 
						if (!_is_temp || _temp_keep_after_free) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!DirAccess::exists(_temp_path)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Ref<DirAccess> dir_access = DirAccess::open(_temp_path, &err);
 | 
				
			||||||
 | 
							if (err != OK) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = dir_access->erase_contents_recursive();
 | 
				
			||||||
 | 
							if (err != OK) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DirAccess::remove_absolute(_temp_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error DirAccess::get_open_error() {
 | 
					Error DirAccess::get_open_error() {
 | 
				
			||||||
	return last_dir_open_error;
 | 
						return last_dir_open_error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -345,10 +419,10 @@ Error DirAccess::copy(const String &p_from, const String &p_to, int p_chmod_flag
 | 
				
			||||||
	Error err;
 | 
						Error err;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
 | 
							Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from);
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Failed to open '%s'.", p_from));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
 | 
							Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to);
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Failed to open '%s'.", p_to));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const size_t copy_buffer_limit = 65536; // 64 KB
 | 
							const size_t copy_buffer_limit = 65536; // 64 KB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -444,11 +518,11 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, const String &p_to, int
 | 
				
			||||||
		String target_dir = p_to + rel_path;
 | 
							String target_dir = p_to + rel_path;
 | 
				
			||||||
		if (!p_target_da->dir_exists(target_dir)) {
 | 
							if (!p_target_da->dir_exists(target_dir)) {
 | 
				
			||||||
			Error err = p_target_da->make_dir(target_dir);
 | 
								Error err = p_target_da->make_dir(target_dir);
 | 
				
			||||||
			ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + target_dir + "'.");
 | 
								ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot create directory '%s'.", target_dir));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Error err = change_dir(rel_path);
 | 
							Error err = change_dir(rel_path);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + rel_path + "'.");
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot change current directory to '%s'.", rel_path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
 | 
							err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
 | 
				
			||||||
		if (err) {
 | 
							if (err) {
 | 
				
			||||||
| 
						 | 
					@ -466,11 +540,11 @@ Error DirAccess::copy_dir(const String &p_from, String p_to, int p_chmod_flags,
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
 | 
						ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<DirAccess> target_da = DirAccess::create_for_path(p_to);
 | 
						Ref<DirAccess> target_da = DirAccess::create_for_path(p_to);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'.");
 | 
						ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", p_to));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!target_da->dir_exists(p_to)) {
 | 
						if (!target_da->dir_exists(p_to)) {
 | 
				
			||||||
		Error err = target_da->make_dir_recursive(p_to);
 | 
							Error err = target_da->make_dir_recursive(p_to);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'.");
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot create directory '%s'.", p_to));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!p_to.ends_with("/")) {
 | 
						if (!p_to.ends_with("/")) {
 | 
				
			||||||
| 
						 | 
					@ -555,8 +629,9 @@ bool DirAccess::is_case_sensitive(const String &p_path) const {
 | 
				
			||||||
void DirAccess::_bind_methods() {
 | 
					void DirAccess::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
 | 
				
			||||||
	ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("create_temp", "prefix", "keep"), &DirAccess::_create_temp, DEFVAL(""), DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
 | 
						ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
 | 
						ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
 | 
						ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
 | 
						ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
 | 
				
			||||||
| 
						 | 
					@ -588,6 +663,8 @@ void DirAccess::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("read_link", "path"), &DirAccess::read_link);
 | 
						ClassDB::bind_method(D_METHOD("read_link", "path"), &DirAccess::read_link);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("create_link", "source", "target"), &DirAccess::create_link);
 | 
						ClassDB::bind_method(D_METHOD("create_link", "source", "target"), &DirAccess::create_link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_bundle", "path"), &DirAccess::is_bundle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
 | 
						ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
 | 
						ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
 | 
						ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
 | 
				
			||||||
| 
						 | 
					@ -598,3 +675,7 @@ void DirAccess::_bind_methods() {
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
 | 
				
			||||||
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
 | 
						ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirAccess::~DirAccess() {
 | 
				
			||||||
 | 
						_delete_temp();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ class DirAccess : public RefCounted {
 | 
				
			||||||
	GDCLASS(DirAccess, RefCounted);
 | 
						GDCLASS(DirAccess, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	enum AccessType {
 | 
						enum AccessType : int32_t {
 | 
				
			||||||
		ACCESS_RESOURCES,
 | 
							ACCESS_RESOURCES,
 | 
				
			||||||
		ACCESS_USERDATA,
 | 
							ACCESS_USERDATA,
 | 
				
			||||||
		ACCESS_FILESYSTEM,
 | 
							ACCESS_FILESYSTEM,
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,13 @@ private:
 | 
				
			||||||
	bool include_navigational = false;
 | 
						bool include_navigational = false;
 | 
				
			||||||
	bool include_hidden = false;
 | 
						bool include_hidden = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _is_temp = false;
 | 
				
			||||||
 | 
						bool _temp_keep_after_free = false;
 | 
				
			||||||
 | 
						String _temp_path;
 | 
				
			||||||
 | 
						void _delete_temp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<DirAccess> _create_temp(const String &p_prefix = "", bool p_keep = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,8 +103,8 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(String p_file) = 0;
 | 
						virtual bool file_exists(String p_file) = 0;
 | 
				
			||||||
	virtual bool dir_exists(String p_dir) = 0;
 | 
						virtual bool dir_exists(String p_dir) = 0;
 | 
				
			||||||
	virtual bool is_readable(String p_dir) { return true; };
 | 
						virtual bool is_readable(String p_dir) { return true; }
 | 
				
			||||||
	virtual bool is_writable(String p_dir) { return true; };
 | 
						virtual bool is_writable(String p_dir) { return true; }
 | 
				
			||||||
	static bool exists(const String &p_dir);
 | 
						static bool exists(const String &p_dir);
 | 
				
			||||||
	virtual uint64_t get_space_left() = 0;
 | 
						virtual uint64_t get_space_left() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,10 +123,10 @@ public:
 | 
				
			||||||
		Ref<DirAccess> da = create(ACCESS_FILESYSTEM);
 | 
							Ref<DirAccess> da = create(ACCESS_FILESYSTEM);
 | 
				
			||||||
		if (da->file_exists(p_path)) {
 | 
							if (da->file_exists(p_path)) {
 | 
				
			||||||
			if (da->remove(p_path) != OK) {
 | 
								if (da->remove(p_path) != OK) {
 | 
				
			||||||
				ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
 | 
									ERR_FAIL_MSG(vformat("Cannot remove file or directory: '%s'.", p_path));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path);
 | 
								ERR_FAIL_MSG(vformat("Cannot remove non-existent file or directory: '%s'.", p_path));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,6 +143,7 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
 | 
						static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
 | 
				
			||||||
 | 
						static Ref<DirAccess> create_temp(const String &p_prefix = "", bool p_keep = false, Error *r_error = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static int _get_drive_count();
 | 
						static int _get_drive_count();
 | 
				
			||||||
	static String get_drive_name(int p_idx);
 | 
						static String get_drive_name(int p_idx);
 | 
				
			||||||
| 
						 | 
					@ -160,9 +168,11 @@ public:
 | 
				
			||||||
	bool get_include_hidden() const;
 | 
						bool get_include_hidden() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool is_case_sensitive(const String &p_path) const;
 | 
						virtual bool is_case_sensitive(const String &p_path) const;
 | 
				
			||||||
 | 
						virtual bool is_bundle(const String &p_file) const { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
	DirAccess() {}
 | 
						DirAccess() {}
 | 
				
			||||||
	virtual ~DirAccess() {}
 | 
						virtual ~DirAccess();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // DIR_ACCESS_H
 | 
					#endif // DIR_ACCESS_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,15 +30,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "dtls_server.h"
 | 
					#include "dtls_server.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					DTLSServer *(*DTLSServer::_create)(bool p_notify_postinitialize) = nullptr;
 | 
				
			||||||
#include "core/io/file_access.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DTLSServer *(*DTLSServer::_create)() = nullptr;
 | 
					 | 
				
			||||||
bool DTLSServer::available = false;
 | 
					bool DTLSServer::available = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DTLSServer *DTLSServer::create() {
 | 
					DTLSServer *DTLSServer::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,14 +38,14 @@ class DTLSServer : public RefCounted {
 | 
				
			||||||
	GDCLASS(DTLSServer, RefCounted);
 | 
						GDCLASS(DTLSServer, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static DTLSServer *(*_create)();
 | 
						static DTLSServer *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static bool available;
 | 
						static bool available;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static bool is_available();
 | 
						static bool is_available();
 | 
				
			||||||
	static DTLSServer *create();
 | 
						static DTLSServer *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error setup(Ref<TLSOptions> p_options) = 0;
 | 
						virtual Error setup(Ref<TLSOptions> p_options) = 0;
 | 
				
			||||||
	virtual void stop() = 0;
 | 
						virtual void stop() = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								engine/core/io/file_access.compat.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								engine/core/io/file_access.compat.inc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,112 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  file_access.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<FileAccess> FileAccess::_open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
 | 
				
			||||||
 | 
						return open_encrypted(p_path, p_mode_flags, p_key, Vector<uint8_t>());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_8_bind_compat_78289(uint8_t p_dest) {
 | 
				
			||||||
 | 
						store_8(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_16_bind_compat_78289(uint16_t p_dest) {
 | 
				
			||||||
 | 
						store_16(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_32_bind_compat_78289(uint32_t p_dest) {
 | 
				
			||||||
 | 
						store_32(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_64_bind_compat_78289(uint64_t p_dest) {
 | 
				
			||||||
 | 
						store_64(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_buffer_bind_compat_78289(const Vector<uint8_t> &p_buffer) {
 | 
				
			||||||
 | 
						store_buffer(p_buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_var_bind_compat_78289(const Variant &p_var, bool p_full_objects) {
 | 
				
			||||||
 | 
						store_var(p_var, p_full_objects);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_half_bind_compat_78289(float p_dest) {
 | 
				
			||||||
 | 
						store_half(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_float_bind_compat_78289(float p_dest) {
 | 
				
			||||||
 | 
						store_float(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_double_bind_compat_78289(double p_dest) {
 | 
				
			||||||
 | 
						store_double(p_dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_real_bind_compat_78289(real_t p_real) {
 | 
				
			||||||
 | 
						store_real(p_real);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_string_bind_compat_78289(const String &p_string) {
 | 
				
			||||||
 | 
						store_string(p_string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_line_bind_compat_78289(const String &p_line) {
 | 
				
			||||||
 | 
						store_line(p_line);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_csv_line_bind_compat_78289(const Vector<String> &p_values, const String &p_delim) {
 | 
				
			||||||
 | 
						store_csv_line(p_values, p_delim);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::store_pascal_string_bind_compat_78289(const String &p_string) {
 | 
				
			||||||
 | 
						store_pascal_string(p_string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::_bind_compatibility_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::_open_encrypted_bind_compat_98918);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_8", "value"), &FileAccess::store_8_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_16", "value"), &FileAccess::store_16_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_32", "value"), &FileAccess::store_32_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_64", "value"), &FileAccess::store_64_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_half", "value"), &FileAccess::store_half_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_float", "value"), &FileAccess::store_float_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_double", "value"), &FileAccess::store_double_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_real", "value"), &FileAccess::store_real_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_buffer", "buffer"), &FileAccess::store_buffer_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_line", "line"), &FileAccess::store_line_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line_bind_compat_78289, DEFVAL(","));
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_string", "string"), &FileAccess::store_string_bind_compat_78289);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var_bind_compat_78289, DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string_bind_compat_78289);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
/**************************************************************************/
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "file_access.h"
 | 
					#include "file_access.h"
 | 
				
			||||||
 | 
					#include "file_access.compat.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/crypto/crypto_core.h"
 | 
					#include "core/crypto/crypto_core.h"
 | 
				
			||||||
| 
						 | 
					@ -37,6 +38,7 @@
 | 
				
			||||||
#include "core/io/file_access_pack.h"
 | 
					#include "core/io/file_access_pack.h"
 | 
				
			||||||
#include "core/io/marshalls.h"
 | 
					#include "core/io/marshalls.h"
 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "core/os/time.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = {};
 | 
					FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,11 +61,9 @@ bool FileAccess::exists(const String &p_name) {
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> f = open(p_name, READ);
 | 
						// Using file_exists because it's faster than trying to open the file.
 | 
				
			||||||
	if (f.is_null()) {
 | 
						Ref<FileAccess> ret = create_for_path(p_name);
 | 
				
			||||||
		return false;
 | 
						return ret->file_exists(p_name);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::_set_access_type(AccessType p_access) {
 | 
					void FileAccess::_set_access_type(AccessType p_access) {
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ void FileAccess::_set_access_type(AccessType p_access) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
 | 
					Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
 | 
				
			||||||
	Ref<FileAccess> ret;
 | 
						Ref<FileAccess> ret;
 | 
				
			||||||
	if (p_path.begins_with("res://")) {
 | 
						if (p_path.begins_with("res://") || p_path.begins_with("uid://")) {
 | 
				
			||||||
		ret = create(ACCESS_RESOURCES);
 | 
							ret = create(ACCESS_RESOURCES);
 | 
				
			||||||
	} else if (p_path.begins_with("user://")) {
 | 
						} else if (p_path.begins_with("user://")) {
 | 
				
			||||||
		ret = create(ACCESS_USERDATA);
 | 
							ret = create(ACCESS_USERDATA);
 | 
				
			||||||
| 
						 | 
					@ -85,6 +85,79 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<FileAccess> FileAccess::create_temp(int p_mode_flags, const String &p_prefix, const String &p_extension, bool p_keep, Error *r_error) {
 | 
				
			||||||
 | 
						const String ERROR_COMMON_PREFIX = "Error while creating temporary file";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p_prefix.is_valid_filename()) {
 | 
				
			||||||
 | 
							*r_error = ERR_FILE_BAD_PATH;
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p_extension.is_valid_filename()) {
 | 
				
			||||||
 | 
							*r_error = ERR_FILE_BAD_PATH;
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" is not a valid extension.)", ERROR_COMMON_PREFIX, p_extension));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const String TEMP_DIR = OS::get_singleton()->get_temp_path();
 | 
				
			||||||
 | 
						String extension = p_extension.trim_prefix(".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t suffix_i = 0;
 | 
				
			||||||
 | 
						String path;
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", "");
 | 
				
			||||||
 | 
							datetime += itos(Time::get_singleton()->get_ticks_usec());
 | 
				
			||||||
 | 
							String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
 | 
				
			||||||
 | 
							path = TEMP_DIR.path_join((p_prefix.is_empty() ? "" : p_prefix + "-") + suffix + (extension.is_empty() ? "" : "." + extension));
 | 
				
			||||||
 | 
							if (!DirAccess::exists(path)) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							suffix_i += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Create file first with WRITE mode.
 | 
				
			||||||
 | 
							// Otherwise, it would fail to open with a READ mode.
 | 
				
			||||||
 | 
							Ref<FileAccess> ret = FileAccess::open(path, FileAccess::ModeFlags::WRITE, &err);
 | 
				
			||||||
 | 
							if (err != OK) {
 | 
				
			||||||
 | 
								*r_error = err;
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: could not create "%s".)", ERROR_COMMON_PREFIX, path));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret->flush();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Open then the temp file with the correct mode flag.
 | 
				
			||||||
 | 
						Ref<FileAccess> ret = FileAccess::open(path, p_mode_flags, &err);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							*r_error = err;
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: could not open "%s".)", ERROR_COMMON_PREFIX, path));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ret.is_valid()) {
 | 
				
			||||||
 | 
							ret->_is_temp_file = true;
 | 
				
			||||||
 | 
							ret->_temp_keep_after_use = p_keep;
 | 
				
			||||||
 | 
							ret->_temp_path = ret->get_path_absolute();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*r_error = OK;
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<FileAccess> FileAccess::_create_temp(int p_mode_flags, const String &p_prefix, const String &p_extension, bool p_keep) {
 | 
				
			||||||
 | 
						return create_temp(p_mode_flags, p_prefix, p_extension, p_keep, &last_file_open_error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileAccess::_delete_temp() {
 | 
				
			||||||
 | 
						if (!_is_temp_file || _temp_keep_after_use) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!FileAccess::exists(_temp_path)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DirAccess::remove_absolute(_temp_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
 | 
					Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
 | 
				
			||||||
	return open_internal(p_path, p_mode_flags);
 | 
						return open_internal(p_path, p_mode_flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -126,7 +199,7 @@ Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags)
 | 
				
			||||||
	return fa;
 | 
						return fa;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
 | 
					Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv) {
 | 
				
			||||||
	Ref<FileAccess> fa = _open(p_path, p_mode_flags);
 | 
						Ref<FileAccess> fa = _open(p_path, p_mode_flags);
 | 
				
			||||||
	if (fa.is_null()) {
 | 
						if (fa.is_null()) {
 | 
				
			||||||
		return fa;
 | 
							return fa;
 | 
				
			||||||
| 
						 | 
					@ -134,7 +207,7 @@ Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccessEncrypted> fae;
 | 
						Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
	fae.instantiate();
 | 
						fae.instantiate();
 | 
				
			||||||
	Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
 | 
						Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ, true, p_iv);
 | 
				
			||||||
	last_file_open_error = err;
 | 
						last_file_open_error = err;
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		return Ref<FileAccess>();
 | 
							return Ref<FileAccess>();
 | 
				
			||||||
| 
						 | 
					@ -184,13 +257,17 @@ FileAccess::AccessType FileAccess::get_access_type() const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String FileAccess::fix_path(const String &p_path) const {
 | 
					String FileAccess::fix_path(const String &p_path) const {
 | 
				
			||||||
	//helper used by file accesses that use a single filesystem
 | 
						// Helper used by file accesses that use a single filesystem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String r_path = p_path.replace("\\", "/");
 | 
						String r_path = p_path.replace("\\", "/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (_access_type) {
 | 
						switch (_access_type) {
 | 
				
			||||||
		case ACCESS_RESOURCES: {
 | 
							case ACCESS_RESOURCES: {
 | 
				
			||||||
			if (ProjectSettings::get_singleton()) {
 | 
								if (ProjectSettings::get_singleton()) {
 | 
				
			||||||
 | 
									if (r_path.begins_with("uid://")) {
 | 
				
			||||||
 | 
										r_path = ResourceUID::uid_to_path(r_path);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (r_path.begins_with("res://")) {
 | 
									if (r_path.begins_with("res://")) {
 | 
				
			||||||
					String resource_path = ProjectSettings::get_singleton()->get_resource_path();
 | 
										String resource_path = ProjectSettings::get_singleton()->get_resource_path();
 | 
				
			||||||
					if (!resource_path.is_empty()) {
 | 
										if (!resource_path.is_empty()) {
 | 
				
			||||||
| 
						 | 
					@ -225,59 +302,48 @@ String FileAccess::fix_path(const String &p_path) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* these are all implemented for ease of porting, then can later be optimized */
 | 
					/* these are all implemented for ease of porting, then can later be optimized */
 | 
				
			||||||
 | 
					uint8_t FileAccess::get_8() const {
 | 
				
			||||||
 | 
						uint8_t data = 0;
 | 
				
			||||||
 | 
						get_buffer(&data, sizeof(uint8_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint16_t FileAccess::get_16() const {
 | 
					uint16_t FileAccess::get_16() const {
 | 
				
			||||||
	uint16_t res;
 | 
						uint16_t data = 0;
 | 
				
			||||||
	uint8_t a, b;
 | 
						get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint16_t));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = get_8();
 | 
					 | 
				
			||||||
	b = get_8();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (big_endian) {
 | 
						if (big_endian) {
 | 
				
			||||||
		SWAP(a, b);
 | 
							data = BSWAP16(data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = b;
 | 
						return data;
 | 
				
			||||||
	res <<= 8;
 | 
					 | 
				
			||||||
	res |= a;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t FileAccess::get_32() const {
 | 
					uint32_t FileAccess::get_32() const {
 | 
				
			||||||
	uint32_t res;
 | 
						uint32_t data = 0;
 | 
				
			||||||
	uint16_t a, b;
 | 
						get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint32_t));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = get_16();
 | 
					 | 
				
			||||||
	b = get_16();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (big_endian) {
 | 
						if (big_endian) {
 | 
				
			||||||
		SWAP(a, b);
 | 
							data = BSWAP32(data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = b;
 | 
						return data;
 | 
				
			||||||
	res <<= 16;
 | 
					 | 
				
			||||||
	res |= a;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t FileAccess::get_64() const {
 | 
					uint64_t FileAccess::get_64() const {
 | 
				
			||||||
	uint64_t res;
 | 
						uint64_t data = 0;
 | 
				
			||||||
	uint32_t a, b;
 | 
						get_buffer(reinterpret_cast<uint8_t *>(&data), sizeof(uint64_t));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = get_32();
 | 
					 | 
				
			||||||
	b = get_32();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (big_endian) {
 | 
						if (big_endian) {
 | 
				
			||||||
		SWAP(a, b);
 | 
							data = BSWAP64(data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = b;
 | 
						return data;
 | 
				
			||||||
	res <<= 32;
 | 
					}
 | 
				
			||||||
	res |= a;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return res;
 | 
					float FileAccess::get_half() const {
 | 
				
			||||||
 | 
						return Math::half_to_float(get_16());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float FileAccess::get_float() const {
 | 
					float FileAccess::get_float() const {
 | 
				
			||||||
| 
						 | 
					@ -317,7 +383,7 @@ double FileAccess::get_double() const {
 | 
				
			||||||
String FileAccess::get_token() const {
 | 
					String FileAccess::get_token() const {
 | 
				
			||||||
	CharString token;
 | 
						CharString token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char32_t c = get_8();
 | 
						uint8_t c = get_8();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!eof_reached()) {
 | 
						while (!eof_reached()) {
 | 
				
			||||||
		if (c <= ' ') {
 | 
							if (c <= ' ') {
 | 
				
			||||||
| 
						 | 
					@ -325,7 +391,7 @@ String FileAccess::get_token() const {
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			token += c;
 | 
								token += char(c);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		c = get_8();
 | 
							c = get_8();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -382,14 +448,14 @@ public:
 | 
				
			||||||
String FileAccess::get_line() const {
 | 
					String FileAccess::get_line() const {
 | 
				
			||||||
	CharBuffer line;
 | 
						CharBuffer line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char32_t c = get_8();
 | 
						uint8_t c = get_8();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!eof_reached()) {
 | 
						while (!eof_reached()) {
 | 
				
			||||||
		if (c == '\n' || c == '\0') {
 | 
							if (c == '\n' || c == '\0' || get_error() != OK) {
 | 
				
			||||||
			line.push_back(0);
 | 
								line.push_back(0);
 | 
				
			||||||
			return String::utf8(line.get_data());
 | 
								return String::utf8(line.get_data());
 | 
				
			||||||
		} else if (c != '\r') {
 | 
							} else if (c != '\r') {
 | 
				
			||||||
			line.push_back(c);
 | 
								line.push_back(char(c));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c = get_8();
 | 
							c = get_8();
 | 
				
			||||||
| 
						 | 
					@ -467,17 +533,6 @@ String FileAccess::get_as_text(bool p_skip_cr) const {
 | 
				
			||||||
	return text;
 | 
						return text;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint64_t i = 0;
 | 
					 | 
				
			||||||
	for (i = 0; i < p_length && !eof_reached(); i++) {
 | 
					 | 
				
			||||||
		p_dst[i] = get_8();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return i;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
 | 
					Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
 | 
				
			||||||
	Vector<uint8_t> data;
 | 
						Vector<uint8_t> data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -487,10 +542,10 @@ Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = data.resize(p_length);
 | 
						Error err = data.resize(p_length);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, data, vformat("Can't resize data to %d elements.", p_length));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t *w = data.ptrw();
 | 
						uint8_t *w = data.ptrw();
 | 
				
			||||||
	int64_t len = get_buffer(&w[0], p_length);
 | 
						int64_t len = get_buffer(w, p_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len < p_length) {
 | 
						if (len < p_length) {
 | 
				
			||||||
		data.resize(len);
 | 
							data.resize(len);
 | 
				
			||||||
| 
						 | 
					@ -510,70 +565,60 @@ String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
 | 
				
			||||||
	w[len] = 0;
 | 
						w[len] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String s;
 | 
						String s;
 | 
				
			||||||
	s.parse_utf8((const char *)w, -1, p_skip_cr);
 | 
						s.parse_utf8((const char *)w, len, p_skip_cr);
 | 
				
			||||||
	return s;
 | 
						return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_16(uint16_t p_dest) {
 | 
					bool FileAccess::store_8(uint8_t p_dest) {
 | 
				
			||||||
	uint8_t a, b;
 | 
						return store_buffer(&p_dest, sizeof(uint8_t));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = p_dest & 0xFF;
 | 
					 | 
				
			||||||
	b = p_dest >> 8;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (big_endian) {
 | 
					 | 
				
			||||||
		SWAP(a, b);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	store_8(a);
 | 
					 | 
				
			||||||
	store_8(b);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_32(uint32_t p_dest) {
 | 
					bool FileAccess::store_16(uint16_t p_dest) {
 | 
				
			||||||
	uint16_t a, b;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = p_dest & 0xFFFF;
 | 
					 | 
				
			||||||
	b = p_dest >> 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (big_endian) {
 | 
						if (big_endian) {
 | 
				
			||||||
		SWAP(a, b);
 | 
							p_dest = BSWAP16(p_dest);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_16(a);
 | 
						return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint16_t));
 | 
				
			||||||
	store_16(b);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_64(uint64_t p_dest) {
 | 
					bool FileAccess::store_32(uint32_t p_dest) {
 | 
				
			||||||
	uint32_t a, b;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = p_dest & 0xFFFFFFFF;
 | 
					 | 
				
			||||||
	b = p_dest >> 32;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (big_endian) {
 | 
						if (big_endian) {
 | 
				
			||||||
		SWAP(a, b);
 | 
							p_dest = BSWAP32(p_dest);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_32(a);
 | 
						return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint32_t));
 | 
				
			||||||
	store_32(b);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_real(real_t p_real) {
 | 
					bool FileAccess::store_64(uint64_t p_dest) {
 | 
				
			||||||
 | 
						if (big_endian) {
 | 
				
			||||||
 | 
							p_dest = BSWAP64(p_dest);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return store_buffer(reinterpret_cast<uint8_t *>(&p_dest), sizeof(uint64_t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool FileAccess::store_real(real_t p_real) {
 | 
				
			||||||
	if constexpr (sizeof(real_t) == 4) {
 | 
						if constexpr (sizeof(real_t) == 4) {
 | 
				
			||||||
		store_float(p_real);
 | 
							return store_float(p_real);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		store_double(p_real);
 | 
							return store_double(p_real);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_float(float p_dest) {
 | 
					bool FileAccess::store_half(float p_dest) {
 | 
				
			||||||
 | 
						return store_16(Math::make_half_float(p_dest));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool FileAccess::store_float(float p_dest) {
 | 
				
			||||||
	MarshallFloat m;
 | 
						MarshallFloat m;
 | 
				
			||||||
	m.f = p_dest;
 | 
						m.f = p_dest;
 | 
				
			||||||
	store_32(m.i);
 | 
						return store_32(m.i);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_double(double p_dest) {
 | 
					bool FileAccess::store_double(double p_dest) {
 | 
				
			||||||
	MarshallDouble m;
 | 
						MarshallDouble m;
 | 
				
			||||||
	m.d = p_dest;
 | 
						m.d = p_dest;
 | 
				
			||||||
	store_64(m.l);
 | 
						return store_64(m.l);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t FileAccess::get_modified_time(const String &p_file) {
 | 
					uint64_t FileAccess::get_modified_time(const String &p_file) {
 | 
				
			||||||
| 
						 | 
					@ -582,7 +627,7 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t mt = fa->_get_modified_time(p_file);
 | 
						uint64_t mt = fa->_get_modified_time(p_file);
 | 
				
			||||||
	return mt;
 | 
						return mt;
 | 
				
			||||||
| 
						 | 
					@ -594,7 +639,7 @@ BitField<FileAccess::UnixPermissionFlags> FileAccess::get_unix_permissions(const
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fa->_get_unix_permissions(p_file);
 | 
						return fa->_get_unix_permissions(p_file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -605,7 +650,7 @@ Error FileAccess::set_unix_permissions(const String &p_file, BitField<FileAccess
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = fa->_set_unix_permissions(p_file, p_permissions);
 | 
						Error err = fa->_set_unix_permissions(p_file, p_permissions);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -617,7 +662,7 @@ bool FileAccess::get_hidden_attribute(const String &p_file) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fa->_get_hidden_attribute(p_file);
 | 
						return fa->_get_hidden_attribute(p_file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -628,7 +673,7 @@ Error FileAccess::set_hidden_attribute(const String &p_file, bool p_hidden) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = fa->_set_hidden_attribute(p_file, p_hidden);
 | 
						Error err = fa->_set_hidden_attribute(p_file, p_hidden);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -640,7 +685,7 @@ bool FileAccess::get_read_only_attribute(const String &p_file) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fa->_get_read_only_attribute(p_file);
 | 
						return fa->_get_read_only_attribute(p_file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -651,25 +696,24 @@ Error FileAccess::set_read_only_attribute(const String &p_file, bool p_ro) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> fa = create_for_path(p_file);
 | 
						Ref<FileAccess> fa = create_for_path(p_file);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
 | 
						ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error err = fa->_set_read_only_attribute(p_file, p_ro);
 | 
						Error err = fa->_set_read_only_attribute(p_file, p_ro);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_string(const String &p_string) {
 | 
					bool FileAccess::store_string(const String &p_string) {
 | 
				
			||||||
	if (p_string.length() == 0) {
 | 
						if (p_string.length() == 0) {
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CharString cs = p_string.utf8();
 | 
						CharString cs = p_string.utf8();
 | 
				
			||||||
	store_buffer((uint8_t *)&cs[0], cs.length());
 | 
						return store_buffer((uint8_t *)&cs[0], cs.length());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_pascal_string(const String &p_string) {
 | 
					bool FileAccess::store_pascal_string(const String &p_string) {
 | 
				
			||||||
	CharString cs = p_string.utf8();
 | 
						CharString cs = p_string.utf8();
 | 
				
			||||||
	store_32(cs.length());
 | 
						return store_32(cs.length()) && store_buffer((uint8_t *)&cs[0], cs.length());
 | 
				
			||||||
	store_buffer((uint8_t *)&cs[0], cs.length());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String FileAccess::get_pascal_string() {
 | 
					String FileAccess::get_pascal_string() {
 | 
				
			||||||
| 
						 | 
					@ -680,24 +724,23 @@ String FileAccess::get_pascal_string() {
 | 
				
			||||||
	cs[sl] = 0;
 | 
						cs[sl] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String ret;
 | 
						String ret;
 | 
				
			||||||
	ret.parse_utf8(cs.ptr());
 | 
						ret.parse_utf8(cs.ptr(), sl);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_line(const String &p_line) {
 | 
					bool FileAccess::store_line(const String &p_line) {
 | 
				
			||||||
	store_string(p_line);
 | 
						return store_string(p_line) && store_8('\n');
 | 
				
			||||||
	store_8('\n');
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
 | 
					bool FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
 | 
				
			||||||
	ERR_FAIL_COND(p_delim.length() != 1);
 | 
						ERR_FAIL_COND_V(p_delim.length() != 1, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String line = "";
 | 
						String line = "";
 | 
				
			||||||
	int size = p_values.size();
 | 
						int size = p_values.size();
 | 
				
			||||||
	for (int i = 0; i < size; ++i) {
 | 
						for (int i = 0; i < size; ++i) {
 | 
				
			||||||
		String value = p_values[i];
 | 
							String value = p_values[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (value.contains("\"") || value.contains(p_delim) || value.contains("\n")) {
 | 
							if (value.contains_char('"') || value.contains(p_delim) || value.contains_char('\n')) {
 | 
				
			||||||
			value = "\"" + value.replace("\"", "\"\"") + "\"";
 | 
								value = "\"" + value.replace("\"", "\"\"") + "\"";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (i < size - 1) {
 | 
							if (i < size - 1) {
 | 
				
			||||||
| 
						 | 
					@ -707,41 +750,43 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_
 | 
				
			||||||
		line += value;
 | 
							line += value;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_line(line);
 | 
						return store_line(line);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
					bool FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
 | 
				
			||||||
	ERR_FAIL_COND(!p_src && p_length > 0);
 | 
					 | 
				
			||||||
	for (uint64_t i = 0; i < p_length; i++) {
 | 
					 | 
				
			||||||
		store_8(p_src[i]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
 | 
					 | 
				
			||||||
	uint64_t len = p_buffer.size();
 | 
						uint64_t len = p_buffer.size();
 | 
				
			||||||
	if (len == 0) {
 | 
						if (len == 0) {
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const uint8_t *r = p_buffer.ptr();
 | 
						const uint8_t *r = p_buffer.ptr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_buffer(&r[0], len);
 | 
						return store_buffer(r, len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
 | 
					bool FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!p_src && p_length > 0, false);
 | 
				
			||||||
 | 
						for (uint64_t i = 0; i < p_length; i++) {
 | 
				
			||||||
 | 
							if (unlikely(!store_8(p_src[i]))) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
 | 
				
			||||||
	int len;
 | 
						int len;
 | 
				
			||||||
	Error err = encode_variant(p_var, nullptr, len, p_full_objects);
 | 
						Error err = encode_variant(p_var, nullptr, len, p_full_objects);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, false, "Error when trying to encode Variant.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Vector<uint8_t> buff;
 | 
						Vector<uint8_t> buff;
 | 
				
			||||||
	buff.resize(len);
 | 
						buff.resize(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t *w = buff.ptrw();
 | 
						uint8_t *w = buff.ptrw();
 | 
				
			||||||
	err = encode_variant(p_var, &w[0], len, p_full_objects);
 | 
						err = encode_variant(p_var, &w[0], len, p_full_objects);
 | 
				
			||||||
	ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
 | 
						ERR_FAIL_COND_V_MSG(err != OK, false, "Error when trying to encode Variant.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_32(len);
 | 
						return store_32(uint32_t(len)) && store_buffer(buff);
 | 
				
			||||||
	store_buffer(buff);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
 | 
					Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
 | 
				
			||||||
| 
						 | 
					@ -750,7 +795,7 @@ Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_err
 | 
				
			||||||
		if (r_error) { // if error requested, do not throw error
 | 
							if (r_error) { // if error requested, do not throw error
 | 
				
			||||||
			return Vector<uint8_t>();
 | 
								return Vector<uint8_t>();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path '" + String(p_path) + "'.");
 | 
							ERR_FAIL_V_MSG(Vector<uint8_t>(), vformat("Can't open file from path '%s'.", String(p_path)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	Vector<uint8_t> data;
 | 
						Vector<uint8_t> data;
 | 
				
			||||||
	data.resize(f->get_length());
 | 
						data.resize(f->get_length());
 | 
				
			||||||
| 
						 | 
					@ -768,7 +813,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
 | 
				
			||||||
		if (r_error) {
 | 
							if (r_error) {
 | 
				
			||||||
			return String();
 | 
								return String();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ERR_FAIL_V_MSG(String(), "Can't get file as string from path '" + String(p_path) + "'.");
 | 
							ERR_FAIL_V_MSG(String(), vformat("Can't get file as string from path '%s'.", String(p_path)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String ret;
 | 
						String ret;
 | 
				
			||||||
| 
						 | 
					@ -859,10 +904,11 @@ String FileAccess::get_sha256(const String &p_file) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccess::_bind_methods() {
 | 
					void FileAccess::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key", "iv"), &FileAccess::open_encrypted, DEFVAL(Vector<uint8_t>()));
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("create_temp", "mode_flags", "prefix", "extension", "keep"), &FileAccess::_create_temp, DEFVAL(""), DEFVAL(""), DEFVAL(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
 | 
				
			||||||
	ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
 | 
						ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
 | 
				
			||||||
| 
						 | 
					@ -881,6 +927,7 @@ void FileAccess::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
 | 
						ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
 | 
						ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
 | 
						ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_half"), &FileAccess::get_half);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
 | 
						ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
 | 
						ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
 | 
						ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
 | 
				
			||||||
| 
						 | 
					@ -899,10 +946,11 @@ void FileAccess::_bind_methods() {
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
 | 
						ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
 | 
						ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
 | 
						ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("store_half", "value"), &FileAccess::store_half);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
 | 
						ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
 | 
						ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
 | 
						ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer);
 | 
						ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
 | 
						ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
 | 
						ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
 | 
				
			||||||
	ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
 | 
						ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
 | 
				
			||||||
| 
						 | 
					@ -950,3 +998,7 @@ void FileAccess::_bind_methods() {
 | 
				
			||||||
	BIND_BITFIELD_FLAG(UNIX_SET_GROUP_ID);
 | 
						BIND_BITFIELD_FLAG(UNIX_SET_GROUP_ID);
 | 
				
			||||||
	BIND_BITFIELD_FLAG(UNIX_RESTRICTED_DELETE);
 | 
						BIND_BITFIELD_FLAG(UNIX_RESTRICTED_DELETE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FileAccess::~FileAccess() {
 | 
				
			||||||
 | 
						_delete_temp();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ class FileAccess : public RefCounted {
 | 
				
			||||||
	GDCLASS(FileAccess, RefCounted);
 | 
						GDCLASS(FileAccess, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	enum AccessType {
 | 
						enum AccessType : int32_t {
 | 
				
			||||||
		ACCESS_RESOURCES,
 | 
							ACCESS_RESOURCES,
 | 
				
			||||||
		ACCESS_USERDATA,
 | 
							ACCESS_USERDATA,
 | 
				
			||||||
		ACCESS_FILESYSTEM,
 | 
							ACCESS_FILESYSTEM,
 | 
				
			||||||
| 
						 | 
					@ -54,14 +54,14 @@ public:
 | 
				
			||||||
		ACCESS_MAX
 | 
							ACCESS_MAX
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum ModeFlags {
 | 
						enum ModeFlags : int32_t {
 | 
				
			||||||
		READ = 1,
 | 
							READ = 1,
 | 
				
			||||||
		WRITE = 2,
 | 
							WRITE = 2,
 | 
				
			||||||
		READ_WRITE = 3,
 | 
							READ_WRITE = 3,
 | 
				
			||||||
		WRITE_READ = 7,
 | 
							WRITE_READ = 7,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum UnixPermissionFlags {
 | 
						enum UnixPermissionFlags : int32_t {
 | 
				
			||||||
		UNIX_EXECUTE_OTHER = 0x001,
 | 
							UNIX_EXECUTE_OTHER = 0x001,
 | 
				
			||||||
		UNIX_WRITE_OTHER = 0x002,
 | 
							UNIX_WRITE_OTHER = 0x002,
 | 
				
			||||||
		UNIX_READ_OTHER = 0x004,
 | 
							UNIX_READ_OTHER = 0x004,
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ public:
 | 
				
			||||||
		UNIX_SET_USER_ID = 0x800,
 | 
							UNIX_SET_USER_ID = 0x800,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum CompressionMode {
 | 
						enum CompressionMode : int32_t {
 | 
				
			||||||
		COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
 | 
							COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
 | 
				
			||||||
		COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
 | 
							COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
 | 
				
			||||||
		COMPRESSION_ZSTD = Compression::MODE_ZSTD,
 | 
							COMPRESSION_ZSTD = Compression::MODE_ZSTD,
 | 
				
			||||||
| 
						 | 
					@ -109,6 +109,27 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static FileCloseFailNotify close_fail_notify;
 | 
						static FileCloseFailNotify close_fail_notify;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						static Ref<FileAccess> _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void store_8_bind_compat_78289(uint8_t p_dest);
 | 
				
			||||||
 | 
						void store_16_bind_compat_78289(uint16_t p_dest);
 | 
				
			||||||
 | 
						void store_32_bind_compat_78289(uint32_t p_dest);
 | 
				
			||||||
 | 
						void store_64_bind_compat_78289(uint64_t p_dest);
 | 
				
			||||||
 | 
						void store_buffer_bind_compat_78289(const Vector<uint8_t> &p_buffer);
 | 
				
			||||||
 | 
						void store_var_bind_compat_78289(const Variant &p_var, bool p_full_objects = false);
 | 
				
			||||||
 | 
						void store_half_bind_compat_78289(float p_dest);
 | 
				
			||||||
 | 
						void store_float_bind_compat_78289(float p_dest);
 | 
				
			||||||
 | 
						void store_double_bind_compat_78289(double p_dest);
 | 
				
			||||||
 | 
						void store_real_bind_compat_78289(real_t p_real);
 | 
				
			||||||
 | 
						void store_string_bind_compat_78289(const String &p_string);
 | 
				
			||||||
 | 
						void store_line_bind_compat_78289(const String &p_line);
 | 
				
			||||||
 | 
						void store_csv_line_bind_compat_78289(const Vector<String> &p_values, const String &p_delim = ",");
 | 
				
			||||||
 | 
						void store_pascal_string_bind_compat_78289(const String &p_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _bind_compatibility_methods();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	static bool backup_save;
 | 
						static bool backup_save;
 | 
				
			||||||
	thread_local static Error last_file_open_error;
 | 
						thread_local static Error last_file_open_error;
 | 
				
			||||||
| 
						 | 
					@ -122,6 +143,13 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
 | 
						static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _is_temp_file = false;
 | 
				
			||||||
 | 
						bool _temp_keep_after_use = false;
 | 
				
			||||||
 | 
						String _temp_path;
 | 
				
			||||||
 | 
						void _delete_temp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<FileAccess> _create_temp(int p_mode_flags, const String &p_prefix = "", const String &p_extension = "", bool p_keep = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static void set_file_close_fail_notify_callback(FileCloseFailNotify p_cbk) { close_fail_notify = p_cbk; }
 | 
						static void set_file_close_fail_notify_callback(FileCloseFailNotify p_cbk) { close_fail_notify = p_cbk; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,18 +165,19 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const = 0; ///< reading passed EOF
 | 
						virtual bool eof_reached() const = 0; ///< reading passed EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const = 0; ///< get a byte
 | 
						virtual uint8_t get_8() const; ///< get a byte
 | 
				
			||||||
	virtual uint16_t get_16() const; ///< get 16 bits uint
 | 
						virtual uint16_t get_16() const; ///< get 16 bits uint
 | 
				
			||||||
	virtual uint32_t get_32() const; ///< get 32 bits uint
 | 
						virtual uint32_t get_32() const; ///< get 32 bits uint
 | 
				
			||||||
	virtual uint64_t get_64() const; ///< get 64 bits uint
 | 
						virtual uint64_t get_64() const; ///< get 64 bits uint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual float get_half() const;
 | 
				
			||||||
	virtual float get_float() const;
 | 
						virtual float get_float() const;
 | 
				
			||||||
	virtual double get_double() const;
 | 
						virtual double get_double() const;
 | 
				
			||||||
	virtual real_t get_real() const;
 | 
						virtual real_t get_real() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Variant get_var(bool p_allow_objects = false) const;
 | 
						Variant get_var(bool p_allow_objects = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const = 0; ///< get an array of bytes, needs to be overwritten by children.
 | 
				
			||||||
	Vector<uint8_t> get_buffer(int64_t p_length) const;
 | 
						Vector<uint8_t> get_buffer(int64_t p_length) const;
 | 
				
			||||||
	virtual String get_line() const;
 | 
						virtual String get_line() const;
 | 
				
			||||||
	virtual String get_token() const;
 | 
						virtual String get_token() const;
 | 
				
			||||||
| 
						 | 
					@ -157,6 +186,7 @@ public:
 | 
				
			||||||
	virtual String get_as_utf8_string(bool p_skip_cr = false) const;
 | 
						virtual String get_as_utf8_string(bool p_skip_cr = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	 * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
 | 
						 * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
 | 
				
			||||||
	 * It's not about the current CPU type but file formats.
 | 
						 * It's not about the current CPU type but file formats.
 | 
				
			||||||
	 * This flag gets reset to `false` (little endian) on each open.
 | 
						 * This flag gets reset to `false` (little endian) on each open.
 | 
				
			||||||
| 
						 | 
					@ -168,26 +198,27 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) = 0;
 | 
						virtual Error resize(int64_t p_length) = 0;
 | 
				
			||||||
	virtual void flush() = 0;
 | 
						virtual void flush() = 0;
 | 
				
			||||||
	virtual void store_8(uint8_t p_dest) = 0; ///< store a byte
 | 
						virtual bool store_8(uint8_t p_dest); ///< store a byte
 | 
				
			||||||
	virtual void store_16(uint16_t p_dest); ///< store 16 bits uint
 | 
						virtual bool store_16(uint16_t p_dest); ///< store 16 bits uint
 | 
				
			||||||
	virtual void store_32(uint32_t p_dest); ///< store 32 bits uint
 | 
						virtual bool store_32(uint32_t p_dest); ///< store 32 bits uint
 | 
				
			||||||
	virtual void store_64(uint64_t p_dest); ///< store 64 bits uint
 | 
						virtual bool store_64(uint64_t p_dest); ///< store 64 bits uint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void store_float(float p_dest);
 | 
						virtual bool store_half(float p_dest);
 | 
				
			||||||
	virtual void store_double(double p_dest);
 | 
						virtual bool store_float(float p_dest);
 | 
				
			||||||
	virtual void store_real(real_t p_real);
 | 
						virtual bool store_double(double p_dest);
 | 
				
			||||||
 | 
						virtual bool store_real(real_t p_real);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void store_string(const String &p_string);
 | 
						virtual bool store_string(const String &p_string);
 | 
				
			||||||
	virtual void store_line(const String &p_line);
 | 
						virtual bool store_line(const String &p_line);
 | 
				
			||||||
	virtual void store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
 | 
						virtual bool store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void store_pascal_string(const String &p_string);
 | 
						virtual bool store_pascal_string(const String &p_string);
 | 
				
			||||||
	virtual String get_pascal_string();
 | 
						virtual String get_pascal_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) = 0; ///< store an array of bytes, needs to be overwritten by children.
 | 
				
			||||||
	void store_buffer(const Vector<uint8_t> &p_buffer);
 | 
						bool store_buffer(const Vector<uint8_t> &p_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void store_var(const Variant &p_var, bool p_full_objects = false);
 | 
						bool store_var(const Variant &p_var, bool p_full_objects = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void close() = 0;
 | 
						virtual void close() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,8 +229,9 @@ public:
 | 
				
			||||||
	static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
 | 
						static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
 | 
				
			||||||
	static Ref<FileAccess> create_for_path(const String &p_path);
 | 
						static Ref<FileAccess> create_for_path(const String &p_path);
 | 
				
			||||||
	static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
 | 
						static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
 | 
				
			||||||
 | 
						static Ref<FileAccess> create_temp(int p_mode_flags, const String &p_prefix = "", const String &p_extension = "", bool p_keep = false, Error *r_error = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
 | 
						static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
 | 
				
			||||||
	static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
 | 
						static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
 | 
				
			||||||
	static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
 | 
						static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
 | 
				
			||||||
	static Error get_open_error();
 | 
						static Error get_open_error();
 | 
				
			||||||
| 
						 | 
					@ -215,8 +247,8 @@ public:
 | 
				
			||||||
	static bool get_read_only_attribute(const String &p_file);
 | 
						static bool get_read_only_attribute(const String &p_file);
 | 
				
			||||||
	static Error set_read_only_attribute(const String &p_file, bool p_ro);
 | 
						static Error set_read_only_attribute(const String &p_file, bool p_ro);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void set_backup_save(bool p_enable) { backup_save = p_enable; };
 | 
						static void set_backup_save(bool p_enable) { backup_save = p_enable; }
 | 
				
			||||||
	static bool is_backup_save_enabled() { return backup_save; };
 | 
						static bool is_backup_save_enabled() { return backup_save; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static String get_md5(const String &p_file);
 | 
						static String get_md5(const String &p_file);
 | 
				
			||||||
	static String get_sha256(const String &p_file);
 | 
						static String get_sha256(const String &p_file);
 | 
				
			||||||
| 
						 | 
					@ -233,8 +265,9 @@ public:
 | 
				
			||||||
		create_func[p_access] = _create_builtin<T>;
 | 
							create_func[p_access] = _create_builtin<T>;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
	FileAccess() {}
 | 
						FileAccess() {}
 | 
				
			||||||
	virtual ~FileAccess() {}
 | 
						virtual ~FileAccess();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VARIANT_ENUM_CAST(FileAccess::CompressionMode);
 | 
					VARIANT_ENUM_CAST(FileAccess::CompressionMode);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,8 +30,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "file_access_compressed.h"
 | 
					#include "file_access_compressed.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/string/print_string.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, uint32_t p_block_size) {
 | 
					void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, uint32_t p_block_size) {
 | 
				
			||||||
	magic = p_magic.ascii().get_data();
 | 
						magic = p_magic.ascii().get_data();
 | 
				
			||||||
	magic = (magic + "    ").substr(0, 4);
 | 
						magic = (magic + "    ").substr(0, 4);
 | 
				
			||||||
| 
						 | 
					@ -40,25 +38,13 @@ void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_
 | 
				
			||||||
	block_size = p_block_size;
 | 
						block_size = p_block_size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WRITE_FIT(m_bytes)                                  \
 | 
					 | 
				
			||||||
	{                                                       \
 | 
					 | 
				
			||||||
		if (write_pos + (m_bytes) > write_max) {            \
 | 
					 | 
				
			||||||
			write_max = write_pos + (m_bytes);              \
 | 
					 | 
				
			||||||
		}                                                   \
 | 
					 | 
				
			||||||
		if (write_max > write_buffer_size) {                \
 | 
					 | 
				
			||||||
			write_buffer_size = next_power_of_2(write_max); \
 | 
					 | 
				
			||||||
			buffer.resize(write_buffer_size);               \
 | 
					 | 
				
			||||||
			write_ptr = buffer.ptrw();                      \
 | 
					 | 
				
			||||||
		}                                                   \
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
 | 
					Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
 | 
				
			||||||
	f = p_base;
 | 
						f = p_base;
 | 
				
			||||||
	cmode = (Compression::Mode)f->get_32();
 | 
						cmode = (Compression::Mode)f->get_32();
 | 
				
			||||||
	block_size = f->get_32();
 | 
						block_size = f->get_32();
 | 
				
			||||||
	if (block_size == 0) {
 | 
						if (block_size == 0) {
 | 
				
			||||||
		f.unref();
 | 
							f.unref();
 | 
				
			||||||
		ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted.");
 | 
							ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, vformat("Can't open compressed file '%s' with block size 0, it is corrupted.", p_base->get_path()));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	read_total = f->get_32();
 | 
						read_total = f->get_32();
 | 
				
			||||||
	uint32_t bc = (read_total / block_size) + 1;
 | 
						uint32_t bc = (read_total / block_size) + 1;
 | 
				
			||||||
| 
						 | 
					@ -137,7 +123,7 @@ void FileAccessCompressed::_close() {
 | 
				
			||||||
		f->store_buffer((const uint8_t *)mgc.get_data(), mgc.length()); //write header 4
 | 
							f->store_buffer((const uint8_t *)mgc.get_data(), mgc.length()); //write header 4
 | 
				
			||||||
		f->store_32(cmode); //write compression mode 4
 | 
							f->store_32(cmode); //write compression mode 4
 | 
				
			||||||
		f->store_32(block_size); //write block size 4
 | 
							f->store_32(block_size); //write block size 4
 | 
				
			||||||
		f->store_32(write_max); //max amount of data written 4
 | 
							f->store_32(uint32_t(write_max)); //max amount of data written 4
 | 
				
			||||||
		uint32_t bc = (write_max / block_size) + 1;
 | 
							uint32_t bc = (write_max / block_size) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (uint32_t i = 0; i < bc; i++) {
 | 
							for (uint32_t i = 0; i < bc; i++) {
 | 
				
			||||||
| 
						 | 
					@ -159,7 +145,7 @@ void FileAccessCompressed::_close() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		f->seek(16); //ok write block sizes
 | 
							f->seek(16); //ok write block sizes
 | 
				
			||||||
		for (uint32_t i = 0; i < bc; i++) {
 | 
							for (uint32_t i = 0; i < bc; i++) {
 | 
				
			||||||
			f->store_32(block_sizes[i]);
 | 
								f->store_32(uint32_t(block_sizes[i]));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		f->seek_end();
 | 
							f->seek_end();
 | 
				
			||||||
		f->store_buffer((const uint8_t *)mgc.get_data(), mgc.length()); //magic at the end too
 | 
							f->store_buffer((const uint8_t *)mgc.get_data(), mgc.length()); //magic at the end too
 | 
				
			||||||
| 
						 | 
					@ -260,38 +246,6 @@ bool FileAccessCompressed::eof_reached() const {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t FileAccessCompressed::get_8() const {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (at_end) {
 | 
					 | 
				
			||||||
		read_eof = true;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint8_t ret = read_ptr[read_pos];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	read_pos++;
 | 
					 | 
				
			||||||
	if (read_pos >= read_block_size) {
 | 
					 | 
				
			||||||
		read_block++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (read_block < read_block_count) {
 | 
					 | 
				
			||||||
			//read another block of compressed data
 | 
					 | 
				
			||||||
			f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize);
 | 
					 | 
				
			||||||
			int total = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
 | 
					 | 
				
			||||||
			ERR_FAIL_COND_V_MSG(total == -1, 0, "Compressed file is corrupt.");
 | 
					 | 
				
			||||||
			read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
 | 
					 | 
				
			||||||
			read_pos = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			read_block--;
 | 
					 | 
				
			||||||
			at_end = true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
						ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
 | 
						ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
 | 
				
			||||||
| 
						 | 
					@ -341,12 +295,25 @@ void FileAccessCompressed::flush() {
 | 
				
			||||||
	// compressed files keep data in memory till close()
 | 
						// compressed files keep data in memory till close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessCompressed::store_8(uint8_t p_dest) {
 | 
					bool FileAccessCompressed::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
 | 
						ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use.");
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
 | 
						ERR_FAIL_COND_V_MSG(!writing, false, "File has not been opened in write mode.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WRITE_FIT(1);
 | 
						if (write_pos + (p_length) > write_max) {
 | 
				
			||||||
	write_ptr[write_pos++] = p_dest;
 | 
							write_max = write_pos + (p_length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (write_max > write_buffer_size) {
 | 
				
			||||||
 | 
							write_buffer_size = next_power_of_2(write_max);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(buffer.resize(write_buffer_size) != OK, false);
 | 
				
			||||||
 | 
							write_ptr = buffer.ptrw();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_length) {
 | 
				
			||||||
 | 
							memcpy(write_ptr + write_pos, p_src, p_length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						write_pos += p_length;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool FileAccessCompressed::file_exists(const String &p_name) {
 | 
					bool FileAccessCompressed::file_exists(const String &p_name) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,14 +83,13 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const override; ///< reading passed EOF
 | 
						virtual bool eof_reached() const override; ///< reading passed EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const override; ///< get a byte
 | 
					 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error get_error() const override; ///< get last error
 | 
						virtual Error get_error() const override; ///< get last error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
						virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
				
			||||||
	virtual void flush() override;
 | 
						virtual void flush() override;
 | 
				
			||||||
	virtual void store_8(uint8_t p_dest) override; ///< store a byte
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
						virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,13 +31,10 @@
 | 
				
			||||||
#include "file_access_encrypted.h"
 | 
					#include "file_access_encrypted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/crypto/crypto_core.h"
 | 
					#include "core/crypto/crypto_core.h"
 | 
				
			||||||
#include "core/string/print_string.h"
 | 
					 | 
				
			||||||
#include "core/variant/variant.h"
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic, const Vector<uint8_t> &p_iv) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute()));
 | 
				
			||||||
Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(file != nullptr, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open.");
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
 | 
						ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pos = 0;
 | 
						pos = 0;
 | 
				
			||||||
| 
						 | 
					@ -49,6 +46,16 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
 | 
				
			||||||
		writing = true;
 | 
							writing = true;
 | 
				
			||||||
		file = p_base;
 | 
							file = p_base;
 | 
				
			||||||
		key = p_key;
 | 
							key = p_key;
 | 
				
			||||||
 | 
							if (p_iv.is_empty()) {
 | 
				
			||||||
 | 
								iv.resize(16);
 | 
				
			||||||
 | 
								CryptoCore::RandomGenerator rng;
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
 | 
				
			||||||
 | 
								Error err = rng.get_random_bytes(iv.ptrw(), 16);
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(err != OK, err);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
								iv = p_iv;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else if (p_mode == MODE_READ) {
 | 
						} else if (p_mode == MODE_READ) {
 | 
				
			||||||
		writing = false;
 | 
							writing = false;
 | 
				
			||||||
| 
						 | 
					@ -63,10 +70,8 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
 | 
				
			||||||
		p_base->get_buffer(md5d, 16);
 | 
							p_base->get_buffer(md5d, 16);
 | 
				
			||||||
		length = p_base->get_64();
 | 
							length = p_base->get_64();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned char iv[16];
 | 
							iv.resize(16);
 | 
				
			||||||
		for (int i = 0; i < 16; i++) {
 | 
							p_base->get_buffer(iv.ptrw(), 16);
 | 
				
			||||||
			iv[i] = p_base->get_8();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		base = p_base->get_position();
 | 
							base = p_base->get_position();
 | 
				
			||||||
		ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT);
 | 
							ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT);
 | 
				
			||||||
| 
						 | 
					@ -83,7 +88,7 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
 | 
				
			||||||
			CryptoCore::AESContext ctx;
 | 
								CryptoCore::AESContext ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
 | 
								ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
 | 
				
			||||||
			ctx.decrypt_cfb(ds, iv, data.ptrw(), data.ptrw());
 | 
								ctx.decrypt_cfb(ds, iv.ptrw(), data.ptrw(), data.ptrw());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data.resize(length);
 | 
							data.resize(length);
 | 
				
			||||||
| 
						 | 
					@ -145,14 +150,9 @@ void FileAccessEncrypted::_close() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		file->store_buffer(hash, 16);
 | 
							file->store_buffer(hash, 16);
 | 
				
			||||||
		file->store_64(data.size());
 | 
							file->store_64(data.size());
 | 
				
			||||||
 | 
							file->store_buffer(iv.ptr(), 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned char iv[16];
 | 
							ctx.encrypt_cfb(len, iv.ptrw(), compressed.ptrw(), compressed.ptrw());
 | 
				
			||||||
		for (int i = 0; i < 16; i++) {
 | 
					 | 
				
			||||||
			iv[i] = Math::rand() % 256;
 | 
					 | 
				
			||||||
			file->store_8(iv[i]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ctx.encrypt_cfb(len, iv, compressed.ptrw(), compressed.ptrw());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		file->store_buffer(compressed.ptr(), compressed.size());
 | 
							file->store_buffer(compressed.ptr(), compressed.size());
 | 
				
			||||||
		data.clear();
 | 
							data.clear();
 | 
				
			||||||
| 
						 | 
					@ -162,7 +162,7 @@ void FileAccessEncrypted::_close() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool FileAccessEncrypted::is_open() const {
 | 
					bool FileAccessEncrypted::is_open() const {
 | 
				
			||||||
	return file != nullptr;
 | 
						return file.is_valid();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String FileAccessEncrypted::get_path() const {
 | 
					String FileAccessEncrypted::get_path() const {
 | 
				
			||||||
| 
						 | 
					@ -206,26 +206,19 @@ bool FileAccessEncrypted::eof_reached() const {
 | 
				
			||||||
	return eofed;
 | 
						return eofed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t FileAccessEncrypted::get_8() const {
 | 
					uint64_t FileAccessEncrypted::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
 | 
						ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
 | 
				
			||||||
	if (pos >= get_length()) {
 | 
					
 | 
				
			||||||
		eofed = true;
 | 
						if (!p_length) {
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t b = data[pos];
 | 
						ERR_FAIL_NULL_V(p_dst, -1);
 | 
				
			||||||
	pos++;
 | 
					 | 
				
			||||||
	return b;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t FileAccessEncrypted::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t to_copy = MIN(p_length, get_length() - pos);
 | 
						uint64_t to_copy = MIN(p_length, get_length() - pos);
 | 
				
			||||||
	for (uint64_t i = 0; i < to_copy; i++) {
 | 
					
 | 
				
			||||||
		p_dst[i] = data[pos++];
 | 
						memcpy(p_dst, data.ptr() + pos, to_copy);
 | 
				
			||||||
	}
 | 
						pos += to_copy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (to_copy < p_length) {
 | 
						if (to_copy < p_length) {
 | 
				
			||||||
		eofed = true;
 | 
							eofed = true;
 | 
				
			||||||
| 
						 | 
					@ -238,21 +231,23 @@ Error FileAccessEncrypted::get_error() const {
 | 
				
			||||||
	return eofed ? ERR_FILE_EOF : OK;
 | 
						return eofed ? ERR_FILE_EOF : OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
					bool FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
 | 
						ERR_FAIL_COND_V_MSG(!writing, false, "File has not been opened in write mode.");
 | 
				
			||||||
	ERR_FAIL_COND(!p_src && p_length > 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pos < get_length()) {
 | 
						if (!p_length) {
 | 
				
			||||||
		for (uint64_t i = 0; i < p_length; i++) {
 | 
							return true;
 | 
				
			||||||
			store_8(p_src[i]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (pos == get_length()) {
 | 
					 | 
				
			||||||
		data.resize(pos + p_length);
 | 
					 | 
				
			||||||
		for (uint64_t i = 0; i < p_length; i++) {
 | 
					 | 
				
			||||||
			data.write[pos + i] = p_src[i];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		pos += p_length;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(p_src, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pos + p_length >= get_length()) {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(data.resize(pos + p_length) != OK, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(data.ptrw() + pos, p_src, p_length);
 | 
				
			||||||
 | 
						pos += p_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessEncrypted::flush() {
 | 
					void FileAccessEncrypted::flush() {
 | 
				
			||||||
| 
						 | 
					@ -261,18 +256,6 @@ void FileAccessEncrypted::flush() {
 | 
				
			||||||
	// encrypted files keep data in memory till close()
 | 
						// encrypted files keep data in memory till close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessEncrypted::store_8(uint8_t p_dest) {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pos < get_length()) {
 | 
					 | 
				
			||||||
		data.write[pos] = p_dest;
 | 
					 | 
				
			||||||
		pos++;
 | 
					 | 
				
			||||||
	} else if (pos == get_length()) {
 | 
					 | 
				
			||||||
		data.push_back(p_dest);
 | 
					 | 
				
			||||||
		pos++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool FileAccessEncrypted::file_exists(const String &p_name) {
 | 
					bool FileAccessEncrypted::file_exists(const String &p_name) {
 | 
				
			||||||
	Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ);
 | 
						Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ);
 | 
				
			||||||
	if (fa.is_null()) {
 | 
						if (fa.is_null()) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,13 +37,14 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FileAccessEncrypted : public FileAccess {
 | 
					class FileAccessEncrypted : public FileAccess {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	enum Mode {
 | 
						enum Mode : int32_t {
 | 
				
			||||||
		MODE_READ,
 | 
							MODE_READ,
 | 
				
			||||||
		MODE_WRITE_AES256,
 | 
							MODE_WRITE_AES256,
 | 
				
			||||||
		MODE_MAX
 | 
							MODE_MAX
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
						Vector<uint8_t> iv;
 | 
				
			||||||
	Vector<uint8_t> key;
 | 
						Vector<uint8_t> key;
 | 
				
			||||||
	bool writing = false;
 | 
						bool writing = false;
 | 
				
			||||||
	Ref<FileAccess> file;
 | 
						Ref<FileAccess> file;
 | 
				
			||||||
| 
						 | 
					@ -57,9 +58,11 @@ private:
 | 
				
			||||||
	void _close();
 | 
						void _close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
 | 
						Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
 | 
				
			||||||
	Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
 | 
						Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<uint8_t> get_iv() const { return iv; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
 | 
						virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
 | 
				
			||||||
	virtual bool is_open() const override; ///< true when file is open
 | 
						virtual bool is_open() const override; ///< true when file is open
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,15 +76,13 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const override; ///< reading passed EOF
 | 
						virtual bool eof_reached() const override; ///< reading passed EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const override; ///< get a byte
 | 
					 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error get_error() const override; ///< get last error
 | 
						virtual Error get_error() const override; ///< get last error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
						virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
				
			||||||
	virtual void flush() override;
 | 
						virtual void flush() override;
 | 
				
			||||||
	virtual void store_8(uint8_t p_dest) override; ///< store a byte
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
 | 
				
			||||||
	virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
						virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,8 +31,6 @@
 | 
				
			||||||
#include "file_access_memory.h"
 | 
					#include "file_access_memory.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/config/project_settings.h"
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
#include "core/io/dir_access.h"
 | 
					 | 
				
			||||||
#include "core/templates/rb_map.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static HashMap<String, Vector<uint8_t>> *files = nullptr;
 | 
					static HashMap<String, Vector<uint8_t>> *files = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,7 +83,7 @@ Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
 | 
				
			||||||
	//name = DirAccess::normalize_path(name);
 | 
						//name = DirAccess::normalize_path(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HashMap<String, Vector<uint8_t>>::Iterator E = files->find(name);
 | 
						HashMap<String, Vector<uint8_t>>::Iterator E = files->find(name);
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, "Can't find file '" + p_path + "'.");
 | 
						ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, vformat("Can't find file '%s'.", p_path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = E->value.ptrw();
 | 
						data = E->value.ptrw();
 | 
				
			||||||
	length = E->value.size();
 | 
						length = E->value.size();
 | 
				
			||||||
| 
						 | 
					@ -122,18 +120,12 @@ bool FileAccessMemory::eof_reached() const {
 | 
				
			||||||
	return pos >= length;
 | 
						return pos >= length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t FileAccessMemory::get_8() const {
 | 
					 | 
				
			||||||
	uint8_t ret = 0;
 | 
					 | 
				
			||||||
	if (pos < length) {
 | 
					 | 
				
			||||||
		ret = data[pos];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	++pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
						if (!p_length) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(p_dst, -1);
 | 
				
			||||||
	ERR_FAIL_NULL_V(data, -1);
 | 
						ERR_FAIL_NULL_V(data, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t left = length - pos;
 | 
						uint64_t left = length - pos;
 | 
				
			||||||
| 
						 | 
					@ -157,20 +149,20 @@ void FileAccessMemory::flush() {
 | 
				
			||||||
	ERR_FAIL_NULL(data);
 | 
						ERR_FAIL_NULL(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessMemory::store_8(uint8_t p_byte) {
 | 
					bool FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
	ERR_FAIL_NULL(data);
 | 
						if (!p_length) {
 | 
				
			||||||
	ERR_FAIL_COND(pos >= length);
 | 
							return true;
 | 
				
			||||||
	data[pos++] = p_byte;
 | 
						}
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(p_src, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND(!p_src && p_length > 0);
 | 
					 | 
				
			||||||
	uint64_t left = length - pos;
 | 
						uint64_t left = length - pos;
 | 
				
			||||||
	uint64_t write = MIN(p_length, left);
 | 
						uint64_t write = MIN(p_length, left);
 | 
				
			||||||
	if (write < p_length) {
 | 
					 | 
				
			||||||
		WARN_PRINT("Writing less data than requested");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(&data[pos], p_src, write);
 | 
						memcpy(&data[pos], p_src, write);
 | 
				
			||||||
	pos += write;
 | 
						pos += write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(write < p_length, false, "Writing less data than requested.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,16 +55,13 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const override; ///< reading passed EOF
 | 
						virtual bool eof_reached() const override; ///< reading passed EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const override; ///< get a byte
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; ///< get an array of bytes
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; ///< get an array of bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error get_error() const override; ///< get last error
 | 
						virtual Error get_error() const override; ///< get last error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
						virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
				
			||||||
	virtual void flush() override;
 | 
						virtual void flush() override;
 | 
				
			||||||
	virtual void store_8(uint8_t p_byte) override; ///< store a byte
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
 | 
				
			||||||
	virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
						virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,6 @@
 | 
				
			||||||
#include "core/os/os.h"
 | 
					#include "core/os/os.h"
 | 
				
			||||||
#include "core/version.h"
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
 | 
					Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
 | 
				
			||||||
	for (int i = 0; i < sources.size(); i++) {
 | 
						for (int i = 0; i < sources.size(); i++) {
 | 
				
			||||||
		if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
 | 
							if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
 | 
				
			||||||
| 
						 | 
					@ -48,7 +46,7 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
 | 
					void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
 | 
				
			||||||
	String simplified_path = p_path.simplify_path();
 | 
						String simplified_path = p_path.simplify_path().trim_prefix("res://");
 | 
				
			||||||
	PathMD5 pmd5(simplified_path.md5_buffer());
 | 
						PathMD5 pmd5(simplified_path.md5_buffer());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool exists = files.has(pmd5);
 | 
						bool exists = files.has(pmd5);
 | 
				
			||||||
| 
						 | 
					@ -68,13 +66,11 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!exists) {
 | 
						if (!exists) {
 | 
				
			||||||
		//search for dir
 | 
							// Search for directory.
 | 
				
			||||||
		String p = simplified_path.replace_first("res://", "");
 | 
					 | 
				
			||||||
		PackedDir *cd = root;
 | 
							PackedDir *cd = root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p.contains("/")) { //in a subdir
 | 
							if (simplified_path.contains_char('/')) { // In a subdirectory.
 | 
				
			||||||
 | 
								Vector<String> ds = simplified_path.get_base_dir().split("/");
 | 
				
			||||||
			Vector<String> ds = p.get_base_dir().split("/");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (int j = 0; j < ds.size(); j++) {
 | 
								for (int j = 0; j < ds.size(); j++) {
 | 
				
			||||||
				if (!cd->subdirs.has(ds[j])) {
 | 
									if (!cd->subdirs.has(ds[j])) {
 | 
				
			||||||
| 
						 | 
					@ -89,19 +85,79 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		String filename = simplified_path.get_file();
 | 
							String filename = simplified_path.get_file();
 | 
				
			||||||
		// Don't add as a file if the path points to a directory
 | 
							// Don't add as a file if the path points to a directory.
 | 
				
			||||||
		if (!filename.is_empty()) {
 | 
							if (!filename.is_empty()) {
 | 
				
			||||||
			cd->files.insert(filename);
 | 
								cd->files.insert(filename);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PackedData::remove_path(const String &p_path) {
 | 
				
			||||||
 | 
						String simplified_path = p_path.simplify_path().trim_prefix("res://");
 | 
				
			||||||
 | 
						PathMD5 pmd5(simplified_path.md5_buffer());
 | 
				
			||||||
 | 
						if (!files.has(pmd5)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Search for directory.
 | 
				
			||||||
 | 
						PackedDir *cd = root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (simplified_path.contains_char('/')) { // In a subdirectory.
 | 
				
			||||||
 | 
							Vector<String> ds = simplified_path.get_base_dir().split("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int j = 0; j < ds.size(); j++) {
 | 
				
			||||||
 | 
								if (!cd->subdirs.has(ds[j])) {
 | 
				
			||||||
 | 
									return; // Subdirectory does not exist, do not bother creating.
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									cd = cd->subdirs[ds[j]];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd->files.erase(simplified_path.get_file());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						files.erase(pmd5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PackedData::add_pack_source(PackSource *p_source) {
 | 
					void PackedData::add_pack_source(PackSource *p_source) {
 | 
				
			||||||
	if (p_source != nullptr) {
 | 
						if (p_source != nullptr) {
 | 
				
			||||||
		sources.push_back(p_source);
 | 
							sources.push_back(p_source);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t *PackedData::get_file_hash(const String &p_path) {
 | 
				
			||||||
 | 
						String simplified_path = p_path.simplify_path().trim_prefix("res://");
 | 
				
			||||||
 | 
						PathMD5 pmd5(simplified_path.md5_buffer());
 | 
				
			||||||
 | 
						HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
 | 
				
			||||||
 | 
						if (!E) {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return E->value.md5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HashSet<String> PackedData::get_file_paths() const {
 | 
				
			||||||
 | 
						HashSet<String> file_paths;
 | 
				
			||||||
 | 
						_get_file_paths(root, root->name, file_paths);
 | 
				
			||||||
 | 
						return file_paths;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PackedData::_get_file_paths(PackedDir *p_dir, const String &p_parent_dir, HashSet<String> &r_paths) const {
 | 
				
			||||||
 | 
						for (const String &E : p_dir->files) {
 | 
				
			||||||
 | 
							r_paths.insert(p_parent_dir.path_join(E));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, PackedDir *> &E : p_dir->subdirs) {
 | 
				
			||||||
 | 
							_get_file_paths(E.value, p_parent_dir.path_join(E.key), r_paths);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PackedData::clear() {
 | 
				
			||||||
 | 
						files.clear();
 | 
				
			||||||
 | 
						_free_packed_dirs(root);
 | 
				
			||||||
 | 
						root = memnew(PackedDir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PackedData *PackedData::singleton = nullptr;
 | 
					PackedData *PackedData::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PackedData::PackedData() {
 | 
					PackedData::PackedData() {
 | 
				
			||||||
| 
						 | 
					@ -207,8 +263,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
 | 
				
			||||||
	uint32_t ver_minor = f->get_32();
 | 
						uint32_t ver_minor = f->get_32();
 | 
				
			||||||
	f->get_32(); // patch number, not used for validation.
 | 
						f->get_32(); // patch number, not used for validation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, "Pack version unsupported: " + itos(version) + ".");
 | 
						ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, vformat("Pack version unsupported: %d.", version));
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
 | 
						ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t pack_flags = f->get_32();
 | 
						uint32_t pack_flags = f->get_32();
 | 
				
			||||||
	uint64_t file_base = f->get_64();
 | 
						uint64_t file_base = f->get_64();
 | 
				
			||||||
| 
						 | 
					@ -251,15 +307,19 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
 | 
				
			||||||
		cs[sl] = 0;
 | 
							cs[sl] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		String path;
 | 
							String path;
 | 
				
			||||||
		path.parse_utf8(cs.ptr());
 | 
							path.parse_utf8(cs.ptr(), sl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint64_t ofs = file_base + f->get_64();
 | 
							uint64_t ofs = f->get_64();
 | 
				
			||||||
		uint64_t size = f->get_64();
 | 
							uint64_t size = f->get_64();
 | 
				
			||||||
		uint8_t md5[16];
 | 
							uint8_t md5[16];
 | 
				
			||||||
		f->get_buffer(md5, 16);
 | 
							f->get_buffer(md5, 16);
 | 
				
			||||||
		uint32_t flags = f->get_32();
 | 
							uint32_t flags = f->get_32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED));
 | 
							if (flags & PACK_FILE_REMOVAL) { // The file was removed.
 | 
				
			||||||
 | 
								PackedData::get_singleton()->remove_path(path);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								PackedData::get_singleton()->add_path(p_path, path, file_base + ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
| 
						 | 
					@ -271,6 +331,44 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//////////////////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
 | 
				
			||||||
 | 
						// Load with offset feature only supported for PCK files.
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with directories.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_path != "res://") {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						add_directory(p_path, p_replace_files);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file) {
 | 
				
			||||||
 | 
						Ref<FileAccess> ret = FileAccess::create_for_path(p_path);
 | 
				
			||||||
 | 
						ret->reopen(p_path, FileAccess::READ);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PackedSourceDirectory::add_directory(const String &p_path, bool p_replace_files) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = DirAccess::open(p_path);
 | 
				
			||||||
 | 
						if (da.is_null()) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						da->set_include_hidden(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const String &file_name : da->get_files()) {
 | 
				
			||||||
 | 
							String file_path = p_path.path_join(file_name);
 | 
				
			||||||
 | 
							uint8_t md5[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | 
				
			||||||
 | 
							PackedData::get_singleton()->add_path(p_path, file_path, 0, 0, md5, this, p_replace_files, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const String &sub_dir_name : da->get_directories()) {
 | 
				
			||||||
 | 
							String sub_dir_path = p_path.path_join(sub_dir_name);
 | 
				
			||||||
 | 
							add_directory(sub_dir_path, p_replace_files);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
 | 
					Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
 | 
				
			||||||
	ERR_PRINT("Can't open pack-referenced file.");
 | 
						ERR_PRINT("Can't open pack-referenced file.");
 | 
				
			||||||
	return ERR_UNAVAILABLE;
 | 
						return ERR_UNAVAILABLE;
 | 
				
			||||||
| 
						 | 
					@ -313,17 +411,6 @@ bool FileAccessPack::eof_reached() const {
 | 
				
			||||||
	return eof;
 | 
						return eof;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t FileAccessPack::get_8() const {
 | 
					 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
 | 
					 | 
				
			||||||
	if (pos >= pf.size) {
 | 
					 | 
				
			||||||
		eof = true;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pos++;
 | 
					 | 
				
			||||||
	return f->get_8();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
 | 
						ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
						ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
				
			||||||
| 
						 | 
					@ -366,12 +453,8 @@ void FileAccessPack::flush() {
 | 
				
			||||||
	ERR_FAIL();
 | 
						ERR_FAIL();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessPack::store_8(uint8_t p_dest) {
 | 
					bool FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
	ERR_FAIL();
 | 
						ERR_FAIL_V(false);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
					 | 
				
			||||||
	ERR_FAIL();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool FileAccessPack::file_exists(const String &p_name) {
 | 
					bool FileAccessPack::file_exists(const String &p_name) {
 | 
				
			||||||
| 
						 | 
					@ -385,7 +468,7 @@ void FileAccessPack::close() {
 | 
				
			||||||
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) :
 | 
					FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) :
 | 
				
			||||||
		pf(p_file),
 | 
							pf(p_file),
 | 
				
			||||||
		f(FileAccess::open(pf.pack, FileAccess::READ)) {
 | 
							f(FileAccess::open(pf.pack, FileAccess::READ)) {
 | 
				
			||||||
	ERR_FAIL_COND_MSG(f.is_null(), "Can't open pack-referenced file '" + String(pf.pack) + "'.");
 | 
						ERR_FAIL_COND_MSG(f.is_null(), vformat("Can't open pack-referenced file '%s'.", String(pf.pack)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f->seek(pf.offset);
 | 
						f->seek(pf.offset);
 | 
				
			||||||
	off = pf.offset;
 | 
						off = pf.offset;
 | 
				
			||||||
| 
						 | 
					@ -393,7 +476,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
 | 
				
			||||||
	if (pf.encrypted) {
 | 
						if (pf.encrypted) {
 | 
				
			||||||
		Ref<FileAccessEncrypted> fae;
 | 
							Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
		fae.instantiate();
 | 
							fae.instantiate();
 | 
				
			||||||
		ERR_FAIL_COND_MSG(fae.is_null(), "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
 | 
							ERR_FAIL_COND_MSG(fae.is_null(), vformat("Can't open encrypted pack-referenced file '%s'.", String(pf.pack)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Vector<uint8_t> key;
 | 
							Vector<uint8_t> key;
 | 
				
			||||||
		key.resize(32);
 | 
							key.resize(32);
 | 
				
			||||||
| 
						 | 
					@ -402,7 +485,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
 | 
							Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
 | 
				
			||||||
		ERR_FAIL_COND_MSG(err, "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
 | 
							ERR_FAIL_COND_MSG(err, vformat("Can't open encrypted pack-referenced file '%s'.", String(pf.pack)));
 | 
				
			||||||
		f = fae;
 | 
							f = fae;
 | 
				
			||||||
		off = 0;
 | 
							off = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -543,8 +626,6 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool DirAccessPack::file_exists(String p_file) {
 | 
					bool DirAccessPack::file_exists(String p_file) {
 | 
				
			||||||
	p_file = fix_path(p_file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PackedData::PackedDir *pd = _find_dir(p_file.get_base_dir());
 | 
						PackedData::PackedDir *pd = _find_dir(p_file.get_base_dir());
 | 
				
			||||||
	if (!pd) {
 | 
						if (!pd) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -553,8 +634,6 @@ bool DirAccessPack::file_exists(String p_file) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool DirAccessPack::dir_exists(String p_dir) {
 | 
					bool DirAccessPack::dir_exists(String p_dir) {
 | 
				
			||||||
	p_dir = fix_path(p_dir);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return _find_dir(p_dir) != nullptr;
 | 
						return _find_dir(p_dir) != nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@
 | 
				
			||||||
#include "core/string/print_string.h"
 | 
					#include "core/string/print_string.h"
 | 
				
			||||||
#include "core/templates/hash_set.h"
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
#include "core/templates/list.h"
 | 
					#include "core/templates/list.h"
 | 
				
			||||||
#include "core/templates/rb_map.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Godot's packed file magic header ("GDPC" in ASCII).
 | 
					// Godot's packed file magic header ("GDPC" in ASCII).
 | 
				
			||||||
#define PACK_HEADER_MAGIC 0x43504447
 | 
					#define PACK_HEADER_MAGIC 0x43504447
 | 
				
			||||||
| 
						 | 
					@ -49,7 +48,8 @@ enum PackFlags {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum PackFileFlags {
 | 
					enum PackFileFlags {
 | 
				
			||||||
	PACK_FILE_ENCRYPTED = 1 << 0
 | 
						PACK_FILE_ENCRYPTED = 1 << 0,
 | 
				
			||||||
 | 
						PACK_FILE_REMOVAL = 1 << 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PackSource;
 | 
					class PackSource;
 | 
				
			||||||
| 
						 | 
					@ -107,10 +107,14 @@ private:
 | 
				
			||||||
	bool disabled = false;
 | 
						bool disabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void _free_packed_dirs(PackedDir *p_dir);
 | 
						void _free_packed_dirs(PackedDir *p_dir);
 | 
				
			||||||
 | 
						void _get_file_paths(PackedDir *p_dir, const String &p_parent_dir, HashSet<String> &r_paths) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	void add_pack_source(PackSource *p_source);
 | 
						void add_pack_source(PackSource *p_source);
 | 
				
			||||||
	void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
 | 
						void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
 | 
				
			||||||
 | 
						void remove_path(const String &p_path);
 | 
				
			||||||
 | 
						uint8_t *get_file_hash(const String &p_path);
 | 
				
			||||||
 | 
						HashSet<String> get_file_paths() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_disabled(bool p_disabled) { disabled = p_disabled; }
 | 
						void set_disabled(bool p_disabled) { disabled = p_disabled; }
 | 
				
			||||||
	_FORCE_INLINE_ bool is_disabled() const { return disabled; }
 | 
						_FORCE_INLINE_ bool is_disabled() const { return disabled; }
 | 
				
			||||||
| 
						 | 
					@ -118,6 +122,8 @@ public:
 | 
				
			||||||
	static PackedData *get_singleton() { return singleton; }
 | 
						static PackedData *get_singleton() { return singleton; }
 | 
				
			||||||
	Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
 | 
						Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
 | 
						_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
 | 
				
			||||||
	_FORCE_INLINE_ bool has_path(const String &p_path);
 | 
						_FORCE_INLINE_ bool has_path(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,6 +147,14 @@ public:
 | 
				
			||||||
	virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
 | 
						virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PackedSourceDirectory : public PackSource {
 | 
				
			||||||
 | 
						void add_directory(const String &p_path, bool p_replace_files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
 | 
				
			||||||
 | 
						virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FileAccessPack : public FileAccess {
 | 
					class FileAccessPack : public FileAccess {
 | 
				
			||||||
	PackedData::PackedFile pf;
 | 
						PackedData::PackedFile pf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,8 +183,6 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const override;
 | 
						virtual bool eof_reached() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void set_big_endian(bool p_big_endian) override;
 | 
						virtual void set_big_endian(bool p_big_endian) override;
 | 
				
			||||||
| 
						 | 
					@ -179,9 +191,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
						virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
				
			||||||
	virtual void flush() override;
 | 
						virtual void flush() override;
 | 
				
			||||||
	virtual void store_8(uint8_t p_dest) override;
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(const String &p_name) override;
 | 
						virtual bool file_exists(const String &p_name) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,21 +201,18 @@ public:
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
 | 
					Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
 | 
				
			||||||
	String simplified_path = p_path.simplify_path();
 | 
						String simplified_path = p_path.simplify_path().trim_prefix("res://");
 | 
				
			||||||
	PathMD5 pmd5(simplified_path.md5_buffer());
 | 
						PathMD5 pmd5(simplified_path.md5_buffer());
 | 
				
			||||||
	HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
 | 
						HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
 | 
				
			||||||
	if (!E) {
 | 
						if (!E) {
 | 
				
			||||||
		return nullptr; //not found
 | 
							return nullptr; // Not found.
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (E->value.offset == 0) {
 | 
					 | 
				
			||||||
		return nullptr; //was erased
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return E->value.src->get_file(p_path, &E->value);
 | 
						return E->value.src->get_file(p_path, &E->value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool PackedData::has_path(const String &p_path) {
 | 
					bool PackedData::has_path(const String &p_path) {
 | 
				
			||||||
	return files.has(PathMD5(p_path.simplify_path().md5_buffer()));
 | 
						return files.has(PathMD5(p_path.simplify_path().trim_prefix("res://").md5_buffer()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool PackedData::has_directory(const String &p_path) {
 | 
					bool PackedData::has_directory(const String &p_path) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,7 +116,7 @@ void ZipArchive::close_handle(unzFile p_file) const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unzFile ZipArchive::get_file_handle(const String &p_file) const {
 | 
					unzFile ZipArchive::get_file_handle(const String &p_file) const {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(!file_exists(p_file), nullptr, "File '" + p_file + " doesn't exist.");
 | 
						ERR_FAIL_COND_V_MSG(!file_exists(p_file), nullptr, vformat("File '%s' doesn't exist.", p_file));
 | 
				
			||||||
	File file = files[p_file];
 | 
						File file = files[p_file];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	zlib_filefunc_def io;
 | 
						zlib_filefunc_def io;
 | 
				
			||||||
| 
						 | 
					@ -136,7 +136,7 @@ unzFile ZipArchive::get_file_handle(const String &p_file) const {
 | 
				
			||||||
	io.free_mem = godot_free;
 | 
						io.free_mem = godot_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
 | 
						unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
 | 
				
			||||||
	ERR_FAIL_NULL_V_MSG(pkg, nullptr, "Cannot open file '" + packages[file.package].filename + "'.");
 | 
						ERR_FAIL_NULL_V_MSG(pkg, nullptr, vformat("Cannot open file '%s'.", packages[file.package].filename));
 | 
				
			||||||
	int unz_err = unzGoToFilePos(pkg, &file.file_pos);
 | 
						int unz_err = unzGoToFilePos(pkg, &file.file_pos);
 | 
				
			||||||
	if (unz_err != UNZ_OK || unzOpenCurrentFile(pkg) != UNZ_OK) {
 | 
						if (unz_err != UNZ_OK || unzOpenCurrentFile(pkg) != UNZ_OK) {
 | 
				
			||||||
		unzClose(pkg);
 | 
							unzClose(pkg);
 | 
				
			||||||
| 
						 | 
					@ -291,12 +291,6 @@ bool FileAccessZip::eof_reached() const {
 | 
				
			||||||
	return at_eof;
 | 
						return at_eof;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t FileAccessZip::get_8() const {
 | 
					 | 
				
			||||||
	uint8_t ret = 0;
 | 
					 | 
				
			||||||
	get_buffer(&ret, 1);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t FileAccessZip::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
					uint64_t FileAccessZip::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 | 
				
			||||||
	ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
						ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
 | 
				
			||||||
	ERR_FAIL_NULL_V(zfile, -1);
 | 
						ERR_FAIL_NULL_V(zfile, -1);
 | 
				
			||||||
| 
						 | 
					@ -328,8 +322,8 @@ void FileAccessZip::flush() {
 | 
				
			||||||
	ERR_FAIL();
 | 
						ERR_FAIL();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileAccessZip::store_8(uint8_t p_dest) {
 | 
					bool FileAccessZip::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 | 
				
			||||||
	ERR_FAIL();
 | 
						ERR_FAIL_V(false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool FileAccessZip::file_exists(const String &p_name) {
 | 
					bool FileAccessZip::file_exists(const String &p_name) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,12 +34,9 @@
 | 
				
			||||||
#ifdef MINIZIP_ENABLED
 | 
					#ifdef MINIZIP_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/io/file_access_pack.h"
 | 
					#include "core/io/file_access_pack.h"
 | 
				
			||||||
#include "core/templates/rb_map.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "thirdparty/minizip/unzip.h"
 | 
					#include "thirdparty/minizip/unzip.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ZipArchive : public PackSource {
 | 
					class ZipArchive : public PackSource {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	struct File {
 | 
						struct File {
 | 
				
			||||||
| 
						 | 
					@ -95,14 +92,13 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool eof_reached() const override; ///< reading passed EOF
 | 
						virtual bool eof_reached() const override; ///< reading passed EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual uint8_t get_8() const override; ///< get a byte
 | 
					 | 
				
			||||||
	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
						virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error get_error() const override; ///< get last error
 | 
						virtual Error get_error() const override; ///< get last error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
						virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
 | 
				
			||||||
	virtual void flush() override;
 | 
						virtual void flush() override;
 | 
				
			||||||
	virtual void store_8(uint8_t p_dest) override; ///< store a byte
 | 
						virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
						virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,9 +42,9 @@ const char *HTTPClient::_methods[METHOD_MAX] = {
 | 
				
			||||||
	"PATCH"
 | 
						"PATCH"
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HTTPClient *HTTPClient::create() {
 | 
					HTTPClient *HTTPClient::create(bool p_notify_postinitialize) {
 | 
				
			||||||
	if (_create) {
 | 
						if (_create) {
 | 
				
			||||||
		return _create();
 | 
							return _create(p_notify_postinitialize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -100,9 +100,9 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
Error HTTPClient::verify_headers(const Vector<String> &p_headers) {
 | 
					Error HTTPClient::verify_headers(const Vector<String> &p_headers) {
 | 
				
			||||||
	for (int i = 0; i < p_headers.size(); i++) {
 | 
						for (int i = 0; i < p_headers.size(); i++) {
 | 
				
			||||||
		String sanitized = p_headers[i].strip_edges();
 | 
							String sanitized = p_headers[i].strip_edges();
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, "Invalid HTTP header at index " + itos(i) + ": empty.");
 | 
							ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, vformat("Invalid HTTP header at index %d: empty.", i));
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(sanitized.find(":") < 1, ERR_INVALID_PARAMETER,
 | 
							ERR_FAIL_COND_V_MSG(sanitized.find_char(':') < 1, ERR_INVALID_PARAMETER,
 | 
				
			||||||
				"Invalid HTTP header at index " + itos(i) + ": String must contain header-value pair, delimited by ':', but was: " + p_headers[i]);
 | 
									vformat("Invalid HTTP header at index %d: String must contain header-value pair, delimited by ':', but was: '%s'.", i, p_headers[i]));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return OK;
 | 
						return OK;
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() {
 | 
				
			||||||
	get_response_headers(&rh);
 | 
						get_response_headers(&rh);
 | 
				
			||||||
	Dictionary ret;
 | 
						Dictionary ret;
 | 
				
			||||||
	for (const String &s : rh) {
 | 
						for (const String &s : rh) {
 | 
				
			||||||
		int sp = s.find(":");
 | 
							int sp = s.find_char(':');
 | 
				
			||||||
		if (sp == -1) {
 | 
							if (sp == -1) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,12 +158,12 @@ protected:
 | 
				
			||||||
	Error _request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body);
 | 
						Error _request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body);
 | 
				
			||||||
	Error _request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String());
 | 
						Error _request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static HTTPClient *(*_create)();
 | 
						static HTTPClient *(*_create)(bool p_notify_postinitialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static HTTPClient *create();
 | 
						static HTTPClient *create(bool p_notify_postinitialize = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String query_string_from_dict(const Dictionary &p_dict);
 | 
						String query_string_from_dict(const Dictionary &p_dict);
 | 
				
			||||||
	Error verify_headers(const Vector<String> &p_headers);
 | 
						Error verify_headers(const Vector<String> &p_headers);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,8 @@
 | 
				
			||||||
#include "core/io/stream_peer_tls.h"
 | 
					#include "core/io/stream_peer_tls.h"
 | 
				
			||||||
#include "core/version.h"
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HTTPClient *HTTPClientTCP::_create_func() {
 | 
					HTTPClient *HTTPClientTCP::_create_func(bool p_notify_postinitialize) {
 | 
				
			||||||
	return memnew(HTTPClientTCP);
 | 
						return static_cast<HTTPClient *>(ClassDB::creator<HTTPClientTCP>(p_notify_postinitialize));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, Ref<TLSOptions> p_options) {
 | 
					Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, Ref<TLSOptions> p_options) {
 | 
				
			||||||
| 
						 | 
					@ -484,7 +484,7 @@ Error HTTPClientTCP::poll() {
 | 
				
			||||||
					// End of response, parse.
 | 
										// End of response, parse.
 | 
				
			||||||
					response_str.push_back(0);
 | 
										response_str.push_back(0);
 | 
				
			||||||
					String response;
 | 
										String response;
 | 
				
			||||||
					response.parse_utf8((const char *)response_str.ptr());
 | 
										response.parse_utf8((const char *)response_str.ptr(), response_str.size());
 | 
				
			||||||
					Vector<String> responses = response.split("\n");
 | 
										Vector<String> responses = response.split("\n");
 | 
				
			||||||
					body_size = -1;
 | 
										body_size = -1;
 | 
				
			||||||
					chunked = false;
 | 
										chunked = false;
 | 
				
			||||||
| 
						 | 
					@ -508,11 +508,11 @@ Error HTTPClientTCP::poll() {
 | 
				
			||||||
							continue;
 | 
												continue;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						if (s.begins_with("content-length:")) {
 | 
											if (s.begins_with("content-length:")) {
 | 
				
			||||||
							body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int();
 | 
												body_size = s.substr(s.find_char(':') + 1, s.length()).strip_edges().to_int();
 | 
				
			||||||
							body_left = body_size;
 | 
												body_left = body_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						} else if (s.begins_with("transfer-encoding:")) {
 | 
											} else if (s.begins_with("transfer-encoding:")) {
 | 
				
			||||||
							String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
 | 
												String encoding = header.substr(header.find_char(':') + 1, header.length()).strip_edges();
 | 
				
			||||||
							if (encoding == "chunked") {
 | 
												if (encoding == "chunked") {
 | 
				
			||||||
								chunked = true;
 | 
													chunked = true;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
| 
						 | 
					@ -662,15 +662,16 @@ PackedByteArray HTTPClientTCP::read_response_body_chunk() {
 | 
				
			||||||
				chunk_left -= rec;
 | 
									chunk_left -= rec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (chunk_left == 0) {
 | 
									if (chunk_left == 0) {
 | 
				
			||||||
					if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') {
 | 
										const int chunk_size = chunk.size();
 | 
				
			||||||
 | 
										if (chunk[chunk_size - 2] != '\r' || chunk[chunk_size - 1] != '\n') {
 | 
				
			||||||
						ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)");
 | 
											ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)");
 | 
				
			||||||
						status = STATUS_CONNECTION_ERROR;
 | 
											status = STATUS_CONNECTION_ERROR;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					ret.resize(chunk.size() - 2);
 | 
										ret.resize(chunk_size - 2);
 | 
				
			||||||
					uint8_t *w = ret.ptrw();
 | 
										uint8_t *w = ret.ptrw();
 | 
				
			||||||
					memcpy(w, chunk.ptr(), chunk.size() - 2);
 | 
										memcpy(w, chunk.ptr(), chunk_size - 2);
 | 
				
			||||||
					chunk.clear();
 | 
										chunk.clear();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -792,6 +793,6 @@ HTTPClientTCP::HTTPClientTCP() {
 | 
				
			||||||
	request_buffer.instantiate();
 | 
						request_buffer.instantiate();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func;
 | 
					HTTPClient *(*HTTPClient::_create)(bool p_notify_postinitialize) = HTTPClientTCP::_create_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // WEB_ENABLED
 | 
					#endif // WEB_ENABLED
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ private:
 | 
				
			||||||
	Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received);
 | 
						Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static HTTPClient *_create_func();
 | 
						static HTTPClient *_create_func(bool p_notify_postinitialize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override;
 | 
						Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -33,7 +33,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/io/resource.h"
 | 
					#include "core/io/resource.h"
 | 
				
			||||||
#include "core/math/color.h"
 | 
					#include "core/math/color.h"
 | 
				
			||||||
#include "core/math/rect2.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Image storage class. This is used to store an image in user memory, as well as
 | 
					 * Image storage class. This is used to store an image in user memory, as well as
 | 
				
			||||||
| 
						 | 
					@ -43,12 +42,17 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Image;
 | 
					class Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function pointer prototypes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
 | 
					typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
 | 
				
			||||||
typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
 | 
					typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
 | 
					typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
 | 
				
			||||||
typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
 | 
					typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
 | 
					typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
 | 
				
			||||||
typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
 | 
					typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
 | 
					typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
 | 
				
			||||||
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
 | 
					typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,57 +63,48 @@ class Image : public Resource {
 | 
				
			||||||
	GDCLASS(Image, Resource);
 | 
						GDCLASS(Image, Resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static SavePNGFunc save_png_func;
 | 
					 | 
				
			||||||
	static SaveJPGFunc save_jpg_func;
 | 
					 | 
				
			||||||
	static SaveEXRFunc save_exr_func;
 | 
					 | 
				
			||||||
	static SavePNGBufferFunc save_png_buffer_func;
 | 
					 | 
				
			||||||
	static SaveEXRBufferFunc save_exr_buffer_func;
 | 
					 | 
				
			||||||
	static SaveJPGBufferFunc save_jpg_buffer_func;
 | 
					 | 
				
			||||||
	static SaveWebPFunc save_webp_func;
 | 
					 | 
				
			||||||
	static SaveWebPBufferFunc save_webp_buffer_func;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum {
 | 
						enum {
 | 
				
			||||||
		MAX_WIDTH = (1 << 24), // force a limit somehow
 | 
							MAX_WIDTH = (1 << 24), // Force a limit somehow.
 | 
				
			||||||
		MAX_HEIGHT = (1 << 24), // force a limit somehow
 | 
							MAX_HEIGHT = (1 << 24), // Force a limit somehow.
 | 
				
			||||||
		MAX_PIXELS = 268435456
 | 
							MAX_PIXELS = 268435456 // 16384 ^ 2
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum Format {
 | 
						enum Format : int32_t {
 | 
				
			||||||
		FORMAT_L8, //luminance
 | 
							FORMAT_L8, // Luminance
 | 
				
			||||||
		FORMAT_LA8, //luminance-alpha
 | 
							FORMAT_LA8, // Luminance-Alpha
 | 
				
			||||||
		FORMAT_R8,
 | 
							FORMAT_R8,
 | 
				
			||||||
		FORMAT_RG8,
 | 
							FORMAT_RG8,
 | 
				
			||||||
		FORMAT_RGB8,
 | 
							FORMAT_RGB8,
 | 
				
			||||||
		FORMAT_RGBA8,
 | 
							FORMAT_RGBA8,
 | 
				
			||||||
		FORMAT_RGBA4444,
 | 
							FORMAT_RGBA4444,
 | 
				
			||||||
		FORMAT_RGB565,
 | 
							FORMAT_RGB565,
 | 
				
			||||||
		FORMAT_RF, //float
 | 
							FORMAT_RF, // Float
 | 
				
			||||||
		FORMAT_RGF,
 | 
							FORMAT_RGF,
 | 
				
			||||||
		FORMAT_RGBF,
 | 
							FORMAT_RGBF,
 | 
				
			||||||
		FORMAT_RGBAF,
 | 
							FORMAT_RGBAF,
 | 
				
			||||||
		FORMAT_RH, //half float
 | 
							FORMAT_RH, // Half
 | 
				
			||||||
		FORMAT_RGH,
 | 
							FORMAT_RGH,
 | 
				
			||||||
		FORMAT_RGBH,
 | 
							FORMAT_RGBH,
 | 
				
			||||||
		FORMAT_RGBAH,
 | 
							FORMAT_RGBAH,
 | 
				
			||||||
		FORMAT_RGBE9995,
 | 
							FORMAT_RGBE9995,
 | 
				
			||||||
		FORMAT_DXT1, //s3tc bc1
 | 
							FORMAT_DXT1, // BC1
 | 
				
			||||||
		FORMAT_DXT3, //bc2
 | 
							FORMAT_DXT3, // BC2
 | 
				
			||||||
		FORMAT_DXT5, //bc3
 | 
							FORMAT_DXT5, // BC3
 | 
				
			||||||
		FORMAT_RGTC_R,
 | 
							FORMAT_RGTC_R, // BC4
 | 
				
			||||||
		FORMAT_RGTC_RG,
 | 
							FORMAT_RGTC_RG, // BC5
 | 
				
			||||||
		FORMAT_BPTC_RGBA, //btpc bc7
 | 
							FORMAT_BPTC_RGBA, // BC7
 | 
				
			||||||
		FORMAT_BPTC_RGBF, //float bc6h
 | 
							FORMAT_BPTC_RGBF, // BC6 Signed
 | 
				
			||||||
		FORMAT_BPTC_RGBFU, //unsigned float bc6hu
 | 
							FORMAT_BPTC_RGBFU, // BC6 Unsigned
 | 
				
			||||||
		FORMAT_ETC, //etc1
 | 
							FORMAT_ETC, // ETC1
 | 
				
			||||||
		FORMAT_ETC2_R11, //etc2
 | 
							FORMAT_ETC2_R11,
 | 
				
			||||||
		FORMAT_ETC2_R11S, //signed, NOT srgb.
 | 
							FORMAT_ETC2_R11S, // Signed, NOT srgb.
 | 
				
			||||||
		FORMAT_ETC2_RG11,
 | 
							FORMAT_ETC2_RG11,
 | 
				
			||||||
		FORMAT_ETC2_RG11S,
 | 
							FORMAT_ETC2_RG11S, // Signed, NOT srgb.
 | 
				
			||||||
		FORMAT_ETC2_RGB8,
 | 
							FORMAT_ETC2_RGB8,
 | 
				
			||||||
		FORMAT_ETC2_RGBA8,
 | 
							FORMAT_ETC2_RGBA8,
 | 
				
			||||||
		FORMAT_ETC2_RGB8A1,
 | 
							FORMAT_ETC2_RGB8A1,
 | 
				
			||||||
		FORMAT_ETC2_RA_AS_RG, //used to make basis universal happy
 | 
							FORMAT_ETC2_RA_AS_RG, // ETC2 RGBA with a RA-RG swizzle for normal maps.
 | 
				
			||||||
		FORMAT_DXT5_RA_AS_RG, //used to make basis universal happy
 | 
							FORMAT_DXT5_RA_AS_RG, // BC3 with a RA-RG swizzle for normal maps.
 | 
				
			||||||
		FORMAT_ASTC_4x4,
 | 
							FORMAT_ASTC_4x4,
 | 
				
			||||||
		FORMAT_ASTC_4x4_HDR,
 | 
							FORMAT_ASTC_4x4_HDR,
 | 
				
			||||||
		FORMAT_ASTC_8x8,
 | 
							FORMAT_ASTC_8x8,
 | 
				
			||||||
| 
						 | 
					@ -118,17 +113,18 @@ public:
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static const char *format_names[FORMAT_MAX];
 | 
						static const char *format_names[FORMAT_MAX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum Interpolation {
 | 
						enum Interpolation {
 | 
				
			||||||
		INTERPOLATE_NEAREST,
 | 
							INTERPOLATE_NEAREST,
 | 
				
			||||||
		INTERPOLATE_BILINEAR,
 | 
							INTERPOLATE_BILINEAR,
 | 
				
			||||||
		INTERPOLATE_CUBIC,
 | 
							INTERPOLATE_CUBIC,
 | 
				
			||||||
		INTERPOLATE_TRILINEAR,
 | 
							INTERPOLATE_TRILINEAR,
 | 
				
			||||||
		INTERPOLATE_LANCZOS,
 | 
							INTERPOLATE_LANCZOS,
 | 
				
			||||||
		/* INTERPOLATE_TRICUBIC, */
 | 
							// INTERPOLATE_TRICUBIC,
 | 
				
			||||||
		/* INTERPOLATE GAUSS */
 | 
							// INTERPOLATE_GAUSS
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//this is used for compression
 | 
						// Used for obtaining optimal compression quality.
 | 
				
			||||||
	enum UsedChannels {
 | 
						enum UsedChannels {
 | 
				
			||||||
		USED_CHANNELS_L,
 | 
							USED_CHANNELS_L,
 | 
				
			||||||
		USED_CHANNELS_LA,
 | 
							USED_CHANNELS_LA,
 | 
				
			||||||
| 
						 | 
					@ -137,13 +133,66 @@ public:
 | 
				
			||||||
		USED_CHANNELS_RGB,
 | 
							USED_CHANNELS_RGB,
 | 
				
			||||||
		USED_CHANNELS_RGBA,
 | 
							USED_CHANNELS_RGBA,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	//some functions provided by something else
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ASTC supports block formats other than 4x4.
 | 
				
			||||||
	enum ASTCFormat {
 | 
						enum ASTCFormat {
 | 
				
			||||||
		ASTC_FORMAT_4x4,
 | 
							ASTC_FORMAT_4x4,
 | 
				
			||||||
		ASTC_FORMAT_8x8,
 | 
							ASTC_FORMAT_8x8,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum RoughnessChannel {
 | 
				
			||||||
 | 
							ROUGHNESS_CHANNEL_R,
 | 
				
			||||||
 | 
							ROUGHNESS_CHANNEL_G,
 | 
				
			||||||
 | 
							ROUGHNESS_CHANNEL_B,
 | 
				
			||||||
 | 
							ROUGHNESS_CHANNEL_A,
 | 
				
			||||||
 | 
							ROUGHNESS_CHANNEL_L,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum Image3DValidateError {
 | 
				
			||||||
 | 
							VALIDATE_3D_OK,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_IMAGE_EMPTY,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_MISSING_IMAGES,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_EXTRA_IMAGES,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH,
 | 
				
			||||||
 | 
							VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum CompressMode {
 | 
				
			||||||
 | 
							COMPRESS_S3TC,
 | 
				
			||||||
 | 
							COMPRESS_ETC,
 | 
				
			||||||
 | 
							COMPRESS_ETC2,
 | 
				
			||||||
 | 
							COMPRESS_BPTC,
 | 
				
			||||||
 | 
							COMPRESS_ASTC,
 | 
				
			||||||
 | 
							COMPRESS_MAX,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum CompressSource {
 | 
				
			||||||
 | 
							COMPRESS_SOURCE_GENERIC,
 | 
				
			||||||
 | 
							COMPRESS_SOURCE_SRGB,
 | 
				
			||||||
 | 
							COMPRESS_SOURCE_NORMAL,
 | 
				
			||||||
 | 
							COMPRESS_SOURCE_MAX,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum AlphaMode {
 | 
				
			||||||
 | 
							ALPHA_NONE,
 | 
				
			||||||
 | 
							ALPHA_BIT,
 | 
				
			||||||
 | 
							ALPHA_BLEND
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// External saver function pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static SavePNGFunc save_png_func;
 | 
				
			||||||
 | 
						static SaveJPGFunc save_jpg_func;
 | 
				
			||||||
 | 
						static SaveEXRFunc save_exr_func;
 | 
				
			||||||
 | 
						static SaveWebPFunc save_webp_func;
 | 
				
			||||||
 | 
						static SavePNGBufferFunc save_png_buffer_func;
 | 
				
			||||||
 | 
						static SaveEXRBufferFunc save_exr_buffer_func;
 | 
				
			||||||
 | 
						static SaveJPGBufferFunc save_jpg_buffer_func;
 | 
				
			||||||
 | 
						static SaveWebPBufferFunc save_webp_buffer_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// External loader function pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static ImageMemLoadFunc _png_mem_loader_func;
 | 
						static ImageMemLoadFunc _png_mem_loader_func;
 | 
				
			||||||
	static ImageMemLoadFunc _png_mem_unpacker_func;
 | 
						static ImageMemLoadFunc _png_mem_unpacker_func;
 | 
				
			||||||
	static ImageMemLoadFunc _jpg_mem_loader_func;
 | 
						static ImageMemLoadFunc _jpg_mem_loader_func;
 | 
				
			||||||
| 
						 | 
					@ -153,30 +202,37 @@ public:
 | 
				
			||||||
	static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
 | 
						static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
 | 
				
			||||||
	static ImageMemLoadFunc _ktx_mem_loader_func;
 | 
						static ImageMemLoadFunc _ktx_mem_loader_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// External VRAM compression function pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
 | 
						static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
 | 
				
			||||||
	static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
 | 
						static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
 | 
				
			||||||
	static void (*_image_compress_etc1_func)(Image *);
 | 
						static void (*_image_compress_etc1_func)(Image *);
 | 
				
			||||||
	static void (*_image_compress_etc2_func)(Image *, UsedChannels p_channels);
 | 
						static void (*_image_compress_etc2_func)(Image *, UsedChannels p_channels);
 | 
				
			||||||
	static void (*_image_compress_astc_func)(Image *, ASTCFormat p_format);
 | 
						static void (*_image_compress_astc_func)(Image *, ASTCFormat p_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels);
 | 
				
			||||||
 | 
						static Error (*_image_compress_bc_rd_func)(Image *, UsedChannels p_channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// External VRAM decompression function pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void (*_image_decompress_bc)(Image *);
 | 
						static void (*_image_decompress_bc)(Image *);
 | 
				
			||||||
	static void (*_image_decompress_bptc)(Image *);
 | 
						static void (*_image_decompress_bptc)(Image *);
 | 
				
			||||||
	static void (*_image_decompress_etc1)(Image *);
 | 
						static void (*_image_decompress_etc1)(Image *);
 | 
				
			||||||
	static void (*_image_decompress_etc2)(Image *);
 | 
						static void (*_image_decompress_etc2)(Image *);
 | 
				
			||||||
	static void (*_image_decompress_astc)(Image *);
 | 
						static void (*_image_decompress_astc)(Image *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// External packer function pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
 | 
						static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
 | 
				
			||||||
	static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
 | 
						static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
 | 
				
			||||||
	static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
					 | 
				
			||||||
	static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image);
 | 
						static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image);
 | 
				
			||||||
	static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
					 | 
				
			||||||
	static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
 | 
						static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
				
			||||||
 | 
						static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
				
			||||||
	static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
						static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer);
 | 
				
			||||||
	static Ref<Image> (*basis_universal_unpacker_ptr)(const uint8_t *p_data, int p_size);
 | 
						static Ref<Image> (*basis_universal_unpacker_ptr)(const uint8_t *p_data, int p_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ Color _get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const;
 | 
					 | 
				
			||||||
	_FORCE_INLINE_ void _set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	static void _bind_methods();
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,15 +243,12 @@ private:
 | 
				
			||||||
	int height = 0;
 | 
						int height = 0;
 | 
				
			||||||
	bool mipmaps = false;
 | 
						bool mipmaps = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void _copy_internals_from(const Image &p_image) {
 | 
						void _copy_internals_from(const Image &p_image);
 | 
				
			||||||
		format = p_image.format;
 | 
					 | 
				
			||||||
		width = p_image.width;
 | 
					 | 
				
			||||||
		height = p_image.height;
 | 
					 | 
				
			||||||
		mipmaps = p_image.mipmaps;
 | 
					 | 
				
			||||||
		data = p_image.data;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
 | 
						_FORCE_INLINE_ Color _get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const;
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void _set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; // Get where the mipmap begins in data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
 | 
						static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
 | 
				
			||||||
	bool _can_modify(Format p_format) const;
 | 
						bool _can_modify(Format p_format) const;
 | 
				
			||||||
| 
						 | 
					@ -212,6 +265,8 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error _load_from_buffer(const Vector<uint8_t> &p_array, ImageMemLoadFunc p_loader);
 | 
						Error _load_from_buffer(const Vector<uint8_t> &p_array, ImageMemLoadFunc p_loader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void _generate_mipmap_from_format(Image::Format p_format, const uint8_t *p_src, uint8_t *p_dst, uint32_t p_width, uint32_t p_height, bool p_renormalize = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d);
 | 
						static void average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d);
 | 
				
			||||||
	static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d);
 | 
						static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d);
 | 
				
			||||||
	static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d);
 | 
						static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d);
 | 
				
			||||||
| 
						 | 
					@ -222,52 +277,32 @@ private:
 | 
				
			||||||
	static void renormalize_rgbe9995(uint32_t *p_rgb);
 | 
						static void renormalize_rgbe9995(uint32_t *p_rgb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	int get_width() const; ///< Get image width
 | 
						int get_width() const;
 | 
				
			||||||
	int get_height() const; ///< Get image height
 | 
						int get_height() const;
 | 
				
			||||||
	Size2i get_size() const;
 | 
						Size2i get_size() const;
 | 
				
			||||||
	bool has_mipmaps() const;
 | 
						bool has_mipmaps() const;
 | 
				
			||||||
	int get_mipmap_count() const;
 | 
						int get_mipmap_count() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Convert the image to another format, conversion only to raw byte format.
 | 
				
			||||||
	 * Convert the image to another format, conversion only to raw byte format
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void convert(Format p_new_format);
 | 
						void convert(Format p_new_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Get the current image format.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	Format get_format() const;
 | 
						Format get_format() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Get where the mipmap begins in data.
 | 
				
			||||||
	 * Get where the mipmap begins in data.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	int64_t get_mipmap_offset(int p_mipmap) const;
 | 
						int64_t get_mipmap_offset(int p_mipmap) const;
 | 
				
			||||||
	void get_mipmap_offset_and_size(int p_mipmap, int64_t &r_ofs, int64_t &r_size) const;
 | 
						void get_mipmap_offset_and_size(int p_mipmap, int64_t &r_ofs, int64_t &r_size) const;
 | 
				
			||||||
	void get_mipmap_offset_size_and_dimensions(int p_mipmap, int64_t &r_ofs, int64_t &r_size, int &w, int &h) const;
 | 
						void get_mipmap_offset_size_and_dimensions(int p_mipmap, int64_t &r_ofs, int64_t &r_size, int &w, int &h) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum Image3DValidateError {
 | 
					 | 
				
			||||||
		VALIDATE_3D_OK,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_IMAGE_EMPTY,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_MISSING_IMAGES,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_EXTRA_IMAGES,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH,
 | 
					 | 
				
			||||||
		VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static Image3DValidateError validate_3d_image(Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images);
 | 
						static Image3DValidateError validate_3d_image(Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images);
 | 
				
			||||||
	static String get_3d_image_validation_error_text(Image3DValidateError p_error);
 | 
						static String get_3d_image_validation_error_text(Image3DValidateError p_error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Resize the image, using the preferred interpolation method.
 | 
				
			||||||
	 * Resize the image, using the preferred interpolation method.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
 | 
						void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
 | 
				
			||||||
	void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
 | 
						void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
 | 
				
			||||||
	void shrink_x2();
 | 
						void shrink_x2();
 | 
				
			||||||
	bool is_size_po2() const;
 | 
						bool is_size_po2() const;
 | 
				
			||||||
	/**
 | 
					
 | 
				
			||||||
	 * Crop the image to a specific size, if larger, then the image is filled by black
 | 
						// Crop the image to a specific size, if larger, then the image is filled by black.
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void crop_from_point(int p_x, int p_y, int p_width, int p_height);
 | 
						void crop_from_point(int p_x, int p_y, int p_width, int p_height);
 | 
				
			||||||
	void crop(int p_width, int p_height);
 | 
						void crop(int p_width, int p_height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -277,34 +312,20 @@ public:
 | 
				
			||||||
	void flip_x();
 | 
						void flip_x();
 | 
				
			||||||
	void flip_y();
 | 
						void flip_y();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Generate a mipmap chain of an image (creates an image 1/4 the size, with averaging of 4->1).
 | 
				
			||||||
	 * Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	Error generate_mipmaps(bool p_renormalize = false);
 | 
						Error generate_mipmaps(bool p_renormalize = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum RoughnessChannel {
 | 
					 | 
				
			||||||
		ROUGHNESS_CHANNEL_R,
 | 
					 | 
				
			||||||
		ROUGHNESS_CHANNEL_G,
 | 
					 | 
				
			||||||
		ROUGHNESS_CHANNEL_B,
 | 
					 | 
				
			||||||
		ROUGHNESS_CHANNEL_A,
 | 
					 | 
				
			||||||
		ROUGHNESS_CHANNEL_L,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Error generate_mipmap_roughness(RoughnessChannel p_roughness_channel, const Ref<Image> &p_normal_map);
 | 
						Error generate_mipmap_roughness(RoughnessChannel p_roughness_channel, const Ref<Image> &p_normal_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void clear_mipmaps();
 | 
						void clear_mipmaps();
 | 
				
			||||||
	void normalize(); //for normal maps
 | 
						void normalize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Creates new internal image data of a given size and format. Current image will be lost.
 | 
				
			||||||
	 * Creates new internal image data of a given size and format. Current image will be lost.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
 | 
						void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
 | 
				
			||||||
	void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
						void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
				
			||||||
	void initialize_data(const char **p_xpm);
 | 
						void initialize_data(const char **p_xpm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						// Returns true when the image is empty (0,0) in size.
 | 
				
			||||||
	 * returns true when the image is empty (0,0) in size
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	bool is_empty() const;
 | 
						bool is_empty() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Vector<uint8_t> get_data() const;
 | 
						Vector<uint8_t> get_data() const;
 | 
				
			||||||
| 
						 | 
					@ -324,27 +345,14 @@ public:
 | 
				
			||||||
	static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
						static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
				
			||||||
	void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
						void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						Image() = default; // Create an empty image.
 | 
				
			||||||
	 * create an empty image
 | 
						Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format); // Create an empty image of a specific size and format.
 | 
				
			||||||
	 */
 | 
						Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data); // Import an image of a specific size and format from a byte vector.
 | 
				
			||||||
	Image() {}
 | 
						Image(const uint8_t *p_mem_png_jpg, int p_len = -1); // Import either a png or jpg from a pointer.
 | 
				
			||||||
	/**
 | 
						Image(const char **p_xpm); // Import an XPM image.
 | 
				
			||||||
	 * create an empty image of a specific size and format
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * import an image of a specific size and format from a pointer
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~Image() {}
 | 
						~Image() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum AlphaMode {
 | 
					 | 
				
			||||||
		ALPHA_NONE,
 | 
					 | 
				
			||||||
		ALPHA_BIT,
 | 
					 | 
				
			||||||
		ALPHA_BLEND
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	AlphaMode detect_alpha() const;
 | 
						AlphaMode detect_alpha() const;
 | 
				
			||||||
	bool is_invisible() const;
 | 
						bool is_invisible() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -359,21 +367,6 @@ public:
 | 
				
			||||||
	static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
 | 
						static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
 | 
				
			||||||
	static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h);
 | 
						static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum CompressMode {
 | 
					 | 
				
			||||||
		COMPRESS_S3TC,
 | 
					 | 
				
			||||||
		COMPRESS_ETC,
 | 
					 | 
				
			||||||
		COMPRESS_ETC2,
 | 
					 | 
				
			||||||
		COMPRESS_BPTC,
 | 
					 | 
				
			||||||
		COMPRESS_ASTC,
 | 
					 | 
				
			||||||
		COMPRESS_MAX,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	enum CompressSource {
 | 
					 | 
				
			||||||
		COMPRESS_SOURCE_GENERIC,
 | 
					 | 
				
			||||||
		COMPRESS_SOURCE_SRGB,
 | 
					 | 
				
			||||||
		COMPRESS_SOURCE_NORMAL,
 | 
					 | 
				
			||||||
		COMPRESS_SOURCE_MAX,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
 | 
						Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
 | 
				
			||||||
	Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
 | 
						Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
 | 
				
			||||||
	Error decompress();
 | 
						Error decompress();
 | 
				
			||||||
| 
						 | 
					@ -383,11 +376,14 @@ public:
 | 
				
			||||||
	void fix_alpha_edges();
 | 
						void fix_alpha_edges();
 | 
				
			||||||
	void premultiply_alpha();
 | 
						void premultiply_alpha();
 | 
				
			||||||
	void srgb_to_linear();
 | 
						void srgb_to_linear();
 | 
				
			||||||
 | 
						void linear_to_srgb();
 | 
				
			||||||
	void normal_map_to_xy();
 | 
						void normal_map_to_xy();
 | 
				
			||||||
	Ref<Image> rgbe_to_srgb();
 | 
						Ref<Image> rgbe_to_srgb();
 | 
				
			||||||
	Ref<Image> get_image_from_mipmap(int p_mipmap) const;
 | 
						Ref<Image> get_image_from_mipmap(int p_mipmap) const;
 | 
				
			||||||
	void bump_map_to_normal_map(float bump_scale = 1.0);
 | 
						void bump_map_to_normal_map(float bump_scale = 1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool detect_signed(bool p_include_mips = true) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
						void blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
				
			||||||
	void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
						void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
				
			||||||
	void blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
						void blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest);
 | 
				
			||||||
| 
						 | 
					@ -398,9 +394,8 @@ public:
 | 
				
			||||||
	Rect2i get_used_rect() const;
 | 
						Rect2i get_used_rect() const;
 | 
				
			||||||
	Ref<Image> get_region(const Rect2i &p_area) const;
 | 
						Ref<Image> get_region(const Rect2i &p_area) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void set_compress_bc_func(void (*p_compress_func)(Image *, UsedChannels));
 | 
					 | 
				
			||||||
	static void set_compress_bptc_func(void (*p_compress_func)(Image *, UsedChannels));
 | 
					 | 
				
			||||||
	static String get_format_name(Format p_format);
 | 
						static String get_format_name(Format p_format);
 | 
				
			||||||
 | 
						static uint32_t get_format_component_mask(Format p_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Error load_png_from_buffer(const Vector<uint8_t> &p_array);
 | 
						Error load_png_from_buffer(const Vector<uint8_t> &p_array);
 | 
				
			||||||
	Error load_jpg_from_buffer(const Vector<uint8_t> &p_array);
 | 
						Error load_jpg_from_buffer(const Vector<uint8_t> &p_array);
 | 
				
			||||||
| 
						 | 
					@ -416,9 +411,6 @@ public:
 | 
				
			||||||
	void convert_ra_rgba8_to_rg();
 | 
						void convert_ra_rgba8_to_rg();
 | 
				
			||||||
	void convert_rgba8_to_bgra8();
 | 
						void convert_rgba8_to_bgra8();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
 | 
					 | 
				
			||||||
	Image(const char **p_xpm);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual Ref<Resource> duplicate(bool p_subresources = false) const override;
 | 
						virtual Ref<Resource> duplicate(bool p_subresources = false) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC) const;
 | 
						UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC) const;
 | 
				
			||||||
| 
						 | 
					@ -437,14 +429,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_as_black();
 | 
						void set_as_black();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void copy_internals_from(const Ref<Image> &p_image) {
 | 
						void copy_internals_from(const Ref<Image> &p_image);
 | 
				
			||||||
		ERR_FAIL_COND_MSG(p_image.is_null(), "Cannot copy image internals: invalid Image object.");
 | 
					 | 
				
			||||||
		format = p_image->format;
 | 
					 | 
				
			||||||
		width = p_image->width;
 | 
					 | 
				
			||||||
		height = p_image->height;
 | 
					 | 
				
			||||||
		mipmaps = p_image->mipmaps;
 | 
					 | 
				
			||||||
		data = p_image->data;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Dictionary compute_image_metrics(const Ref<Image> p_compared_image, bool p_luma_metric = true);
 | 
						Dictionary compute_image_metrics(const Ref<Image> p_compared_image, bool p_luma_metric = true);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,8 +30,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "image_loader.h"
 | 
					#include "image_loader.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/string/print_string.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ImageFormatLoader::_bind_methods() {
 | 
					void ImageFormatLoader::_bind_methods() {
 | 
				
			||||||
	BIND_BITFIELD_FLAG(FLAG_NONE);
 | 
						BIND_BITFIELD_FLAG(FLAG_NONE);
 | 
				
			||||||
	BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);
 | 
						BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);
 | 
				
			||||||
| 
						 | 
					@ -82,15 +80,16 @@ void ImageFormatLoaderExtension::_bind_methods() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
 | 
					Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
 | 
				
			||||||
	ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "Can't load an image: invalid Image object.");
 | 
						ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "Can't load an image: invalid Image object.");
 | 
				
			||||||
 | 
						const String file = ResourceUID::ensure_path(p_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<FileAccess> f = p_custom;
 | 
						Ref<FileAccess> f = p_custom;
 | 
				
			||||||
	if (f.is_null()) {
 | 
						if (f.is_null()) {
 | 
				
			||||||
		Error err;
 | 
							Error err;
 | 
				
			||||||
		f = FileAccess::open(p_file, FileAccess::READ, &err);
 | 
							f = FileAccess::open(file, FileAccess::READ, &err);
 | 
				
			||||||
		ERR_FAIL_COND_V_MSG(f.is_null(), err, "Error opening file '" + p_file + "'.");
 | 
							ERR_FAIL_COND_V_MSG(f.is_null(), err, vformat("Error opening file '%s'.", file));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String extension = p_file.get_extension();
 | 
						String extension = file.get_extension();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < loader.size(); i++) {
 | 
						for (int i = 0; i < loader.size(); i++) {
 | 
				
			||||||
		if (!loader[i]->recognize(extension)) {
 | 
							if (!loader[i]->recognize(extension)) {
 | 
				
			||||||
| 
						 | 
					@ -98,7 +97,7 @@ Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<File
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
 | 
							Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
 | 
				
			||||||
		if (err != OK) {
 | 
							if (err != OK) {
 | 
				
			||||||
			ERR_PRINT("Error loading image: " + p_file);
 | 
								ERR_PRINT(vformat("Error loading image: '%s'.", file));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (err != ERR_FILE_UNRECOGNIZED) {
 | 
							if (err != ERR_FILE_UNRECOGNIZED) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue