feat: godot-engine-source-4.3-stable
This commit is contained in:
		
							parent
							
								
									c59a7dcade
								
							
						
					
					
						commit
						7125d019b5
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -6,3 +6,4 @@
 | 
				
			||||||
config.log
 | 
					config.log
 | 
				
			||||||
.sconf_temp
 | 
					.sconf_temp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					engine/.github
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										199
									
								
								engine/.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								engine/.clang-format
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,199 @@
 | 
				
			||||||
 | 
					# Commented out parameters are those with the same value as base LLVM style.
 | 
				
			||||||
 | 
					# We can uncomment them if we want to change their value, or enforce the
 | 
				
			||||||
 | 
					# chosen value in case the base style changes (last sync: Clang 14.0).
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					### General config, applies to all languages ###
 | 
				
			||||||
 | 
					BasedOnStyle:  LLVM
 | 
				
			||||||
 | 
					AccessModifierOffset: -4
 | 
				
			||||||
 | 
					AlignAfterOpenBracket: DontAlign
 | 
				
			||||||
 | 
					# AlignArrayOfStructures: None
 | 
				
			||||||
 | 
					# AlignConsecutiveMacros: None
 | 
				
			||||||
 | 
					# AlignConsecutiveAssignments: None
 | 
				
			||||||
 | 
					# AlignConsecutiveBitFields: None
 | 
				
			||||||
 | 
					# AlignConsecutiveDeclarations: None
 | 
				
			||||||
 | 
					# AlignEscapedNewlines: Right
 | 
				
			||||||
 | 
					AlignOperands:   DontAlign
 | 
				
			||||||
 | 
					AlignTrailingComments: false
 | 
				
			||||||
 | 
					# AllowAllArgumentsOnNextLine: true
 | 
				
			||||||
 | 
					AllowAllParametersOfDeclarationOnNextLine: false
 | 
				
			||||||
 | 
					# AllowShortEnumsOnASingleLine: true
 | 
				
			||||||
 | 
					# AllowShortBlocksOnASingleLine: Never
 | 
				
			||||||
 | 
					# AllowShortCaseLabelsOnASingleLine: false
 | 
				
			||||||
 | 
					# AllowShortFunctionsOnASingleLine: All
 | 
				
			||||||
 | 
					# AllowShortLambdasOnASingleLine: All
 | 
				
			||||||
 | 
					# AllowShortIfStatementsOnASingleLine: Never
 | 
				
			||||||
 | 
					# AllowShortLoopsOnASingleLine: false
 | 
				
			||||||
 | 
					# AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
 | 
					# AlwaysBreakAfterReturnType: None
 | 
				
			||||||
 | 
					# AlwaysBreakBeforeMultilineStrings: false
 | 
				
			||||||
 | 
					# AlwaysBreakTemplateDeclarations: MultiLine
 | 
				
			||||||
 | 
					# AttributeMacros:
 | 
				
			||||||
 | 
					#   - __capability
 | 
				
			||||||
 | 
					# BinPackArguments: true
 | 
				
			||||||
 | 
					# BinPackParameters: true
 | 
				
			||||||
 | 
					# BraceWrapping:
 | 
				
			||||||
 | 
					#   AfterCaseLabel:  false
 | 
				
			||||||
 | 
					#   AfterClass:      false
 | 
				
			||||||
 | 
					#   AfterControlStatement: Never
 | 
				
			||||||
 | 
					#   AfterEnum:       false
 | 
				
			||||||
 | 
					#   AfterFunction:   false
 | 
				
			||||||
 | 
					#   AfterNamespace:  false
 | 
				
			||||||
 | 
					#   AfterObjCDeclaration: false
 | 
				
			||||||
 | 
					#   AfterStruct:     false
 | 
				
			||||||
 | 
					#   AfterUnion:      false
 | 
				
			||||||
 | 
					#   AfterExternBlock: false
 | 
				
			||||||
 | 
					#   BeforeCatch:     false
 | 
				
			||||||
 | 
					#   BeforeElse:      false
 | 
				
			||||||
 | 
					#   BeforeLambdaBody: false
 | 
				
			||||||
 | 
					#   BeforeWhile:     false
 | 
				
			||||||
 | 
					#   IndentBraces:    false
 | 
				
			||||||
 | 
					#   SplitEmptyFunction: true
 | 
				
			||||||
 | 
					#   SplitEmptyRecord: true
 | 
				
			||||||
 | 
					#   SplitEmptyNamespace: true
 | 
				
			||||||
 | 
					# BreakBeforeBinaryOperators: None
 | 
				
			||||||
 | 
					# BreakBeforeConceptDeclarations: true
 | 
				
			||||||
 | 
					# BreakBeforeBraces: Attach
 | 
				
			||||||
 | 
					# BreakBeforeInheritanceComma: false
 | 
				
			||||||
 | 
					# BreakInheritanceList: BeforeColon
 | 
				
			||||||
 | 
					# BreakBeforeTernaryOperators: true
 | 
				
			||||||
 | 
					# BreakConstructorInitializersBeforeComma: false
 | 
				
			||||||
 | 
					BreakConstructorInitializers: AfterColon
 | 
				
			||||||
 | 
					# BreakStringLiterals: true
 | 
				
			||||||
 | 
					ColumnLimit:     0
 | 
				
			||||||
 | 
					# CommentPragmas:  '^ IWYU pragma:'
 | 
				
			||||||
 | 
					# QualifierAlignment: Leave
 | 
				
			||||||
 | 
					# CompactNamespaces: false
 | 
				
			||||||
 | 
					ConstructorInitializerIndentWidth: 8
 | 
				
			||||||
 | 
					ContinuationIndentWidth: 8
 | 
				
			||||||
 | 
					Cpp11BracedListStyle: false
 | 
				
			||||||
 | 
					# DeriveLineEnding: true
 | 
				
			||||||
 | 
					# DerivePointerAlignment: false
 | 
				
			||||||
 | 
					# DisableFormat:   false
 | 
				
			||||||
 | 
					# EmptyLineAfterAccessModifier: Never
 | 
				
			||||||
 | 
					# EmptyLineBeforeAccessModifier: LogicalBlock
 | 
				
			||||||
 | 
					# ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
 | 
					# PackConstructorInitializers: BinPack
 | 
				
			||||||
 | 
					ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
				
			||||||
 | 
					# AllowAllConstructorInitializersOnNextLine: true
 | 
				
			||||||
 | 
					# FixNamespaceComments: true
 | 
				
			||||||
 | 
					# ForEachMacros:
 | 
				
			||||||
 | 
					#   - foreach
 | 
				
			||||||
 | 
					#   - Q_FOREACH
 | 
				
			||||||
 | 
					#   - BOOST_FOREACH
 | 
				
			||||||
 | 
					# IfMacros:
 | 
				
			||||||
 | 
					#   - KJ_IF_MAYBE
 | 
				
			||||||
 | 
					# IncludeBlocks:   Preserve
 | 
				
			||||||
 | 
					IncludeCategories:
 | 
				
			||||||
 | 
					  - Regex:           '".*"'
 | 
				
			||||||
 | 
					    Priority:        1
 | 
				
			||||||
 | 
					  - Regex:           '^<.*\.h>'
 | 
				
			||||||
 | 
					    Priority:        2
 | 
				
			||||||
 | 
					  - Regex:           '^<.*'
 | 
				
			||||||
 | 
					    Priority:        3
 | 
				
			||||||
 | 
					# IncludeIsMainRegex: '(Test)?$'
 | 
				
			||||||
 | 
					# IncludeIsMainSourceRegex: ''
 | 
				
			||||||
 | 
					# IndentAccessModifiers: false
 | 
				
			||||||
 | 
					IndentCaseLabels: true
 | 
				
			||||||
 | 
					# IndentCaseBlocks: false
 | 
				
			||||||
 | 
					# IndentGotoLabels: true
 | 
				
			||||||
 | 
					# IndentPPDirectives: None
 | 
				
			||||||
 | 
					# IndentExternBlock: AfterExternBlock
 | 
				
			||||||
 | 
					# IndentRequires:  false
 | 
				
			||||||
 | 
					IndentWidth:     4
 | 
				
			||||||
 | 
					# IndentWrappedFunctionNames: false
 | 
				
			||||||
 | 
					# InsertTrailingCommas: None
 | 
				
			||||||
 | 
					# JavaScriptQuotes: Leave
 | 
				
			||||||
 | 
					# JavaScriptWrapImports: true
 | 
				
			||||||
 | 
					KeepEmptyLinesAtTheStartOfBlocks: false
 | 
				
			||||||
 | 
					# LambdaBodyIndentation: Signature
 | 
				
			||||||
 | 
					# MacroBlockBegin: ''
 | 
				
			||||||
 | 
					# MacroBlockEnd:   ''
 | 
				
			||||||
 | 
					# MaxEmptyLinesToKeep: 1
 | 
				
			||||||
 | 
					# NamespaceIndentation: None
 | 
				
			||||||
 | 
					# PenaltyBreakAssignment: 2
 | 
				
			||||||
 | 
					# PenaltyBreakBeforeFirstCallParameter: 19
 | 
				
			||||||
 | 
					# PenaltyBreakComment: 300
 | 
				
			||||||
 | 
					# PenaltyBreakFirstLessLess: 120
 | 
				
			||||||
 | 
					# PenaltyBreakOpenParenthesis: 0
 | 
				
			||||||
 | 
					# PenaltyBreakString: 1000
 | 
				
			||||||
 | 
					# PenaltyBreakTemplateDeclaration: 10
 | 
				
			||||||
 | 
					# PenaltyExcessCharacter: 1000000
 | 
				
			||||||
 | 
					# PenaltyReturnTypeOnItsOwnLine: 60
 | 
				
			||||||
 | 
					# PenaltyIndentedWhitespace: 0
 | 
				
			||||||
 | 
					# PointerAlignment: Right
 | 
				
			||||||
 | 
					# PPIndentWidth:   -1
 | 
				
			||||||
 | 
					# ReferenceAlignment: Pointer
 | 
				
			||||||
 | 
					# ReflowComments:  true
 | 
				
			||||||
 | 
					# RemoveBracesLLVM: false
 | 
				
			||||||
 | 
					# SeparateDefinitionBlocks: Leave
 | 
				
			||||||
 | 
					# ShortNamespaceLines: 1
 | 
				
			||||||
 | 
					# SortIncludes:    CaseSensitive
 | 
				
			||||||
 | 
					# SortJavaStaticImport: Before
 | 
				
			||||||
 | 
					# SortUsingDeclarations: true
 | 
				
			||||||
 | 
					# SpaceAfterCStyleCast: false
 | 
				
			||||||
 | 
					# SpaceAfterLogicalNot: false
 | 
				
			||||||
 | 
					# SpaceAfterTemplateKeyword: true
 | 
				
			||||||
 | 
					# SpaceBeforeAssignmentOperators: true
 | 
				
			||||||
 | 
					# SpaceBeforeCaseColon: false
 | 
				
			||||||
 | 
					# SpaceBeforeCpp11BracedList: false
 | 
				
			||||||
 | 
					# SpaceBeforeCtorInitializerColon: true
 | 
				
			||||||
 | 
					# SpaceBeforeInheritanceColon: true
 | 
				
			||||||
 | 
					# SpaceBeforeParens: ControlStatements
 | 
				
			||||||
 | 
					# SpaceBeforeParensOptions:
 | 
				
			||||||
 | 
					#   AfterControlStatements: true
 | 
				
			||||||
 | 
					#   AfterForeachMacros: true
 | 
				
			||||||
 | 
					#   AfterFunctionDefinitionName: false
 | 
				
			||||||
 | 
					#   AfterFunctionDeclarationName: false
 | 
				
			||||||
 | 
					#   AfterIfMacros:   true
 | 
				
			||||||
 | 
					#   AfterOverloadedOperator: false
 | 
				
			||||||
 | 
					#   BeforeNonEmptyParentheses: false
 | 
				
			||||||
 | 
					# SpaceAroundPointerQualifiers: Default
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
 | 
					# BitFieldColonSpacing: Both
 | 
				
			||||||
 | 
					# StatementAttributeLikeMacros:
 | 
				
			||||||
 | 
					#   - Q_EMIT
 | 
				
			||||||
 | 
					# StatementMacros:
 | 
				
			||||||
 | 
					#   - Q_UNUSED
 | 
				
			||||||
 | 
					#   - QT_REQUIRE_VERSION
 | 
				
			||||||
 | 
					TabWidth:        4
 | 
				
			||||||
 | 
					# UseCRLF:         false
 | 
				
			||||||
 | 
					UseTab:          Always
 | 
				
			||||||
 | 
					# WhitespaceSensitiveMacros:
 | 
				
			||||||
 | 
					#   - STRINGIZE
 | 
				
			||||||
 | 
					#   - PP_STRINGIZE
 | 
				
			||||||
 | 
					#   - BOOST_PP_STRINGIZE
 | 
				
			||||||
 | 
					#   - NS_SWIFT_NAME
 | 
				
			||||||
 | 
					#   - CF_SWIFT_NAME
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					### C++ specific config ###
 | 
				
			||||||
 | 
					Language:        Cpp
 | 
				
			||||||
 | 
					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']
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
							
								
								
									
										22
									
								
								engine/.clang-tidy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								engine/.clang-tidy
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					Checks: >-
 | 
				
			||||||
 | 
					  -*,
 | 
				
			||||||
 | 
					  cppcoreguidelines-pro-type-member-init,
 | 
				
			||||||
 | 
					  modernize-redundant-void-arg,
 | 
				
			||||||
 | 
					  modernize-use-bool-literals,
 | 
				
			||||||
 | 
					  modernize-use-default-member-init,
 | 
				
			||||||
 | 
					  modernize-use-nullptr,
 | 
				
			||||||
 | 
					  readability-braces-around-statements,
 | 
				
			||||||
 | 
					  readability-redundant-member-init
 | 
				
			||||||
 | 
					WarningsAsErrors: ''
 | 
				
			||||||
 | 
					HeaderFileExtensions: ['', h, hh, hpp, hxx, inc, glsl]
 | 
				
			||||||
 | 
					ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
 | 
				
			||||||
 | 
					HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
 | 
				
			||||||
 | 
					FormatStyle: file
 | 
				
			||||||
 | 
					CheckOptions:
 | 
				
			||||||
 | 
					  cppcoreguidelines-pro-type-member-init.IgnoreArrays: true
 | 
				
			||||||
 | 
					  cppcoreguidelines-pro-type-member-init.UseAssignment: true
 | 
				
			||||||
 | 
					  modernize-use-bool-literals.IgnoreMacros: false
 | 
				
			||||||
 | 
					  modernize-use-default-member-init.IgnoreMacros: false
 | 
				
			||||||
 | 
					  modernize-use-default-member-init.UseAssignment: true
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
							
								
								
									
										26
									
								
								engine/.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								engine/.editorconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					root = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*]
 | 
				
			||||||
 | 
					charset = utf-8
 | 
				
			||||||
 | 
					end_of_line = lf
 | 
				
			||||||
 | 
					indent_style = tab
 | 
				
			||||||
 | 
					insert_final_newline = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.{cpp,hpp,c,h,mm}]
 | 
				
			||||||
 | 
					trim_trailing_whitespace = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[{*.gradle,AndroidManifest.xml}]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[{*.py,SConstruct,SCsub}]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# YAML requires indentation with spaces instead of tabs.
 | 
				
			||||||
 | 
					[*.{yml,yaml}]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.svg]
 | 
				
			||||||
 | 
					insert_final_newline = false
 | 
				
			||||||
							
								
								
									
										56
									
								
								engine/.git-blame-ignore-revs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								engine/.git-blame-ignore-revs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					# This file contains a list of Git commit hashes that should be hidden from the
 | 
				
			||||||
 | 
					# regular Git history. Typically, this includes commits involving mass auto-formatting
 | 
				
			||||||
 | 
					# or other normalizations. Commit hashes *must* use the full 40-character notation.
 | 
				
			||||||
 | 
					# To apply the ignore list in your local Git client, you must run:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   git config blame.ignoreRevsFile .git-blame-ignore-revs
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is automatically used by GitHub.com's blame view.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# A Whole New World (clang-format edition)
 | 
				
			||||||
 | 
					5dbf1809c6e3e905b94b8764e99491e608122261
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Style: clang-format: Disable KeepEmptyLinesAtTheStartOfBlocks
 | 
				
			||||||
 | 
					0be6d925dc3c6413bce7a3ccb49631b8e4a6e67a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Style: clang-format: Disable AllowShortIfStatementsOnASingleLine
 | 
				
			||||||
 | 
					e956e80c1fa1cc8aefcb1533e5acf5cf3c8ffdd9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# One Copyright Update to rule them all
 | 
				
			||||||
 | 
					d95794ec8a7c362b06a9cf080e2554ef77adb667
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright statements to 2022
 | 
				
			||||||
 | 
					fe52458154c64fb1b741df4f7bd10106395f7cbd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright statements to 2021
 | 
				
			||||||
 | 
					b5334d14f7a471f94bcbd64d5bae2ad853d0b7f1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright statements to 2020
 | 
				
			||||||
 | 
					a7f49ac9a107820a62677ee3fb49d38982a25165
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright statements to 2019
 | 
				
			||||||
 | 
					b16c309f82c77d606472c3c721a1857e323a09e7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright statements to 2018
 | 
				
			||||||
 | 
					b50a9114b105dafafdda8248a38653bca314a6f3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Welcome in 2017, dear changelog reader!
 | 
				
			||||||
 | 
					c7bc44d5ad9aae4902280012f7654e2318cd910e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Update copyright to 2016 in headers
 | 
				
			||||||
 | 
					5be9ff7b6715a661e85f99b108f96340de7ef435
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Updated copyright year in all headers
 | 
				
			||||||
 | 
					fdaa2920eb21fff3320a17e9239e04dfadecdb00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add missing copyright headers and fix formatting
 | 
				
			||||||
 | 
					e4213e66b2dd8f5a87d8cf5015ac83ba3143279d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Use HTTPS URL for Godot's website in the headers
 | 
				
			||||||
 | 
					bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add "Godot Engine contributors" copyright line
 | 
				
			||||||
 | 
					df61dc4b2bd54a5a40c515493c76f5a458e5b541
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enforce template syntax `typename` over `class`
 | 
				
			||||||
 | 
					9903e6779b70fc03aae70a37b9cf053f4f355b91
 | 
				
			||||||
							
								
								
									
										23
									
								
								engine/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								engine/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					# Properly detect languages on Github
 | 
				
			||||||
 | 
					*.h linguist-language=cpp
 | 
				
			||||||
 | 
					*.inc linguist-language=cpp
 | 
				
			||||||
 | 
					thirdparty/* linguist-vendored
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Normalize EOL for all files that Git considers text files
 | 
				
			||||||
 | 
					* text=auto eol=lf
 | 
				
			||||||
 | 
					# Except for Windows-only / Visual Studio files
 | 
				
			||||||
 | 
					*.bat eol=crlf
 | 
				
			||||||
 | 
					*.sln eol=crlf
 | 
				
			||||||
 | 
					*.csproj eol=crlf
 | 
				
			||||||
 | 
					misc/msvs/*.template eol=crlf
 | 
				
			||||||
 | 
					# And some test files where the EOL matters
 | 
				
			||||||
 | 
					*.test.txt -text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The above only works properly for Git 2.10+, so for older versions
 | 
				
			||||||
 | 
					# we need to manually list the binary files we don't want modified.
 | 
				
			||||||
 | 
					*.icns binary
 | 
				
			||||||
 | 
					*.ico binary
 | 
				
			||||||
 | 
					*.jar binary
 | 
				
			||||||
 | 
					*.png binary
 | 
				
			||||||
 | 
					*.ttf binary
 | 
				
			||||||
 | 
					*.tza binary
 | 
				
			||||||
							
								
								
									
										381
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								engine/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,381 @@
 | 
				
			||||||
 | 
					# Godot .gitignore config
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Aims to encompass the most commonly found files that we don't want committed
 | 
				
			||||||
 | 
					# to Git, such as compilation output, IDE specific files, etc.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# It doesn't cover *all* thirdparty IDE extensions under the sun so if you have
 | 
				
			||||||
 | 
					# specific needs covered here, you can add them to:
 | 
				
			||||||
 | 
					#   .git/info/exclude
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Or contribute them to this file if they're common enough that a good number of
 | 
				
			||||||
 | 
					# users would benefit from the shared rules.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is organized by sections, with subsections ordered alphabetically.
 | 
				
			||||||
 | 
					# - Build configuration
 | 
				
			||||||
 | 
					# - Godot generated files
 | 
				
			||||||
 | 
					# - General build output
 | 
				
			||||||
 | 
					# - IDE and tool specific
 | 
				
			||||||
 | 
					# - Visual Studio specific
 | 
				
			||||||
 | 
					# - OS specific
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###########################
 | 
				
			||||||
 | 
					### Build configuration ###
 | 
				
			||||||
 | 
					###########################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/custom.py
 | 
				
			||||||
 | 
					misc/hooks/pre-commit-custom-*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#############################
 | 
				
			||||||
 | 
					### Godot generated files ###
 | 
				
			||||||
 | 
					#############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Buildsystem
 | 
				
			||||||
 | 
					bin
 | 
				
			||||||
 | 
					*.gen.*
 | 
				
			||||||
 | 
					compile_commands.json
 | 
				
			||||||
 | 
					platform/windows/godot_res.res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Ninja build files
 | 
				
			||||||
 | 
					build.ninja
 | 
				
			||||||
 | 
					.ninja
 | 
				
			||||||
 | 
					run_ninja_env.bat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generated by Godot binary
 | 
				
			||||||
 | 
					.import/
 | 
				
			||||||
 | 
					/gdextension_interface.h
 | 
				
			||||||
 | 
					extension_api.json
 | 
				
			||||||
 | 
					logs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generated by unit tests
 | 
				
			||||||
 | 
					tests/data/*.translation
 | 
				
			||||||
 | 
					tests/data/crypto/out*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					### General build output ###
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# C/C++ generated
 | 
				
			||||||
 | 
					*.a
 | 
				
			||||||
 | 
					*.ax
 | 
				
			||||||
 | 
					*.d
 | 
				
			||||||
 | 
					*.dll
 | 
				
			||||||
 | 
					*.lib
 | 
				
			||||||
 | 
					*.lo
 | 
				
			||||||
 | 
					*.o
 | 
				
			||||||
 | 
					*.os
 | 
				
			||||||
 | 
					*.ox
 | 
				
			||||||
 | 
					*.Plo
 | 
				
			||||||
 | 
					*.so
 | 
				
			||||||
 | 
					# Binutils tmp linker output of the form "stXXXXXX" where "X" is alphanumeric
 | 
				
			||||||
 | 
					st[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python development
 | 
				
			||||||
 | 
					.venv
 | 
				
			||||||
 | 
					venv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python generated
 | 
				
			||||||
 | 
					__pycache__/
 | 
				
			||||||
 | 
					*.pyc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Documentation
 | 
				
			||||||
 | 
					doc/_build/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Android
 | 
				
			||||||
 | 
					.gradle/
 | 
				
			||||||
 | 
					local.properties
 | 
				
			||||||
 | 
					*.iml
 | 
				
			||||||
 | 
					.gradletasknamecache
 | 
				
			||||||
 | 
					project.properties
 | 
				
			||||||
 | 
					platform/android/java/*/.cxx/
 | 
				
			||||||
 | 
					platform/android/java/*/build/
 | 
				
			||||||
 | 
					platform/android/java/*/libs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# iOS
 | 
				
			||||||
 | 
					*.dSYM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Web platform
 | 
				
			||||||
 | 
					*.bc
 | 
				
			||||||
 | 
					platform/web/node_modules/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Misc
 | 
				
			||||||
 | 
					*.debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#############################
 | 
				
			||||||
 | 
					### IDE and tool specific ###
 | 
				
			||||||
 | 
					#############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Automake
 | 
				
			||||||
 | 
					.deps/*
 | 
				
			||||||
 | 
					.dirstamp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ccls
 | 
				
			||||||
 | 
					.ccls-cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# clangd
 | 
				
			||||||
 | 
					.clangd/
 | 
				
			||||||
 | 
					.cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CLion
 | 
				
			||||||
 | 
					cmake-build-debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Code::Blocks
 | 
				
			||||||
 | 
					*.cbp
 | 
				
			||||||
 | 
					*.layout
 | 
				
			||||||
 | 
					*.depend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CodeLite
 | 
				
			||||||
 | 
					*.project
 | 
				
			||||||
 | 
					*.workspace
 | 
				
			||||||
 | 
					.codelite/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cppcheck
 | 
				
			||||||
 | 
					*.cppcheck
 | 
				
			||||||
 | 
					cppcheck-cppcheck-build-dir/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Eclipse CDT
 | 
				
			||||||
 | 
					.cproject
 | 
				
			||||||
 | 
					.settings/
 | 
				
			||||||
 | 
					*.pydevproject
 | 
				
			||||||
 | 
					*.launch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Emacs
 | 
				
			||||||
 | 
					\#*\#
 | 
				
			||||||
 | 
					.\#*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# GCOV code coverage
 | 
				
			||||||
 | 
					*.gcda
 | 
				
			||||||
 | 
					*.gcno
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Geany
 | 
				
			||||||
 | 
					*.geany
 | 
				
			||||||
 | 
					.geanyprj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Gprof
 | 
				
			||||||
 | 
					gmon.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Jetbrains IDEs
 | 
				
			||||||
 | 
					.idea/
 | 
				
			||||||
 | 
					.fleet/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Kate
 | 
				
			||||||
 | 
					*.kate-swp
 | 
				
			||||||
 | 
					.kateproject.build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Kdevelop
 | 
				
			||||||
 | 
					*.kdev4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mypy
 | 
				
			||||||
 | 
					.mypy_cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Qt Creator
 | 
				
			||||||
 | 
					*.config
 | 
				
			||||||
 | 
					*.creator
 | 
				
			||||||
 | 
					*.creator.*
 | 
				
			||||||
 | 
					*.files
 | 
				
			||||||
 | 
					*.includes
 | 
				
			||||||
 | 
					*.cflags
 | 
				
			||||||
 | 
					*.cxxflags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SCons
 | 
				
			||||||
 | 
					.sconf_temp
 | 
				
			||||||
 | 
					.sconsign*.dblite
 | 
				
			||||||
 | 
					.scons_env.json
 | 
				
			||||||
 | 
					.scons_node_count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Sourcetrail
 | 
				
			||||||
 | 
					*.srctrl*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tags
 | 
				
			||||||
 | 
					# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
 | 
				
			||||||
 | 
					# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
 | 
				
			||||||
 | 
					TAGS
 | 
				
			||||||
 | 
					!TAGS/
 | 
				
			||||||
 | 
					tags
 | 
				
			||||||
 | 
					*.tags
 | 
				
			||||||
 | 
					!tags/
 | 
				
			||||||
 | 
					gtags.files
 | 
				
			||||||
 | 
					GTAGS
 | 
				
			||||||
 | 
					GRTAGS
 | 
				
			||||||
 | 
					GPATH
 | 
				
			||||||
 | 
					cscope.files
 | 
				
			||||||
 | 
					cscope.out
 | 
				
			||||||
 | 
					cscope.in.out
 | 
				
			||||||
 | 
					cscope.po.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Vim
 | 
				
			||||||
 | 
					*.swo
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio Code
 | 
				
			||||||
 | 
					.vscode/
 | 
				
			||||||
 | 
					*.code-workspace
 | 
				
			||||||
 | 
					.history/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Xcode
 | 
				
			||||||
 | 
					xcuserdata/
 | 
				
			||||||
 | 
					*.xcscmblueprint
 | 
				
			||||||
 | 
					*.xccheckout
 | 
				
			||||||
 | 
					*.xcodeproj/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##############################
 | 
				
			||||||
 | 
					### Visual Studio specific ###
 | 
				
			||||||
 | 
					##############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
 | 
				
			||||||
 | 
					# Ignore Visual Studio temporary files, build results, and
 | 
				
			||||||
 | 
					# files generated by popular Visual Studio add-ons.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Actual VS project files we don't use
 | 
				
			||||||
 | 
					*.sln
 | 
				
			||||||
 | 
					*.vcxproj*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific files
 | 
				
			||||||
 | 
					*.rsuser
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.user
 | 
				
			||||||
 | 
					*.userosscache
 | 
				
			||||||
 | 
					*.sln.docstates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific files (MonoDevelop/Xamarin Studio)
 | 
				
			||||||
 | 
					*.userprefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build results
 | 
				
			||||||
 | 
					[Dd]ebug/
 | 
				
			||||||
 | 
					[Dd]ebugPublic/
 | 
				
			||||||
 | 
					[Rr]elease/
 | 
				
			||||||
 | 
					[Rr]eleases/
 | 
				
			||||||
 | 
					x64/
 | 
				
			||||||
 | 
					x86/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Ww][Ii][Nn]32/
 | 
				
			||||||
 | 
					[Aa][Rr][Mm]/
 | 
				
			||||||
 | 
					[Aa][Rr][Mm]64/
 | 
				
			||||||
 | 
					bld/
 | 
				
			||||||
 | 
					[Bb]in/
 | 
				
			||||||
 | 
					[Oo]bj/
 | 
				
			||||||
 | 
					[Ll]og/
 | 
				
			||||||
 | 
					[Ll]ogs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Do not ignore arch-specific folders anywhere under thirdparty libraries
 | 
				
			||||||
 | 
					!thirdparty/**/x64/
 | 
				
			||||||
 | 
					!thirdparty/**/x86/
 | 
				
			||||||
 | 
					!thirdparty/**/arm/
 | 
				
			||||||
 | 
					!thirdparty/**/arm64/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 2015/2017 cache/options directory
 | 
				
			||||||
 | 
					.vs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 2017 auto generated files
 | 
				
			||||||
 | 
					Generated\ Files/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Files built by Visual Studio
 | 
				
			||||||
 | 
					*_i.c
 | 
				
			||||||
 | 
					*_p.c
 | 
				
			||||||
 | 
					*_h.h
 | 
				
			||||||
 | 
					*.ilk
 | 
				
			||||||
 | 
					*.meta
 | 
				
			||||||
 | 
					*.obj
 | 
				
			||||||
 | 
					*.iobj
 | 
				
			||||||
 | 
					*.pch
 | 
				
			||||||
 | 
					*.pdb
 | 
				
			||||||
 | 
					*.ipdb
 | 
				
			||||||
 | 
					*.pgc
 | 
				
			||||||
 | 
					*.pgd
 | 
				
			||||||
 | 
					*.rsp
 | 
				
			||||||
 | 
					*.sbr
 | 
				
			||||||
 | 
					*.tlb
 | 
				
			||||||
 | 
					*.tli
 | 
				
			||||||
 | 
					*.tlh
 | 
				
			||||||
 | 
					*.tmp
 | 
				
			||||||
 | 
					*.tmp_proj
 | 
				
			||||||
 | 
					*_wpftmp.csproj
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.tlog
 | 
				
			||||||
 | 
					*.vspscc
 | 
				
			||||||
 | 
					*.vssscc
 | 
				
			||||||
 | 
					.builds
 | 
				
			||||||
 | 
					*.pidb
 | 
				
			||||||
 | 
					*.svclog
 | 
				
			||||||
 | 
					*.scc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual C++ cache files
 | 
				
			||||||
 | 
					ipch/
 | 
				
			||||||
 | 
					*.aps
 | 
				
			||||||
 | 
					*.ncb
 | 
				
			||||||
 | 
					*.opendb
 | 
				
			||||||
 | 
					*.opensdf
 | 
				
			||||||
 | 
					*.sdf
 | 
				
			||||||
 | 
					*.cachefile
 | 
				
			||||||
 | 
					*.VC.db
 | 
				
			||||||
 | 
					*.VC.VC.opendb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio profiler
 | 
				
			||||||
 | 
					*.psess
 | 
				
			||||||
 | 
					*.vsp
 | 
				
			||||||
 | 
					*.vspx
 | 
				
			||||||
 | 
					*.sap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio Trace Files
 | 
				
			||||||
 | 
					*.e2e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ReSharper is a .NET coding add-in
 | 
				
			||||||
 | 
					_ReSharper*/
 | 
				
			||||||
 | 
					*.[Rr]e[Ss]harper
 | 
				
			||||||
 | 
					*.DotSettings.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio cache files
 | 
				
			||||||
 | 
					# files ending in .cache can be ignored
 | 
				
			||||||
 | 
					*.[Cc]ache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Others
 | 
				
			||||||
 | 
					ClientBin/
 | 
				
			||||||
 | 
					enc_temp_folder/
 | 
				
			||||||
 | 
					~$*
 | 
				
			||||||
 | 
					*.dbmdl
 | 
				
			||||||
 | 
					*.dbproj.schemaview
 | 
				
			||||||
 | 
					*.jfm
 | 
				
			||||||
 | 
					*.pfx
 | 
				
			||||||
 | 
					*.publishsettings
 | 
				
			||||||
 | 
					orleans.codegen.cs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Backup & report files from converting an old project file
 | 
				
			||||||
 | 
					# to a newer Visual Studio version. Backup files are not needed,
 | 
				
			||||||
 | 
					# because we have git ;-)
 | 
				
			||||||
 | 
					_UpgradeReport_Files/
 | 
				
			||||||
 | 
					Backup*/
 | 
				
			||||||
 | 
					UpgradeLog*.XML
 | 
				
			||||||
 | 
					UpgradeLog*.htm
 | 
				
			||||||
 | 
					ServiceFabricBackup/
 | 
				
			||||||
 | 
					*.rptproj.bak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Hint file for IntelliSense
 | 
				
			||||||
 | 
					cpp.hint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###################
 | 
				
			||||||
 | 
					### OS specific ###
 | 
				
			||||||
 | 
					###################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Linux
 | 
				
			||||||
 | 
					*~
 | 
				
			||||||
 | 
					.directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# macOS
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					__MACOSX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows
 | 
				
			||||||
 | 
					# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
 | 
				
			||||||
 | 
					[Tt]humbs.db
 | 
				
			||||||
 | 
					[Tt]humbs.db:encryptable
 | 
				
			||||||
 | 
					ehthumbs.db
 | 
				
			||||||
 | 
					ehthumbs_vista.db
 | 
				
			||||||
 | 
					*.stackdump
 | 
				
			||||||
 | 
					[Dd]esktop.ini
 | 
				
			||||||
 | 
					$RECYCLE.BIN/
 | 
				
			||||||
 | 
					*.cab
 | 
				
			||||||
 | 
					*.msi
 | 
				
			||||||
 | 
					*.msix
 | 
				
			||||||
 | 
					*.msm
 | 
				
			||||||
 | 
					*.msp
 | 
				
			||||||
 | 
					*.lnk
 | 
				
			||||||
 | 
					*.generated.props
 | 
				
			||||||
							
								
								
									
										182
									
								
								engine/.mailmap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								engine/.mailmap
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,182 @@
 | 
				
			||||||
 | 
					Aaron Record <aaronjrecord@gmail.com>
 | 
				
			||||||
 | 
					ajreckof <66184050+ajreckof@users.noreply.github.com> <tbonhoure@ymail.com>
 | 
				
			||||||
 | 
					Alexander Holland <alexander.holland@live.de>
 | 
				
			||||||
 | 
					Alexander Holland <alexander.holland@live.de> <alexander.holland@haw-hamburg.de>
 | 
				
			||||||
 | 
					Alexander Holland <alexander.holland@live.de> <AlexHolly>
 | 
				
			||||||
 | 
					Alfred Reinold Baudisch <alfred@alfredbaudisch.com>
 | 
				
			||||||
 | 
					Andrea Catania <info@andreacatania.com>
 | 
				
			||||||
 | 
					Anish Bhobe <anishbhobe@hotmail.com>
 | 
				
			||||||
 | 
					Anutrix <numaanzaheerahmed@yahoo.com>
 | 
				
			||||||
 | 
					Aren Villanueva <arenvillanueva@yomogi-soft.com> <aren@displaysweet.com>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org> <puntob@gmail.com>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org> <punto@godotengine.org>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org> <ariel@okamstudio.com>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini.local>
 | 
				
			||||||
 | 
					Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini-2.local>
 | 
				
			||||||
 | 
					Arman Elgudzhyan <48544263+puchik@users.noreply.github.com>
 | 
				
			||||||
 | 
					A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> <over999ships@gmail.com>
 | 
				
			||||||
 | 
					Bastiaan Olij <mux213@gmail.com>
 | 
				
			||||||
 | 
					Benjamin <mafortion.benjamin@gmail.com>
 | 
				
			||||||
 | 
					Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.de>
 | 
				
			||||||
 | 
					Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.org>
 | 
				
			||||||
 | 
					Bruno Lourenço <madequa@users.noreply.github.com> <bmlourenco@gmail.com>
 | 
				
			||||||
 | 
					Chaosus <chaosus89@gmail.com>
 | 
				
			||||||
 | 
					ChibiDenDen <pdaniq@gmail.com>
 | 
				
			||||||
 | 
					Chris Bradfield <chris@kidscancode.org> <cb@scribe.net>
 | 
				
			||||||
 | 
					Clay John <claynjohn@gmail.com>
 | 
				
			||||||
 | 
					Clay John <claynjohn@gmail.com> <clayjohn@shaw.ca>
 | 
				
			||||||
 | 
					CookieBadger <emil.dobetsberger@gmail.com>
 | 
				
			||||||
 | 
					Dana Olson <dana@shineuponthee.com> <adolson@gmail.com>
 | 
				
			||||||
 | 
					dankan1890 <mewuidev2@gmail.com>
 | 
				
			||||||
 | 
					Daniel J. Ramirez <djrmuv@gmail.com>
 | 
				
			||||||
 | 
					David Cambré <david.cambre@gmail.com> <David.Cambre@gmail.com>
 | 
				
			||||||
 | 
					DmitriySalnikov <salnikov.mine@yandex.ru>
 | 
				
			||||||
 | 
					DmitriySalnikov <salnikov.mine@yandex.ru> <dimokgamer@gmail.com>
 | 
				
			||||||
 | 
					Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
 | 
				
			||||||
 | 
					DeeJayLSP <djlsplays@gmail.com> <60024671+DeeJayLSP@users.noreply.github.com>
 | 
				
			||||||
 | 
					Emmanuel Barroga <emmanuelbarroga@gmail.com>
 | 
				
			||||||
 | 
					Eric M <itsjusteza@gmail.com>
 | 
				
			||||||
 | 
					Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
 | 
				
			||||||
 | 
					Erik Selecký <35656626+rxlecky@users.noreply.github.com>
 | 
				
			||||||
 | 
					Erik Selecký <35656626+rxlecky@users.noreply.github.com> <35656626+SeleckyErik@users.noreply.github.com>
 | 
				
			||||||
 | 
					Eveline Jarosz <marqin.pl@gmail.com>
 | 
				
			||||||
 | 
					Eveline Jarosz <marqin.pl@gmail.com> <marqin.pl+git@gmail.com>
 | 
				
			||||||
 | 
					Fabian <supagu@gmail.com>
 | 
				
			||||||
 | 
					Ferenc Arn <tagcup@yahoo.com>
 | 
				
			||||||
 | 
					Ferenc Arn <tagcup@yahoo.com> <tagcup@users.noreply.github.com>
 | 
				
			||||||
 | 
					FireForge <67974470+fire-forge@users.noreply.github.com> <isaacr.7.2005@gmail.com>
 | 
				
			||||||
 | 
					Florian Kothmeier <floriankothmeier@web.de>
 | 
				
			||||||
 | 
					foxydevloper <12120644+foxydevloper@users.noreply.github.com>
 | 
				
			||||||
 | 
					Fredia Huya-Kouadio <fhuyakou@gmail.com>
 | 
				
			||||||
 | 
					Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@google.com>
 | 
				
			||||||
 | 
					Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@fb.com>
 | 
				
			||||||
 | 
					Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@meta.com>
 | 
				
			||||||
 | 
					Geequlim <geequlim@gmail.com>
 | 
				
			||||||
 | 
					Gilles Roudiere <gilles.roudiere@gmail.com>
 | 
				
			||||||
 | 
					Gilles Roudiere <gilles.roudiere@gmail.com> <gilles.roudiere@laas.fr>
 | 
				
			||||||
 | 
					Gordon MacPherson <gordon@gordonite.tech>
 | 
				
			||||||
 | 
					Guilherme Felipe <guilhermefelipecgs@gmail.com>
 | 
				
			||||||
 | 
					Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
 | 
				
			||||||
 | 
					HaSa1002 <johawitt@outlook.de>
 | 
				
			||||||
 | 
					Hein-Pieter van Braam-Stewart <hp@tmm.cx>
 | 
				
			||||||
 | 
					Hugo Locurcio <hugo.locurcio@hugo.pro> <hugo.l@openmailbox.org>
 | 
				
			||||||
 | 
					Hugo Locurcio <hugo.locurcio@hugo.pro> <Calinou@users.noreply.github.com>
 | 
				
			||||||
 | 
					Hugo Locurcio <hugo.locurcio@hugo.pro> Calinou <calinou@opmbx.org>
 | 
				
			||||||
 | 
					Ian Bishop <ianb96@gmail.com>
 | 
				
			||||||
 | 
					Ignacio Etcheverry <ignalfonsore@gmail.com>
 | 
				
			||||||
 | 
					Ignacio Etcheverry <ignalfonsore@gmail.com> <neikeq@users.noreply.github.com>
 | 
				
			||||||
 | 
					Ilaria Cislaghi <cislaghi.ilaria@gmail.com>
 | 
				
			||||||
 | 
					Ilaria Cislaghi <cislaghi.ilaria@gmail.com> <ilaria.cislaghi@simedis.com>
 | 
				
			||||||
 | 
					Indah Sylvia <ISylvox@yahoo.com>
 | 
				
			||||||
 | 
					Ivan Shakhov <ivan.shakhov@jetbrains.com> <Ivan.Shakhov@jetbrains.com>
 | 
				
			||||||
 | 
					Ivan Shakhov <ivan.shakhov@jetbrains.com> <van800@gmail.com>
 | 
				
			||||||
 | 
					iwek <miwanczuk7@gmail.com>
 | 
				
			||||||
 | 
					J08nY <johny@neuromancer.sk> <jancar.jj@gmail.com>
 | 
				
			||||||
 | 
					J08nY <johny@neuromancer.sk> <J08nY@users.noreply.github.com>
 | 
				
			||||||
 | 
					Jake Young <young9003@gmail.com>
 | 
				
			||||||
 | 
					Jakub Grzesik <kubecz3k@gmail.com>
 | 
				
			||||||
 | 
					Jakub Marcowski <chubercikbattle@gmail.com> <01158831@pw.edu.pl>
 | 
				
			||||||
 | 
					Jakub Marcowski <chubercikbattle@gmail.com> <37378746+Chubercik@users.noreply.github.com>
 | 
				
			||||||
 | 
					janglee <merupatel123@gmail.com>
 | 
				
			||||||
 | 
					Jason Knight <00jknight@gmail.com> <jason@winterpixel.com>
 | 
				
			||||||
 | 
					Jean-Michel Bernard <jmb462@gmail.com>
 | 
				
			||||||
 | 
					Jérôme Gully <jerome.gully0@gmail.com>
 | 
				
			||||||
 | 
					JFonS <joan.fonssanchez@gmail.com>
 | 
				
			||||||
 | 
					jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
 | 
				
			||||||
 | 
					Juan Linietsky <reduzio@gmail.com>
 | 
				
			||||||
 | 
					Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
 | 
				
			||||||
 | 
					Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
 | 
				
			||||||
 | 
					Juan Linietsky <reduzio@gmail.com> <reduz@Juans-MBP.fibertel.com.ar>
 | 
				
			||||||
 | 
					Juan Linietsky <reduzio@gmail.com> <red@kyoko>
 | 
				
			||||||
 | 
					Julian Murgia <the.straton@gmail.com>
 | 
				
			||||||
 | 
					Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com>
 | 
				
			||||||
 | 
					karroffel <therzog@mail.de>
 | 
				
			||||||
 | 
					karroffel <therzog@mail.de> <thomas.herzog@mail.com>
 | 
				
			||||||
 | 
					karroffel <therzog@mail.de> <thomas.herzog@simedis.com>
 | 
				
			||||||
 | 
					Kelly Thomas <kelly.thomas@hotmail.com.au>
 | 
				
			||||||
 | 
					Kongfa Waroros <gongpha@hotmail.com>
 | 
				
			||||||
 | 
					K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
 | 
				
			||||||
 | 
					kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
 | 
				
			||||||
 | 
					Leon Krause <lk@leonkrause.com> <eska@eska.me>
 | 
				
			||||||
 | 
					Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
 | 
				
			||||||
 | 
					Liz Haas <27thLiz@gmail.com>
 | 
				
			||||||
 | 
					Liz Haas <27thLiz@gmail.com> <liu.gam3@gmail.com>
 | 
				
			||||||
 | 
					Liz Haas <27thLiz@gmail.com> <hinsbart@gmail.com>
 | 
				
			||||||
 | 
					Liz Haas <27thLiz@gmail.com> <hinsbart@users.noreply.github.com>
 | 
				
			||||||
 | 
					Liz Haas <27thLiz@gmail.com> <entenflugstuhl@gmail.com>
 | 
				
			||||||
 | 
					Manuele Finocchiaro <m4nu3lf@gmail.com>
 | 
				
			||||||
 | 
					Manuel Strey <manuel.strey@gmx.de>
 | 
				
			||||||
 | 
					Marcel Admiraal <madmiraal@users.noreply.github.com>
 | 
				
			||||||
 | 
					Marcelo Fernandez <marcelofg55@gmail.com>
 | 
				
			||||||
 | 
					Marcin Zawiejski <dragmz@gmail.com>
 | 
				
			||||||
 | 
					Marcus Elg <marcusaccounts@yahoo.se>
 | 
				
			||||||
 | 
					Mariano Javier Suligoy <marianognu.easyrpg@gmail.com>
 | 
				
			||||||
 | 
					Mario Schlack <m4r10.5ch14ck@gmail.com>
 | 
				
			||||||
 | 
					Mark DiBarry <markdibarry@protonmail.com>
 | 
				
			||||||
 | 
					marxin <mliska@suse.cz>
 | 
				
			||||||
 | 
					marynate <mary.w.nate@gmail.com> <marynate@github.com>
 | 
				
			||||||
 | 
					Mateo Kuruk Miccino <mateomiccino@gmail.com>
 | 
				
			||||||
 | 
					Max Hilbrunner <m.hilbrunner@gmail.com>
 | 
				
			||||||
 | 
					Max Hilbrunner <m.hilbrunner@gmail.com> <mhilbrunner@users.noreply.github.com>
 | 
				
			||||||
 | 
					MewPurPur <mew.pur.pur@abv.bg>
 | 
				
			||||||
 | 
					Michael Alexsander <michaelalexsander@protonmail.com>
 | 
				
			||||||
 | 
					Micky <micheledevita2@gmail.com> <66727710+Mickeon@users.noreply.github.com>
 | 
				
			||||||
 | 
					Nathan Franke <natfra@pm.me> <nathanwfranke@gmail.com>
 | 
				
			||||||
 | 
					Nathan Lovato <nathan@gdquest.com>
 | 
				
			||||||
 | 
					Nathan Warden <nathan@nathanwarden.com> <nathanwardenlee@icloud.com>
 | 
				
			||||||
 | 
					Nicholas Huelin <62965063+SirQuartz@users.noreply.github.com>
 | 
				
			||||||
 | 
					Nils ANDRÉ-CHANG <nils@nilsand.re>
 | 
				
			||||||
 | 
					Nils ANDRÉ-CHANG <nils@nilsand.re> <nils.andre.chang@gmail.com>
 | 
				
			||||||
 | 
					Nông Văn Tình <vannongtinh@gmail.com>
 | 
				
			||||||
 | 
					Nuno Donato <nunodonato@gmail.com> <n.donato@estrelasustentavel.pt>
 | 
				
			||||||
 | 
					ocean (they/them) <anvilfolk@gmail.com>
 | 
				
			||||||
 | 
					Pawel Kowal <pkowal1982@gmail.com>
 | 
				
			||||||
 | 
					Pedro J. Estébanez <pedrojrulez@gmail.com> <RandomShaper@users.noreply.github.com>
 | 
				
			||||||
 | 
					Patrick Exner <patrick.exner1@web.de>
 | 
				
			||||||
 | 
					Patrick <firefly2442@gmail.com>
 | 
				
			||||||
 | 
					Paul Batty <p_batty@hotmail.co.uk>
 | 
				
			||||||
 | 
					Paul Batty <p_batty@hotmail.co.uk> <Paulb23@users.noreply.github.com>
 | 
				
			||||||
 | 
					Pawel Kowal <pkowal1982@gmail.com> <pawel.kowal@javart.eu>
 | 
				
			||||||
 | 
					Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
 | 
				
			||||||
 | 
					Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
 | 
				
			||||||
 | 
					Poommetee Ketson <poommetee@protonmail.com>
 | 
				
			||||||
 | 
					Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
 | 
				
			||||||
 | 
					Rafał Mikrut <mikrutrafal@protonmail.com>
 | 
				
			||||||
 | 
					Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
 | 
				
			||||||
 | 
					Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
 | 
				
			||||||
 | 
					Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@users.noreply.github.com>
 | 
				
			||||||
 | 
					Ramesh Ravone <ramesh.maran443@gmail.com>
 | 
				
			||||||
 | 
					RaphaelHunter <raphael10241024@gmail.com>
 | 
				
			||||||
 | 
					RaphaelHunter <raphael10241024@gmail.com> <Raphael10241024@gmail.com>
 | 
				
			||||||
 | 
					RaphaelHunter <raphael10241024@gmail.com> <raphael20141024@gmail.com>
 | 
				
			||||||
 | 
					Rémi Verschelde <rverschelde@gmail.com> <remi@verschelde.fr>
 | 
				
			||||||
 | 
					Rhody Lugo <rhodylugo@gmail.com> <rhodylugo@me.com>
 | 
				
			||||||
 | 
					Ricardo Subtil <ricasubtil@gmail.com>
 | 
				
			||||||
 | 
					Rindbee <idleman@yeah.net>
 | 
				
			||||||
 | 
					Riteo Siuga <riteo@posteo.net>
 | 
				
			||||||
 | 
					Robin Hübner <profan@prfn.se> <robinhubner@gmail.com>
 | 
				
			||||||
 | 
					romulox_x <romulox_x@yahoo.com>
 | 
				
			||||||
 | 
					rune-scape <allie.smith.epic@gmail.com>
 | 
				
			||||||
 | 
					rune-scape <allie.smith.epic@gmail.com> <spartacrafter@gmail.com>
 | 
				
			||||||
 | 
					Ruslan Mustakov <r.mustakov@gmail.com> <ruslan.mustakov@xored.com>
 | 
				
			||||||
 | 
					Saracen <SaracenOne@gmail.com>
 | 
				
			||||||
 | 
					sheepandshepherd <sheepandshepherd@hotmail.com> <sheepandshepherd@users.noreply.github.com>
 | 
				
			||||||
 | 
					Silc 'Tokage' Renew <tokage.it.lab@gmail.com>
 | 
				
			||||||
 | 
					Silc 'Tokage' Renew <tokage.it.lab@gmail.com> <61938263+TokageItLab@users.noreply.github.com>
 | 
				
			||||||
 | 
					Swarnim Arun <swarnimarun11@gmail.com>
 | 
				
			||||||
 | 
					TechnoPorg <jonah.janzen@gmail.com> <69441745+TechnoPorg@users.noreply.github.com>
 | 
				
			||||||
 | 
					Theo Hallenius <redsymbzone@hotmail.com>
 | 
				
			||||||
 | 
					Tomasz Chabora <kobewi4e@gmail.com>
 | 
				
			||||||
 | 
					Twarit <wtwarit@gmail.com>
 | 
				
			||||||
 | 
					Vitika9 <vitika.program@gmail.com>
 | 
				
			||||||
 | 
					V.VamsiKrishna <vk@bsb.in> <vamsikrishna.v@gmail.com>
 | 
				
			||||||
 | 
					Wilhem Barbier <nounoursheureux@openmailbox.org> <wilhem.b@free.fr>
 | 
				
			||||||
 | 
					Wilhem Barbier <nounoursheureux@openmailbox.org> <schtroumps31@gmail.com>
 | 
				
			||||||
 | 
					Will Nations <willnationsdev@gmail.com>
 | 
				
			||||||
 | 
					yg2f <yoann@terminajones.com>
 | 
				
			||||||
 | 
					Yuri Sizov <yuris@humnom.net> <pycbouh@users.noreply.github.com>
 | 
				
			||||||
 | 
					Yuri Sizov <yuris@humnom.net> <yaschik4ilicha@gmail.com>
 | 
				
			||||||
 | 
					Zae <zaevi@live.com>
 | 
				
			||||||
 | 
					Zak Stam <zakscomputers@hotmail.com>
 | 
				
			||||||
 | 
					Zher Huei Lee <lee.zh.92@gmail.com>
 | 
				
			||||||
							
								
								
									
										184
									
								
								engine/.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								engine/.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,184 @@
 | 
				
			||||||
 | 
					default_language_version:
 | 
				
			||||||
 | 
					  python: python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exclude: |
 | 
				
			||||||
 | 
					  (?x)^(
 | 
				
			||||||
 | 
					    .*thirdparty/.*|
 | 
				
			||||||
 | 
					    .*-so_wrap\.(h|c)$
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					repos:
 | 
				
			||||||
 | 
					  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
				
			||||||
 | 
					    rev: v17.0.6
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: clang-format
 | 
				
			||||||
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					        exclude: |
 | 
				
			||||||
 | 
					          (?x)^(
 | 
				
			||||||
 | 
					            tests/python_build/.*|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/com/.*
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - repo: https://github.com/pocc/pre-commit-hooks
 | 
				
			||||||
 | 
					    rev: v1.3.5
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: clang-tidy
 | 
				
			||||||
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
 | 
				
			||||||
 | 
					        args: [--fix, --quiet, --use-color]
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					        exclude: |
 | 
				
			||||||
 | 
					          (?x)^(
 | 
				
			||||||
 | 
					            tests/python_build/.*|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/com/.*
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        additional_dependencies: [clang-tidy==18.1.1]
 | 
				
			||||||
 | 
					        require_serial: true
 | 
				
			||||||
 | 
					        stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
				
			||||||
 | 
					    rev: v0.4.4
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: ruff
 | 
				
			||||||
 | 
					        args: [--fix]
 | 
				
			||||||
 | 
					      - id: ruff-format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - repo: https://github.com/pre-commit/mirrors-mypy
 | 
				
			||||||
 | 
					    rev: v0.971
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: mypy
 | 
				
			||||||
 | 
					        files: \.py$
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - repo: https://github.com/codespell-project/codespell
 | 
				
			||||||
 | 
					    rev: v2.3.0
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: codespell
 | 
				
			||||||
 | 
					        additional_dependencies: [tomli]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ### Requires Docker; look into alternative implementation.
 | 
				
			||||||
 | 
					  # - repo: https://github.com/comkieffer/pre-commit-xmllint.git
 | 
				
			||||||
 | 
					  #   rev: 1.0.0
 | 
				
			||||||
 | 
					  #   hooks:
 | 
				
			||||||
 | 
					  #     - id: xmllint
 | 
				
			||||||
 | 
					  #       language: docker
 | 
				
			||||||
 | 
					  #       types_or: [text]
 | 
				
			||||||
 | 
					  #       files: ^(doc/classes|.*/doc_classes)/.*\.xml$
 | 
				
			||||||
 | 
					  #       args: [--schema, doc/class.xsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - repo: local
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: make-rst
 | 
				
			||||||
 | 
					        name: make-rst
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python doc/tools/make_rst.py
 | 
				
			||||||
 | 
					        args: [doc/classes, modules, platform, --dry-run, --color]
 | 
				
			||||||
 | 
					        pass_filenames: false
 | 
				
			||||||
 | 
					        files: ^(doc/classes|.*/doc_classes)/.*\.xml$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: doc-status
 | 
				
			||||||
 | 
					        name: doc-status
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python doc/tools/doc_status.py
 | 
				
			||||||
 | 
					        args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes]
 | 
				
			||||||
 | 
					        pass_filenames: false
 | 
				
			||||||
 | 
					        files: ^(doc/classes|.*/doc_classes)/.*\.xml$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: eslint
 | 
				
			||||||
 | 
					        name: eslint
 | 
				
			||||||
 | 
					        language: node
 | 
				
			||||||
 | 
					        entry: eslint
 | 
				
			||||||
 | 
					        files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
 | 
				
			||||||
 | 
					        args: [--fix, --no-warn-ignored, --no-config-lookup, --config, platform/web/eslint.config.cjs]
 | 
				
			||||||
 | 
					        additional_dependencies:
 | 
				
			||||||
 | 
					          - '@eslint/js@^9.3.0'
 | 
				
			||||||
 | 
					          - '@html-eslint/eslint-plugin@^0.24.1'
 | 
				
			||||||
 | 
					          - '@html-eslint/parser@^0.24.1'
 | 
				
			||||||
 | 
					          - '@stylistic/eslint-plugin@^2.1.0'
 | 
				
			||||||
 | 
					          - 'eslint@^9.3.0'
 | 
				
			||||||
 | 
					          - 'eslint-plugin-html@^8.1.1'
 | 
				
			||||||
 | 
					          - 'globals@^15.3.0'
 | 
				
			||||||
 | 
					          - 'espree@^10.0.1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: jsdoc
 | 
				
			||||||
 | 
					        name: jsdoc
 | 
				
			||||||
 | 
					        language: node
 | 
				
			||||||
 | 
					        entry: jsdoc
 | 
				
			||||||
 | 
					        files: ^platform/web/js/engine/(engine|config|features)\.js$
 | 
				
			||||||
 | 
					        args:
 | 
				
			||||||
 | 
					          - --template
 | 
				
			||||||
 | 
					          - platform/web/js/jsdoc2rst/
 | 
				
			||||||
 | 
					          - platform/web/js/engine/engine.js
 | 
				
			||||||
 | 
					          - platform/web/js/engine/config.js
 | 
				
			||||||
 | 
					          - platform/web/js/engine/features.js
 | 
				
			||||||
 | 
					          - --destination
 | 
				
			||||||
 | 
					          - ''
 | 
				
			||||||
 | 
					          - -d
 | 
				
			||||||
 | 
					          - dry-run
 | 
				
			||||||
 | 
					        pass_filenames: false
 | 
				
			||||||
 | 
					        additional_dependencies: ['jsdoc@^4.0.3']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: svgo
 | 
				
			||||||
 | 
					        name: svgo
 | 
				
			||||||
 | 
					        language: node
 | 
				
			||||||
 | 
					        entry: svgo
 | 
				
			||||||
 | 
					        files: \.svg$
 | 
				
			||||||
 | 
					        args: [--quiet, --config, misc/utility/svgo.config.mjs]
 | 
				
			||||||
 | 
					        additional_dependencies: ["svgo@3.3.2"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: copyright-headers
 | 
				
			||||||
 | 
					        name: copyright-headers
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python misc/scripts/copyright_headers.py
 | 
				
			||||||
 | 
					        files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
 | 
				
			||||||
 | 
					        exclude: |
 | 
				
			||||||
 | 
					          (?x)^(
 | 
				
			||||||
 | 
					            core/math/bvh_.*\.inc$|
 | 
				
			||||||
 | 
					            platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/com/.*|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java$|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java$|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java$
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: header-guards
 | 
				
			||||||
 | 
					        name: header-guards
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python misc/scripts/header_guards.py
 | 
				
			||||||
 | 
					        files: \.(h|hpp|hh|hxx)$
 | 
				
			||||||
 | 
					        exclude: ^.*/(thread|platform_config|platform_gl)\.h$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: file-format
 | 
				
			||||||
 | 
					        name: file-format
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python misc/scripts/file_format.py
 | 
				
			||||||
 | 
					        types_or: [text]
 | 
				
			||||||
 | 
					        exclude: |
 | 
				
			||||||
 | 
					          (?x)^(
 | 
				
			||||||
 | 
					            .*\.test\.txt$|
 | 
				
			||||||
 | 
					            .*\.svg$|
 | 
				
			||||||
 | 
					            .*\.patch$|
 | 
				
			||||||
 | 
					            .*\.out$|
 | 
				
			||||||
 | 
					            modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd$|
 | 
				
			||||||
 | 
					            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
 | 
				
			||||||
 | 
					            modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
 | 
				
			||||||
 | 
					            platform/android/java/lib/src/com/google/.*
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - id: dotnet-format
 | 
				
			||||||
 | 
					        name: dotnet-format
 | 
				
			||||||
 | 
					        language: python
 | 
				
			||||||
 | 
					        entry: python misc/scripts/dotnet_format.py
 | 
				
			||||||
 | 
					        types_or: [c#]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# End of upstream Godot pre-commit hooks.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Keep this separation to let downstream forks add their own hooks to this file,
 | 
				
			||||||
 | 
					# without running into merge conflicts when rebasing on latest upstream.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Start of downstream pre-commit hooks.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This is still the "repo: local" scope, so new local hooks can be defined directly at this indentation:
 | 
				
			||||||
 | 
					#     - id: new-local-hook
 | 
				
			||||||
 | 
					# To add external repo hooks, bring the indentation back to:
 | 
				
			||||||
 | 
					# - repo: my-remote-hook
 | 
				
			||||||
							
								
								
									
										321
									
								
								engine/AUTHORS.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								engine/AUTHORS.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,321 @@
 | 
				
			||||||
 | 
					# Godot Engine authors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Godot Engine is developed by a community of voluntary contributors who
 | 
				
			||||||
 | 
					contribute code, bug reports, documentation, artwork, support, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is impossible to list them all; nevertheless, this file aims at listing
 | 
				
			||||||
 | 
					the developers who contributed significant patches to this MIT licensed
 | 
				
			||||||
 | 
					source code. "Significant" is arbitrarily decided, but should be fair :)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GitHub usernames are indicated in parentheses, or as sole entry when no other
 | 
				
			||||||
 | 
					name is available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Project Founders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Juan Linietsky (reduz)
 | 
				
			||||||
 | 
					    Ariel Manzur (punto-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Lead Developer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Juan Linietsky (reduz)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Project Manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Rémi Verschelde (akien-mga)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Developers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(in alphabetical order, with over 10 commits excluding merges)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Aaron Franke (aaronfranke)
 | 
				
			||||||
 | 
					    Aaron Pagano (aaronp64)
 | 
				
			||||||
 | 
					    Aaron Record (LightningAA)
 | 
				
			||||||
 | 
					    Adam Scott (adamscott)
 | 
				
			||||||
 | 
					    Alexander Hartmann (Alex2782)
 | 
				
			||||||
 | 
					    Alexander Holland (AlexHolly)
 | 
				
			||||||
 | 
					    Alex Drozd (brno32)
 | 
				
			||||||
 | 
					    Alexey Khoroshavin (allkhor)
 | 
				
			||||||
 | 
					    Alfred Reinold Baudisch (alfredbaudisch)
 | 
				
			||||||
 | 
					    Alistair Leslie-Hughes (alesliehughes)
 | 
				
			||||||
 | 
					    Alket Rexhepi (alketii)
 | 
				
			||||||
 | 
					    Andrea Catania (AndreaCatania)
 | 
				
			||||||
 | 
					    Andreia Gaita (shana)
 | 
				
			||||||
 | 
					    Andrii Doroshenko (Xrayez)
 | 
				
			||||||
 | 
					    Andy Maloney (asmaloney)
 | 
				
			||||||
 | 
					    Andy Moss (MillionOstrich)
 | 
				
			||||||
 | 
					    Angad Kambli (angad-k)
 | 
				
			||||||
 | 
					    Anilforextra (AnilBK)
 | 
				
			||||||
 | 
					    Anish Bhobe (KidRigger)
 | 
				
			||||||
 | 
					    Anton Yabchinskiy (a12n)
 | 
				
			||||||
 | 
					    Anutrix
 | 
				
			||||||
 | 
					    Aren Villanueva (kurikaesu)
 | 
				
			||||||
 | 
					    Ariel Manzur (punto-)
 | 
				
			||||||
 | 
					    Arman Elgudzhyan (puchik)
 | 
				
			||||||
 | 
					    AThousandShips
 | 
				
			||||||
 | 
					    aXu-AP
 | 
				
			||||||
 | 
					    Bartłomiej T. Listwon (Listwon)
 | 
				
			||||||
 | 
					    Bastiaan Olij (BastiaanOlij)
 | 
				
			||||||
 | 
					    Ben Brookshire (sheepandshepherd)
 | 
				
			||||||
 | 
					    Benjamin Larsson (Nallebeorn)
 | 
				
			||||||
 | 
					    Bernhard Liebl (poke1024)
 | 
				
			||||||
 | 
					    Bhuvan Vemula (Bhu1-V)
 | 
				
			||||||
 | 
					    bitsawer
 | 
				
			||||||
 | 
					    Błażej Szczygieł (zaps166)
 | 
				
			||||||
 | 
					    BlueCube3310
 | 
				
			||||||
 | 
					    Bojidar Marinov (bojidar-bg)
 | 
				
			||||||
 | 
					    Brian Semrau (briansemrau)
 | 
				
			||||||
 | 
					    Bruno Lourenço (MadEqua)
 | 
				
			||||||
 | 
					    Cameron Reikes (creikey)
 | 
				
			||||||
 | 
					    Camille Mohr-Daurat (pouleyKetchoupp)
 | 
				
			||||||
 | 
					    Caner Demirer (cdemirer)
 | 
				
			||||||
 | 
					    Carl Olsson (not-surt)
 | 
				
			||||||
 | 
					    Carter Anderson (cart)
 | 
				
			||||||
 | 
					    ChibiDenDen
 | 
				
			||||||
 | 
					    Chris Bradfield (cbscribe)
 | 
				
			||||||
 | 
					    Christian Kaiser (ckaiser)
 | 
				
			||||||
 | 
					    Clay John (clayjohn)
 | 
				
			||||||
 | 
					    ConteZero
 | 
				
			||||||
 | 
					    CookieBadger
 | 
				
			||||||
 | 
					    Dana Olson (adolson)
 | 
				
			||||||
 | 
					    Daniel J. Ramirez (djrm)
 | 
				
			||||||
 | 
					    Daniel Rakos (aqnuep)
 | 
				
			||||||
 | 
					    Daniel Zilberleyb (dzil123)
 | 
				
			||||||
 | 
					    Danil Alexeev (dalexeev)
 | 
				
			||||||
 | 
					    dankan1890
 | 
				
			||||||
 | 
					    Darío Banini (DarioSamo)
 | 
				
			||||||
 | 
					    David Cambré (Gallilus)
 | 
				
			||||||
 | 
					    David Sichma (DavidSichma)
 | 
				
			||||||
 | 
					    David Snopek (dsnopek)
 | 
				
			||||||
 | 
					    Dharkael (lupoDharkael)
 | 
				
			||||||
 | 
					    Dmitry Koteroff (Krakean)
 | 
				
			||||||
 | 
					    Dmitry Maganov (vonagam)
 | 
				
			||||||
 | 
					    Dominik Jasiński (dreamsComeTrue)
 | 
				
			||||||
 | 
					    Douglas Leão (DeeJayLSP)
 | 
				
			||||||
 | 
					    DualMatrix
 | 
				
			||||||
 | 
					    Ellen Poe (ellenhp)
 | 
				
			||||||
 | 
					    Emilio Coppola (coppolaemilio)
 | 
				
			||||||
 | 
					    Emmanuel Barroga (codecustard)
 | 
				
			||||||
 | 
					    Emmanuel Leblond (touilleMan)
 | 
				
			||||||
 | 
					    Eoin O'Neill (Eoin-ONeill-Yokai)
 | 
				
			||||||
 | 
					    Eric Lasota (elasota)
 | 
				
			||||||
 | 
					    Eric M (EricEzaM)
 | 
				
			||||||
 | 
					    Eric Rybicki (ericrybick)
 | 
				
			||||||
 | 
					    Erik Selecký (rxlecky)
 | 
				
			||||||
 | 
					    est31
 | 
				
			||||||
 | 
					    Eveline Jarosz (Marqin)
 | 
				
			||||||
 | 
					    Fabian Mathews (supagu)
 | 
				
			||||||
 | 
					    Fabio Alessandrelli (Faless)
 | 
				
			||||||
 | 
					    Fabrice Cipolla (fabriceci)
 | 
				
			||||||
 | 
					    Ferenc Arn (tagcup)
 | 
				
			||||||
 | 
					    FireForge (fire-forge)
 | 
				
			||||||
 | 
					    Florian Kothmeier (Dragoncraft89)
 | 
				
			||||||
 | 
					    follower
 | 
				
			||||||
 | 
					    foxydevloper
 | 
				
			||||||
 | 
					    François Belair (Razoric480)
 | 
				
			||||||
 | 
					    Franklin Sobrinho (TheHX)
 | 
				
			||||||
 | 
					    Fredia Huya-Kouadio (m4gr3d)
 | 
				
			||||||
 | 
					    Geequlim
 | 
				
			||||||
 | 
					    George Marques (vnen)
 | 
				
			||||||
 | 
					    Gerrit Großkopf (Grosskopf)
 | 
				
			||||||
 | 
					    Gilles Roudiere (groud)
 | 
				
			||||||
 | 
					    Gordon MacPherson (RevoluPowered)
 | 
				
			||||||
 | 
					    Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
 | 
				
			||||||
 | 
					    Hakim Rouatbi (hakro)
 | 
				
			||||||
 | 
					    Hanif Bin Ariffin (hbina)
 | 
				
			||||||
 | 
					    Haoyu Qiu (timothyqiu)
 | 
				
			||||||
 | 
					    Hein-Pieter van Braam-Stewart (hpvb)
 | 
				
			||||||
 | 
					    Hendrik Brucker (Geometror)
 | 
				
			||||||
 | 
					    Hilderin
 | 
				
			||||||
 | 
					    hilfazer
 | 
				
			||||||
 | 
					    Hiroshi Ogawa (hi-ogawa)
 | 
				
			||||||
 | 
					    HolonProduction
 | 
				
			||||||
 | 
					    homer666
 | 
				
			||||||
 | 
					    hoontee
 | 
				
			||||||
 | 
					    Hugo Locurcio (Calinou)
 | 
				
			||||||
 | 
					    Ian Bishop (ianb96)
 | 
				
			||||||
 | 
					    Ibrahn Sahir (ibrahn)
 | 
				
			||||||
 | 
					    Ignacio Roldán Etcheverry (neikeq)
 | 
				
			||||||
 | 
					    Igor Kordiukiewicz (IgorKordiukiewicz)
 | 
				
			||||||
 | 
					    Ilaria Cislaghi (QbieShay)
 | 
				
			||||||
 | 
					    Indah Sylvia (ISylvox)
 | 
				
			||||||
 | 
					    Ivan Šachov (van800)
 | 
				
			||||||
 | 
					    J08nY
 | 
				
			||||||
 | 
					    Jake Young (Duroxxigar)
 | 
				
			||||||
 | 
					    Jakub Grzesik (kubecz3k)
 | 
				
			||||||
 | 
					    Jakub Marcowski (Chubercik)
 | 
				
			||||||
 | 
					    James Buck (jbuck3)
 | 
				
			||||||
 | 
					    Jan Haller (Bromeon)
 | 
				
			||||||
 | 
					    Jason Knight (jasonwinterpixel)
 | 
				
			||||||
 | 
					    Jean-Michel Bernard (jmb462)
 | 
				
			||||||
 | 
					    Jérôme Gully (Nutriz)
 | 
				
			||||||
 | 
					    Jia Jun Chai (SkyLucilfer)
 | 
				
			||||||
 | 
					    jitspoe
 | 
				
			||||||
 | 
					    Joan Fons Sanchez (JFonS)
 | 
				
			||||||
 | 
					    Johan Manuel (29jm)
 | 
				
			||||||
 | 
					    Johannes Witt (HaSa1002)
 | 
				
			||||||
 | 
					    Jonathan Nicholl (jtnicholl)
 | 
				
			||||||
 | 
					    Jordan Schidlowsky (winterpixelgames)
 | 
				
			||||||
 | 
					    Josh Jones (DarkKilauea)
 | 
				
			||||||
 | 
					    Joshua Grams (JoshuaGrams)
 | 
				
			||||||
 | 
					    Juan Linietsky (reduz)
 | 
				
			||||||
 | 
					    Julian Murgia (StraToN)
 | 
				
			||||||
 | 
					    Julien Nguyen (Blackiris)
 | 
				
			||||||
 | 
					    Jummit
 | 
				
			||||||
 | 
					    Justo Delgado (mrcdk)
 | 
				
			||||||
 | 
					    karroffel
 | 
				
			||||||
 | 
					    Kelly Thomas (KellyThomas)
 | 
				
			||||||
 | 
					    kleonc
 | 
				
			||||||
 | 
					    Kongfa Waroros (gongpha)
 | 
				
			||||||
 | 
					    Kostadin Damyanov (Max-Might)
 | 
				
			||||||
 | 
					    K. S. Ernest (iFire) Lee (fire)
 | 
				
			||||||
 | 
					    lawnjelly
 | 
				
			||||||
 | 
					    Leon Krause (leonkrause)
 | 
				
			||||||
 | 
					    Liz Haas (27thLiz)
 | 
				
			||||||
 | 
					    Lucien Menassol (Kanabenki)
 | 
				
			||||||
 | 
					    Lyuma
 | 
				
			||||||
 | 
					    Maganty Rushyendra (mrushyendra)
 | 
				
			||||||
 | 
					    Magian (magian1127)
 | 
				
			||||||
 | 
					    Mai Lavelle (maiself)
 | 
				
			||||||
 | 
					    Malcolm Nixon (Malcolmnixon)
 | 
				
			||||||
 | 
					    Manuele Finocchiaro (m4nu3lf)
 | 
				
			||||||
 | 
					    Marcel Admiraal (madmiraal)
 | 
				
			||||||
 | 
					    Marcelo Fernandez (marcelofg55)
 | 
				
			||||||
 | 
					    Marc Gilleron (Zylann)
 | 
				
			||||||
 | 
					    Marcin Zawiejski (dragmz)
 | 
				
			||||||
 | 
					    Marcus Brummer (mbrlabs)
 | 
				
			||||||
 | 
					    Marcus Elg (MCrafterzz)
 | 
				
			||||||
 | 
					    Mariano Javier Suligoy (MarianoGnu)
 | 
				
			||||||
 | 
					    Mario Schlack (hurikhan)
 | 
				
			||||||
 | 
					    Marios Staikopoulos (marstaik)
 | 
				
			||||||
 | 
					    Marius Hanl (Maran23)
 | 
				
			||||||
 | 
					    Mark DiBarry (markdibarry)
 | 
				
			||||||
 | 
					    Mark Riedesel (klowner)
 | 
				
			||||||
 | 
					    Markus Sauermann (Sauermann)
 | 
				
			||||||
 | 
					    Martin Capitanio (capnm)
 | 
				
			||||||
 | 
					    Martin Liška (marxin)
 | 
				
			||||||
 | 
					    Martin Sjursen (binbitten)
 | 
				
			||||||
 | 
					    marynate
 | 
				
			||||||
 | 
					    Masoud BH (masoudbh3)
 | 
				
			||||||
 | 
					    Mateo Kuruk Miccino (kuruk-mm)
 | 
				
			||||||
 | 
					    Matias N. Goldberg (darksylinc)
 | 
				
			||||||
 | 
					    Matthew (skyace65)
 | 
				
			||||||
 | 
					    Matthias Hölzl (hoelzl)
 | 
				
			||||||
 | 
					    Max Hilbrunner (mhilbrunner)
 | 
				
			||||||
 | 
					    merumelu
 | 
				
			||||||
 | 
					    Meru Patel (Janglee123)
 | 
				
			||||||
 | 
					    MewPurPur
 | 
				
			||||||
 | 
					    Michael Alexsander (YeldhamDev)
 | 
				
			||||||
 | 
					    Michał Iwańczuk (iwek7)
 | 
				
			||||||
 | 
					    MichiRecRoom (LikeLakers2)
 | 
				
			||||||
 | 
					    Micky (Mickeon)
 | 
				
			||||||
 | 
					    Mikael Hermansson (mihe)
 | 
				
			||||||
 | 
					    MinusKube
 | 
				
			||||||
 | 
					    MJacred
 | 
				
			||||||
 | 
					    Morris "Tabor" Arroad (mortarroad)
 | 
				
			||||||
 | 
					    mrezai
 | 
				
			||||||
 | 
					    Muhammad Huri (CakHuri)
 | 
				
			||||||
 | 
					    muiroc
 | 
				
			||||||
 | 
					    myaaaaaaaaa
 | 
				
			||||||
 | 
					    Nathalie Galla (MurderVeggie)
 | 
				
			||||||
 | 
					    Nathan Franke (nathanfranke)
 | 
				
			||||||
 | 
					    Nathan Lovato (NathanLovato)
 | 
				
			||||||
 | 
					    Nathan Warden (NathanWarden)
 | 
				
			||||||
 | 
					    Nicholas Huelin (SirQuartz)
 | 
				
			||||||
 | 
					    Nikita Lita (nikitalita)
 | 
				
			||||||
 | 
					    Nils André-Chang (NilsIrl)
 | 
				
			||||||
 | 
					    Noah Beard (TwistedTwigleg)
 | 
				
			||||||
 | 
					    Nông Văn Tình (nongvantinh)
 | 
				
			||||||
 | 
					    Nuno Donato (nunodonato)
 | 
				
			||||||
 | 
					    ocean (they/them) (anvilfolk)
 | 
				
			||||||
 | 
					    Omar El Sheikh (The-O-King)
 | 
				
			||||||
 | 
					    Ovnuniarchos
 | 
				
			||||||
 | 
					    Pascal Richter (ShyRed)
 | 
				
			||||||
 | 
					    passivestar
 | 
				
			||||||
 | 
					    Patrick Dawson (pkdawson)
 | 
				
			||||||
 | 
					    Patrick Exner (FlameLizard)
 | 
				
			||||||
 | 
					    Patrick (firefly2442)
 | 
				
			||||||
 | 
					    Paul Batty (Paulb23)
 | 
				
			||||||
 | 
					    Paul Joannon (paulloz)
 | 
				
			||||||
 | 
					    Paul Trojahn (ptrojahn)
 | 
				
			||||||
 | 
					    Pāvels Nadtočajevs (bruvzg)
 | 
				
			||||||
 | 
					    Paweł Fertyk (pfertyk)
 | 
				
			||||||
 | 
					    Pawel Kowal (pkowal1982)
 | 
				
			||||||
 | 
					    Pawel Lampe (Scony)
 | 
				
			||||||
 | 
					    Pedro J. Estébanez (RandomShaper)
 | 
				
			||||||
 | 
					    Pieter-Jan Briers (PJB3005)
 | 
				
			||||||
 | 
					    Poommetee Ketson (Noshyaar)
 | 
				
			||||||
 | 
					    Przemysław Gołąb (n-pigeon)
 | 
				
			||||||
 | 
					    Rafael M. G. (rafallus)
 | 
				
			||||||
 | 
					    Rafał Mikrut (qarmin)
 | 
				
			||||||
 | 
					    Raffaele Picca (RPicster)
 | 
				
			||||||
 | 
					    Ralf Hölzemer (rollenrolm)
 | 
				
			||||||
 | 
					    Ramesh Ravone (RameshRavone)
 | 
				
			||||||
 | 
					    Raphael2048
 | 
				
			||||||
 | 
					    Raul Santos (raulsntos)
 | 
				
			||||||
 | 
					    Ray Koopa (RayKoopa)
 | 
				
			||||||
 | 
					    RedMser
 | 
				
			||||||
 | 
					    RedworkDE
 | 
				
			||||||
 | 
					    Rémi Verschelde (akien-mga)
 | 
				
			||||||
 | 
					    Rhody Lugo (rraallvv)
 | 
				
			||||||
 | 
					    Ricardo Buring (rburing)
 | 
				
			||||||
 | 
					    Ricardo Subtil (Ev1lbl0w)
 | 
				
			||||||
 | 
					    Riteo Siuga (Riteo)
 | 
				
			||||||
 | 
					    Roberto F. Arroyo (robfram)
 | 
				
			||||||
 | 
					    Robert Yevdokimov (ryevdokimov)
 | 
				
			||||||
 | 
					    Robin Hübner (profan)
 | 
				
			||||||
 | 
					    romulox-x
 | 
				
			||||||
 | 
					    Rune Smith (rune-scape)
 | 
				
			||||||
 | 
					    Ruslan Mustakov (endragor)
 | 
				
			||||||
 | 
					    Ryan Roden-Corrent (rrcore)
 | 
				
			||||||
 | 
					    Saniko (sanikoyes)
 | 
				
			||||||
 | 
					    santouits
 | 
				
			||||||
 | 
					    SaracenOne
 | 
				
			||||||
 | 
					    Septian Ganendra S. K. (sepTN)
 | 
				
			||||||
 | 
					    Sergey Minakov (naithar)
 | 
				
			||||||
 | 
					    sersoong
 | 
				
			||||||
 | 
					    Shiqing (kawa-yoiko)
 | 
				
			||||||
 | 
					    Silc 'Tokage' Renew (TokageItLab)
 | 
				
			||||||
 | 
					    Simon Wenner (swenner)
 | 
				
			||||||
 | 
					    smix8
 | 
				
			||||||
 | 
					    snailrhymer
 | 
				
			||||||
 | 
					    Sofox (TheSofox)
 | 
				
			||||||
 | 
					    Stanislav Labzyuk (DarkMessiah)
 | 
				
			||||||
 | 
					    Stijn Hinlopen (hinlopen)
 | 
				
			||||||
 | 
					    stmSi
 | 
				
			||||||
 | 
					    Swarnim Arun (minraws)
 | 
				
			||||||
 | 
					    TC (floppyhammer)
 | 
				
			||||||
 | 
					    TechnoPorg
 | 
				
			||||||
 | 
					    Thaddeus Crews (Repiteo)
 | 
				
			||||||
 | 
					    Thakee Nathees (ThakeeNathees)
 | 
				
			||||||
 | 
					    thebestnom
 | 
				
			||||||
 | 
					    Theo Hallenius (TheoXD)
 | 
				
			||||||
 | 
					    Timo Schwarzer (timoschwarzer)
 | 
				
			||||||
 | 
					    Timothé Bonhoure (ajreckof)
 | 
				
			||||||
 | 
					    Timo (toger5)
 | 
				
			||||||
 | 
					    Tomasz Chabora (KoBeWi)
 | 
				
			||||||
 | 
					    trollodel
 | 
				
			||||||
 | 
					    Twarit Waikar (IronicallySerious)
 | 
				
			||||||
 | 
					    Umang Kalra (theoway)
 | 
				
			||||||
 | 
					    Vinzenz Feenstra (vinzenz)
 | 
				
			||||||
 | 
					    Vitika Soni (Vitika9)
 | 
				
			||||||
 | 
					    박한얼 (volzhs)
 | 
				
			||||||
 | 
					    V. Vamsi Krishna (vkbsb)
 | 
				
			||||||
 | 
					    Wilhem Barbier (nounoursheureux)
 | 
				
			||||||
 | 
					    William Deurwaarder (williamd67)
 | 
				
			||||||
 | 
					    Will Nations (willnationsdev)
 | 
				
			||||||
 | 
					    Wilson E. Alvarez (Rubonnek)
 | 
				
			||||||
 | 
					    Xavier Cho (mysticfall)
 | 
				
			||||||
 | 
					    Yaohua Xiong (xiongyaohua)
 | 
				
			||||||
 | 
					    yg2f (SuperUserNameMan)
 | 
				
			||||||
 | 
					    Yordan Dolchinkov (Jordyfel)
 | 
				
			||||||
 | 
					    Yuri Rubinsky (Chaosus)
 | 
				
			||||||
 | 
					    Yuri Sizov (YuriSizov)
 | 
				
			||||||
 | 
					    Zae Chao (zaevi)
 | 
				
			||||||
 | 
					    Zak Stam (zaksnet)
 | 
				
			||||||
 | 
					    Zher Huei Lee (leezh)
 | 
				
			||||||
 | 
					    Zi Ye (MajorMcDoom)
 | 
				
			||||||
 | 
					    ZuBsPaCe
 | 
				
			||||||
 | 
					    Дмитрий Сальников (DmitriySalnikov)
 | 
				
			||||||
 | 
					    忘忧の (Daylily-Zeleen)
 | 
				
			||||||
 | 
					    谢天 (jsjtxietian)
 | 
				
			||||||
 | 
					    风青山 (Rindbee)
 | 
				
			||||||
							
								
								
									
										3525
									
								
								engine/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3525
									
								
								engine/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										213
									
								
								engine/CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								engine/CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,213 @@
 | 
				
			||||||
 | 
					# Contributors guidelines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This document summarizes the most important points for people interested in
 | 
				
			||||||
 | 
					contributing to Godot, especially via bug reports or pull requests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The Godot documentation has a dedicated [Contributing section](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
 | 
				
			||||||
 | 
					which details these points and more, and is a recommended read.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Table of contents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Reporting bugs](#reporting-bugs)
 | 
				
			||||||
 | 
					- [Proposing features or improvements](#proposing-features-or-improvements)
 | 
				
			||||||
 | 
					- [Contributing pull requests](#contributing-pull-requests)
 | 
				
			||||||
 | 
					- [Contributing to Godot translations](#contributing-to-godot-translations)
 | 
				
			||||||
 | 
					- [Communicating with developers](#communicating-with-developers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Reporting bugs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Report bugs [here](https://github.com/godotengine/godot/issues/new?assignees=&labels=&template=bug_report.yml).
 | 
				
			||||||
 | 
					Please follow the instructions in the template when you do.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Notably, please include a Minimal Reproduction Project (MRP), which is a small
 | 
				
			||||||
 | 
					Godot project which reproduces the issue, with no unnecessary files included.
 | 
				
			||||||
 | 
					Be sure to not include the `.godot` folder in the archive to save space.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Make sure that the bug you are experiencing is reproducible in the latest Godot
 | 
				
			||||||
 | 
					releases. You can find an overview of all Godot releases [on the website](https://godotengine.org/download/archive/)
 | 
				
			||||||
 | 
					to confirm whether your current version is the latest one. It's worth testing
 | 
				
			||||||
 | 
					against both the latest stable release and the latest dev snapshot for the next
 | 
				
			||||||
 | 
					Godot release.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you run into a bug which wasn't present in an earlier Godot version (what we
 | 
				
			||||||
 | 
					call a _regression_), please mention it and clarify which versions you tested
 | 
				
			||||||
 | 
					(both the one(s) working and the one(s) exhibiting the bug).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Proposing features or improvements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**The main issue tracker is for bug reports and does not accept feature proposals.**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Instead, head to the [Godot Proposals repository](https://github.com/godotengine/godot-proposals)
 | 
				
			||||||
 | 
					and follow the instructions in the README file and issue template.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributing pull requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to add new engine features, please make sure that:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- This functionality is desired, which means that it solves a common use case
 | 
				
			||||||
 | 
					  that several users will need in their real-life projects.
 | 
				
			||||||
 | 
					- You talked to other developers on how to implement it best. See also
 | 
				
			||||||
 | 
					  [Proposing features or improvements](#proposing-features-or-improvements).
 | 
				
			||||||
 | 
					- Even if it doesn't get merged, your PR is useful for future work by another
 | 
				
			||||||
 | 
					  developer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Similar rules can be applied when contributing bug fixes - it's always best to
 | 
				
			||||||
 | 
					discuss the implementation in the bug report first if you are not 100% about
 | 
				
			||||||
 | 
					what would be the best fix.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can refer to the [Pull request review process](https://docs.godotengine.org/en/latest/contributing/workflow/pr_review_guidelines.html)
 | 
				
			||||||
 | 
					for insights into the intended lifecycle of pull requests. This should help you
 | 
				
			||||||
 | 
					ensure that your pull request fulfills the requirements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition to the following tips, also take a look at the
 | 
				
			||||||
 | 
					[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html)
 | 
				
			||||||
 | 
					for an introduction to developing on Godot.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
 | 
				
			||||||
 | 
					also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
 | 
				
			||||||
 | 
					(with a helpful guide for Git usage), and our [Code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html)
 | 
				
			||||||
 | 
					which all contributions need to follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Be mindful of your commits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Try to make simple PRs that handle one specific topic. Just like for reporting
 | 
				
			||||||
 | 
					issues, it's better to open 3 different PRs that each address a different issue
 | 
				
			||||||
 | 
					than one big PR with three commits. This makes it easier to review, approve, and
 | 
				
			||||||
 | 
					merge the changes independently.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When updating your fork with upstream changes, please use ``git pull --rebase``
 | 
				
			||||||
 | 
					to avoid creating "merge commits". Those commits unnecessarily pollute the git
 | 
				
			||||||
 | 
					history when coming from PRs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also try to make commits that bring the engine from one stable state to another
 | 
				
			||||||
 | 
					stable state, i.e. if your first commit has a bug that you fixed in the second
 | 
				
			||||||
 | 
					commit, try to merge them together before making your pull request. This
 | 
				
			||||||
 | 
					includes fixing build issues or typos, adding documentation, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
 | 
				
			||||||
 | 
					documentation for tips on using Git, amending commits and rebasing branches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This [Git style guide](https://github.com/agis-/git-style-guide) also has some
 | 
				
			||||||
 | 
					good practices to have in mind.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Format your commit messages with readability in mind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The way you format your commit messages is quite important to ensure that the
 | 
				
			||||||
 | 
					commit history and changelog will be easy to read and understand. A Git commit
 | 
				
			||||||
 | 
					message is formatted as a short title (first line) and an extended description
 | 
				
			||||||
 | 
					(everything after the first line and an empty separation line).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The short title is the most important part, as it is what will appear in the
 | 
				
			||||||
 | 
					changelog or in the GitHub interface unless you click the "expand" button.
 | 
				
			||||||
 | 
					Try to keep that first line under 72 characters, but you can go slightly above
 | 
				
			||||||
 | 
					if necessary to keep the sentence clear.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It should be written in English, starting with a capital letter, and usually
 | 
				
			||||||
 | 
					with a verb in imperative form. A typical bugfix would start with "Fix", while
 | 
				
			||||||
 | 
					the addition of a new feature would start with "Add". A prefix can be added to
 | 
				
			||||||
 | 
					specify the engine area affected by the commit. Some examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add C# iOS support
 | 
				
			||||||
 | 
					- Show doc tooltips when hovering properties in the theme editor
 | 
				
			||||||
 | 
					- Fix GLES3 instanced rendering color and custom data defaults
 | 
				
			||||||
 | 
					- Core: Fix `Object::has_method()` for script static methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If your commit fixes a reported issue, please include it in the _description_
 | 
				
			||||||
 | 
					of the PR (not in the title, or the commit message) using one of the
 | 
				
			||||||
 | 
					[GitHub closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
 | 
				
			||||||
 | 
					such as "Fixes #1234". This will cause the issue to be closed automatically if
 | 
				
			||||||
 | 
					the PR is merged. Adding it to the commit message is easier, but adds a lot of
 | 
				
			||||||
 | 
					unnecessary updates in the issue distracting from the thread.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here's an example of a well-formatted commit message (note how the extended
 | 
				
			||||||
 | 
					description is also manually wrapped at 80 chars for readability):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
 | 
					Prevent French fries carbonization by fixing heat regulation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When using the French fries frying module, Godot would not regulate the heat
 | 
				
			||||||
 | 
					and thus bring the oil bath to supercritical liquid conditions, thus causing
 | 
				
			||||||
 | 
					unwanted side effects in the physics engine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By fixing the regulation system via an added binding to the internal feature,
 | 
				
			||||||
 | 
					this commit now ensures that Godot will not go past the ebullition temperature
 | 
				
			||||||
 | 
					of cooking oil under normal atmospheric conditions.
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Note:** When using the GitHub online editor or its drag-and-drop
 | 
				
			||||||
 | 
					feature, *please* edit the commit title to something meaningful. Commits named
 | 
				
			||||||
 | 
					"Update my_file.cpp" won't be accepted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Document your changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If your pull request adds methods, properties or signals that are exposed to
 | 
				
			||||||
 | 
					scripting APIs, you **must** update the class reference to document those.
 | 
				
			||||||
 | 
					This is to ensure the documentation coverage doesn't decrease as contributions
 | 
				
			||||||
 | 
					are merged.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html)
 | 
				
			||||||
 | 
					using your compiled binary, then fill in the descriptions.
 | 
				
			||||||
 | 
					Follow the style guide described in the
 | 
				
			||||||
 | 
					[Documentation writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If your pull request modifies parts of the code in a non-obvious way, make sure
 | 
				
			||||||
 | 
					to add comments in the code as well. This helps other people understand the
 | 
				
			||||||
 | 
					change without having to dive into the Git history.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Write unit tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When fixing a bug or contributing a new feature, we recommend including unit
 | 
				
			||||||
 | 
					tests in the same commit as the rest of the pull request. Unit tests are pieces
 | 
				
			||||||
 | 
					of code that compare the output to a predetermined *expected result* to detect
 | 
				
			||||||
 | 
					regressions. Tests are compiled and run on GitHub Actions for every commit and
 | 
				
			||||||
 | 
					pull request.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pull requests that include tests are more likely to be merged, since we can have
 | 
				
			||||||
 | 
					greater confidence in them not being the target of regressions in the future.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For bugs, the unit tests should cover the functionality that was previously
 | 
				
			||||||
 | 
					broken. If done well, this ensures regressions won't appear in the future
 | 
				
			||||||
 | 
					again. For new features, the unit tests should cover the newly added
 | 
				
			||||||
 | 
					functionality, testing both the "success" and "expected failure" cases if
 | 
				
			||||||
 | 
					applicable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Feel free to contribute standalone pull requests to add new tests or improve
 | 
				
			||||||
 | 
					existing tests as well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html)
 | 
				
			||||||
 | 
					for information on writing tests in Godot's C++ codebase.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributing to Godot translations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can contribute to Godot translations on [Hosted Weblate](https://hosted.weblate.org/projects/godot-engine/),
 | 
				
			||||||
 | 
					an open source and web-based translation platform.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please refer to our [editor and documentation localization guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/editor_and_docs_localization.html)
 | 
				
			||||||
 | 
					for an overview of the translation resources and what they correspond to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Communicating with developers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The Godot Engine community has [many communication
 | 
				
			||||||
 | 
					channels](https://godotengine.org/community), some used more for user-level
 | 
				
			||||||
 | 
					discussions and support, others more for development discussions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To communicate with developers (e.g. to discuss a feature you want to implement
 | 
				
			||||||
 | 
					or a bug you want to fix), the following channels can be used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Godot Contributors Chat](https://chat.godotengine.org): You will
 | 
				
			||||||
 | 
					  find most core developers there, so it's the go-to platform for direct chat
 | 
				
			||||||
 | 
					  about Godot Engine development. Browse the [Directory](https://chat.godotengine.org/directory/channels)
 | 
				
			||||||
 | 
					  for an overview of public channels focusing on various engine areas which you
 | 
				
			||||||
 | 
					  might be interested in.
 | 
				
			||||||
 | 
					- [Bug tracker](https://github.com/godotengine/godot/issues): If there is an
 | 
				
			||||||
 | 
					  existing issue about a topic you want to discuss, you can participate directly.
 | 
				
			||||||
 | 
					  If not, you can open a new issue. Please mind the guidelines outlined above
 | 
				
			||||||
 | 
					  for bug reporting.
 | 
				
			||||||
 | 
					- [Feature proposals](https://github.com/godotengine/godot-proposals/issues):
 | 
				
			||||||
 | 
					  To propose a new feature, we have a dedicated issue tracker for that. Don't
 | 
				
			||||||
 | 
					  hesitate to start by talking about your idea on the Godot Contributors Chat
 | 
				
			||||||
 | 
					  to make sure that it makes sense in Godot's context.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thanks for your interest in contributing!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					—The Godot development team
 | 
				
			||||||
							
								
								
									
										1984
									
								
								engine/COPYRIGHT.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1984
									
								
								engine/COPYRIGHT.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										516
									
								
								engine/DONORS.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										516
									
								
								engine/DONORS.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,516 @@
 | 
				
			||||||
 | 
					# Donors to the Godot Engine project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Godot Engine is a non-profit project developed by a community of voluntary
 | 
				
			||||||
 | 
					contributors, as well as occasional paid contributors thanks to the financial
 | 
				
			||||||
 | 
					support of generous donors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The ways to donate to the project, as well as details on how the funds are
 | 
				
			||||||
 | 
					used, are described on [Godot's website](https://godotengine.org/donate).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following is a list of the current monthly donors, who will have their
 | 
				
			||||||
 | 
					generous deed immortalized in the next stable release of Godot Engine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Patrons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OSS Capital <https://oss.capital/>
 | 
				
			||||||
 | 
					    Re-Logic <https://re-logic.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Platinum sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Google Play <https://play.google.com/>
 | 
				
			||||||
 | 
					    Ramatak <https://ramatak.com/>
 | 
				
			||||||
 | 
					    V-Sekai <https://github.com/V-Sekai>
 | 
				
			||||||
 | 
					    W4 Games <https://w4games.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Gold sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Mega Crit <https://www.megacrit.com/>
 | 
				
			||||||
 | 
					    Pirate Software <https://gopiratesoftware.com/>
 | 
				
			||||||
 | 
					    Prehensile Tales <https://prehensile-tales.com/>
 | 
				
			||||||
 | 
					    Robot Gentleman <http://robotgentleman.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Silver sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Broken Rules <https://brokenrul.es/>
 | 
				
			||||||
 | 
					    Chasing Carrots <https://www.chasing-carrots.com/>
 | 
				
			||||||
 | 
					    Copia Wealth Studios <https://copiawealthstudios.com/>
 | 
				
			||||||
 | 
					    Indoor Astronaut <https://indoorastronaut.ch/>
 | 
				
			||||||
 | 
					    Load Complete <https://loadcomplete.com/>
 | 
				
			||||||
 | 
					    Null <https://null.com/>
 | 
				
			||||||
 | 
					    Orbital Knight <https://www.orbitalknight.com/>
 | 
				
			||||||
 | 
					    Playful Studios <https://playfulstudios.com/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Diamond members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Bippinbits <http://domekeepergame.com/>
 | 
				
			||||||
 | 
					    Sealow
 | 
				
			||||||
 | 
					    And 5 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Titanium members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Adriaan de Jongh <https://adriaan.games/>
 | 
				
			||||||
 | 
					    Anitya Space <https://www.anitya.space/>
 | 
				
			||||||
 | 
					    Basically Games
 | 
				
			||||||
 | 
					    FDG Entertainment <https://www.fdg-entertainment.com/>
 | 
				
			||||||
 | 
					    Game Dev Artisan <https://gamedevartisan.com/>
 | 
				
			||||||
 | 
					    Garry Newman
 | 
				
			||||||
 | 
					    Isaiah Smith <https://www.isaiahsmith.dev/>
 | 
				
			||||||
 | 
					    Libretrend <https://libretrend.com/>
 | 
				
			||||||
 | 
					    Life Art Studios <https://lifeartstudios.net/>
 | 
				
			||||||
 | 
					    Lucid Silence Games
 | 
				
			||||||
 | 
					    Matthew Campbell
 | 
				
			||||||
 | 
					    PolyMars <https://polymars.dev/>
 | 
				
			||||||
 | 
					    RPG in a Box <https://www.rpginabox.com/>
 | 
				
			||||||
 | 
					    Razenpok <https://www.youtube.com/watch?v=-QxI-RP6-HM>
 | 
				
			||||||
 | 
					    Smirk Software <https://smirk.gg/>
 | 
				
			||||||
 | 
					    粟二华 (Su Erhua)
 | 
				
			||||||
 | 
					    And 6 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Platinum members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Andy Touch
 | 
				
			||||||
 | 
					    BlockImperiumGames (BIG)
 | 
				
			||||||
 | 
					    Christoph Woinke
 | 
				
			||||||
 | 
					    Christopher Shifflett
 | 
				
			||||||
 | 
					    Cody Bentley
 | 
				
			||||||
 | 
					    Darrin Massena
 | 
				
			||||||
 | 
					    Edward Flick
 | 
				
			||||||
 | 
					    GetIntoGameDev
 | 
				
			||||||
 | 
					    HP van Braam
 | 
				
			||||||
 | 
					    iCommitGames
 | 
				
			||||||
 | 
					    Jonah Stich
 | 
				
			||||||
 | 
					    katnamag
 | 
				
			||||||
 | 
					    Marek Belski
 | 
				
			||||||
 | 
					    Matthew Ekenstedt
 | 
				
			||||||
 | 
					    Memories in 8Bit
 | 
				
			||||||
 | 
					    Mike King
 | 
				
			||||||
 | 
					    Neal Gompa (Conan Kudo)
 | 
				
			||||||
 | 
					    Radivarig
 | 
				
			||||||
 | 
					    Ronnie Cheng
 | 
				
			||||||
 | 
					    Ryan Heath
 | 
				
			||||||
 | 
					    Scott Pezza
 | 
				
			||||||
 | 
					    ShikadiGum
 | 
				
			||||||
 | 
					    Silver Creek Entertainment
 | 
				
			||||||
 | 
					    SolarLabyrinth
 | 
				
			||||||
 | 
					    Stephan Kessler
 | 
				
			||||||
 | 
					    Stephan Lanfermann
 | 
				
			||||||
 | 
					    TigerJ
 | 
				
			||||||
 | 
					    Violin Iliev
 | 
				
			||||||
 | 
					    Vladimír Chvátil
 | 
				
			||||||
 | 
					    And 16 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Gold members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    80px
 | 
				
			||||||
 | 
					    afreytes
 | 
				
			||||||
 | 
					    alMoo Games
 | 
				
			||||||
 | 
					    Alva Majo
 | 
				
			||||||
 | 
					    Antti Vesanen
 | 
				
			||||||
 | 
					    Asher Glick
 | 
				
			||||||
 | 
					    Axthelm
 | 
				
			||||||
 | 
					    Bellbird Studio
 | 
				
			||||||
 | 
					    Benito
 | 
				
			||||||
 | 
					    Benjamin Sarsgard
 | 
				
			||||||
 | 
					    Ben Rog-Wilhelm
 | 
				
			||||||
 | 
					    Bernd Barsuhn
 | 
				
			||||||
 | 
					    BetaTester704
 | 
				
			||||||
 | 
					    Brian Levinsen
 | 
				
			||||||
 | 
					    Brut
 | 
				
			||||||
 | 
					    Bryce Dixon
 | 
				
			||||||
 | 
					    c64cosmin
 | 
				
			||||||
 | 
					    Carlo del Mundo
 | 
				
			||||||
 | 
					    Cindy Trieu
 | 
				
			||||||
 | 
					    ClarkThyLord
 | 
				
			||||||
 | 
					    Codex404
 | 
				
			||||||
 | 
					    cora
 | 
				
			||||||
 | 
					    Daniel Eichler
 | 
				
			||||||
 | 
					    Daniel Krafft
 | 
				
			||||||
 | 
					    David Chen Zhen
 | 
				
			||||||
 | 
					    David Coles
 | 
				
			||||||
 | 
					    David Hubber
 | 
				
			||||||
 | 
					    David Snopek
 | 
				
			||||||
 | 
					    Deakcor
 | 
				
			||||||
 | 
					    Delton Ding
 | 
				
			||||||
 | 
					    dfseifert
 | 
				
			||||||
 | 
					    dgehrig
 | 
				
			||||||
 | 
					    dhanielk
 | 
				
			||||||
 | 
					    Distorted Realities
 | 
				
			||||||
 | 
					    Dono
 | 
				
			||||||
 | 
					    Don't You Know Who I Am? Inc.
 | 
				
			||||||
 | 
					    Dustuu
 | 
				
			||||||
 | 
					    Edelweiss
 | 
				
			||||||
 | 
					    Ends
 | 
				
			||||||
 | 
					    Eren Ogrul
 | 
				
			||||||
 | 
					    Eric Brand
 | 
				
			||||||
 | 
					    Eric Phy
 | 
				
			||||||
 | 
					    Faisal Al-Kubaisi (QatariGameDev)
 | 
				
			||||||
 | 
					    FeralBytes
 | 
				
			||||||
 | 
					    Festzeltgaming.de
 | 
				
			||||||
 | 
					    Gaudipern
 | 
				
			||||||
 | 
					    GlassBrick
 | 
				
			||||||
 | 
					    Grau
 | 
				
			||||||
 | 
					    Guangzhou Lingchan
 | 
				
			||||||
 | 
					    Hayden Oliver
 | 
				
			||||||
 | 
					    hiulit
 | 
				
			||||||
 | 
					    Illyan
 | 
				
			||||||
 | 
					    Ivan Tabashki
 | 
				
			||||||
 | 
					    Jacob (HACKhalo2 Studios)
 | 
				
			||||||
 | 
					    Jam
 | 
				
			||||||
 | 
					    Jason Cawood
 | 
				
			||||||
 | 
					    Javier Roman
 | 
				
			||||||
 | 
					    Jeff Hungerford
 | 
				
			||||||
 | 
					    Jeronimo Schreyer
 | 
				
			||||||
 | 
					    Joel Martinez
 | 
				
			||||||
 | 
					    Johannes Wuensch
 | 
				
			||||||
 | 
					    John Gabriel
 | 
				
			||||||
 | 
					    Jonas Yamazaki
 | 
				
			||||||
 | 
					    José Canepa
 | 
				
			||||||
 | 
					    Joshua Stelly
 | 
				
			||||||
 | 
					    Justin Sasso
 | 
				
			||||||
 | 
					    Kalydi Balázs
 | 
				
			||||||
 | 
					    KAR Games
 | 
				
			||||||
 | 
					    Kiri "ExpiredPopsicle" Artemis
 | 
				
			||||||
 | 
					    KOGA Mitsuhiro (@shiena)
 | 
				
			||||||
 | 
					    korinVR
 | 
				
			||||||
 | 
					    Kristian Kriehl
 | 
				
			||||||
 | 
					    Lars Thießen
 | 
				
			||||||
 | 
					    Lisandro Lorea (Red Mage Games)
 | 
				
			||||||
 | 
					    Logan Apple
 | 
				
			||||||
 | 
					    Luca Junge
 | 
				
			||||||
 | 
					    LyaaaaaGames
 | 
				
			||||||
 | 
					    m1n1ster
 | 
				
			||||||
 | 
					    Manuel Requena
 | 
				
			||||||
 | 
					    Mara Huldra
 | 
				
			||||||
 | 
					    Martin Šenkeřík
 | 
				
			||||||
 | 
					    Michael Gooch
 | 
				
			||||||
 | 
					    Modus Ponens
 | 
				
			||||||
 | 
					    Moshe Harris
 | 
				
			||||||
 | 
					    Moth
 | 
				
			||||||
 | 
					    Mr. Byte
 | 
				
			||||||
 | 
					    Nassor Paulino da Silva
 | 
				
			||||||
 | 
					    nezticle
 | 
				
			||||||
 | 
					    Niklas Wahrman
 | 
				
			||||||
 | 
					    Niwl Games
 | 
				
			||||||
 | 
					    NotNet
 | 
				
			||||||
 | 
					    Oathbringer
 | 
				
			||||||
 | 
					    Officine Pixel
 | 
				
			||||||
 | 
					    ohanaya3
 | 
				
			||||||
 | 
					    Okatima AB
 | 
				
			||||||
 | 
					    Oleksii Nosov
 | 
				
			||||||
 | 
					    Osirisa
 | 
				
			||||||
 | 
					    Patrick Traynor
 | 
				
			||||||
 | 
					    Petr Malac
 | 
				
			||||||
 | 
					    pirey
 | 
				
			||||||
 | 
					    Rafa Laguna
 | 
				
			||||||
 | 
					    @reilaos
 | 
				
			||||||
 | 
					    Request
 | 
				
			||||||
 | 
					    re:thinc
 | 
				
			||||||
 | 
					    Richard Ivánek
 | 
				
			||||||
 | 
					    Rudi P
 | 
				
			||||||
 | 
					    Samuel Judd
 | 
				
			||||||
 | 
					    ScoreSpace
 | 
				
			||||||
 | 
					    Shiny Shinken
 | 
				
			||||||
 | 
					    Silverclad Studios
 | 
				
			||||||
 | 
					    Sofox
 | 
				
			||||||
 | 
					    Space Kraken Studios
 | 
				
			||||||
 | 
					    spacesloth
 | 
				
			||||||
 | 
					    Spoony Panda
 | 
				
			||||||
 | 
					    TANAKA Yu
 | 
				
			||||||
 | 
					    TaraSophieDev (pls fix #43093)
 | 
				
			||||||
 | 
					    Thad Guidry
 | 
				
			||||||
 | 
					    ThatGamer
 | 
				
			||||||
 | 
					    The Polyglot Programmer
 | 
				
			||||||
 | 
					    TheRiverNyx
 | 
				
			||||||
 | 
					    Thomas Lobig
 | 
				
			||||||
 | 
					    Tim Nedvyga
 | 
				
			||||||
 | 
					    Tom Langwaldt
 | 
				
			||||||
 | 
					    Trevor Slocum
 | 
				
			||||||
 | 
					    tukon
 | 
				
			||||||
 | 
					    Tyler C
 | 
				
			||||||
 | 
					    Vagastella
 | 
				
			||||||
 | 
					    Vincent Foulon
 | 
				
			||||||
 | 
					    Vojtech Lacina
 | 
				
			||||||
 | 
					    Watchinofoye
 | 
				
			||||||
 | 
					    Weasel Games
 | 
				
			||||||
 | 
					    Wilson Birney
 | 
				
			||||||
 | 
					    Wolfram
 | 
				
			||||||
 | 
					    WuotanStudios.com
 | 
				
			||||||
 | 
					    Zhu Li
 | 
				
			||||||
 | 
					    zikes
 | 
				
			||||||
 | 
					    嗯大爷
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Alex Khayrullin
 | 
				
			||||||
 | 
					    Algebrute
 | 
				
			||||||
 | 
					    Andriy
 | 
				
			||||||
 | 
					    Antanas Paskauskas
 | 
				
			||||||
 | 
					    anti666
 | 
				
			||||||
 | 
					    Ari
 | 
				
			||||||
 | 
					    Arisaka Mayuki
 | 
				
			||||||
 | 
					    Arthur S. Muszynski
 | 
				
			||||||
 | 
					    Cameron Connolly
 | 
				
			||||||
 | 
					    Charlie Whitfield
 | 
				
			||||||
 | 
					    Craig Ostrin
 | 
				
			||||||
 | 
					    Craig Swain
 | 
				
			||||||
 | 
					    CzechBlueBear
 | 
				
			||||||
 | 
					    Dennis Belfrage
 | 
				
			||||||
 | 
					    Emily A. Bellows
 | 
				
			||||||
 | 
					    Felix Winterhalter
 | 
				
			||||||
 | 
					    Fransiska
 | 
				
			||||||
 | 
					    Harry Tumber
 | 
				
			||||||
 | 
					    James Couzens
 | 
				
			||||||
 | 
					    Jared White
 | 
				
			||||||
 | 
					    Jesús Chicharro
 | 
				
			||||||
 | 
					    Joel Fivat
 | 
				
			||||||
 | 
					    Johnathan Kupferer
 | 
				
			||||||
 | 
					    Josef Stumpfegger
 | 
				
			||||||
 | 
					    Joshua Lesperance
 | 
				
			||||||
 | 
					    Kelteseth
 | 
				
			||||||
 | 
					    kickmaniac
 | 
				
			||||||
 | 
					    Liam Smyth
 | 
				
			||||||
 | 
					    LoparPanda
 | 
				
			||||||
 | 
					    Martin Gulliksson
 | 
				
			||||||
 | 
					    Martin Soucek
 | 
				
			||||||
 | 
					    Michael Dürwald
 | 
				
			||||||
 | 
					    Michael Policastro
 | 
				
			||||||
 | 
					    n00sh
 | 
				
			||||||
 | 
					    Nicolás Monner Sans
 | 
				
			||||||
 | 
					    Nikita Rotskov
 | 
				
			||||||
 | 
					    Nikola Whallon
 | 
				
			||||||
 | 
					    Oliver Dick
 | 
				
			||||||
 | 
					    Patrick Wuttke
 | 
				
			||||||
 | 
					    Pete Goodwin
 | 
				
			||||||
 | 
					    Philip Woods
 | 
				
			||||||
 | 
					    Reilt
 | 
				
			||||||
 | 
					    Rickard Hermanson
 | 
				
			||||||
 | 
					    Rob
 | 
				
			||||||
 | 
					    Rob McInroy
 | 
				
			||||||
 | 
					    RodZilla
 | 
				
			||||||
 | 
					    Ruzgud
 | 
				
			||||||
 | 
					    Ryan Breaker
 | 
				
			||||||
 | 
					    "Sage Automatic Systems, LLC"
 | 
				
			||||||
 | 
					    spacechase0
 | 
				
			||||||
 | 
					    sus
 | 
				
			||||||
 | 
					    Thomas Kurz
 | 
				
			||||||
 | 
					    Tobias Bocanegra
 | 
				
			||||||
 | 
					    Torbulous
 | 
				
			||||||
 | 
					    toto bibi
 | 
				
			||||||
 | 
					    Valryia
 | 
				
			||||||
 | 
					    VoidPointer
 | 
				
			||||||
 | 
					    Yifan Lai
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Aaron Mayfield
 | 
				
			||||||
 | 
					    Adam Carr
 | 
				
			||||||
 | 
					    Adam Smeltzer
 | 
				
			||||||
 | 
					    Adisibio
 | 
				
			||||||
 | 
					    Aidan Marwick
 | 
				
			||||||
 | 
					    Aidan O'Flannagain
 | 
				
			||||||
 | 
					    AJWolbers
 | 
				
			||||||
 | 
					    Alan Beauchamp
 | 
				
			||||||
 | 
					    Alexander Erlemann
 | 
				
			||||||
 | 
					    Alex Clavelle
 | 
				
			||||||
 | 
					    alex raeside
 | 
				
			||||||
 | 
					    Andre Altmueller
 | 
				
			||||||
 | 
					    Andreas Østergaard Nielsen
 | 
				
			||||||
 | 
					    Andrew
 | 
				
			||||||
 | 
					    Ano Nim
 | 
				
			||||||
 | 
					    Arch Toasty
 | 
				
			||||||
 | 
					    Arda Erol
 | 
				
			||||||
 | 
					    A Really Tall Horse
 | 
				
			||||||
 | 
					    Arturo Rosales
 | 
				
			||||||
 | 
					    Ash K
 | 
				
			||||||
 | 
					    Aubrey Falconer
 | 
				
			||||||
 | 
					    Austin Miller
 | 
				
			||||||
 | 
					    AzulCrescent
 | 
				
			||||||
 | 
					    Beau Seymour
 | 
				
			||||||
 | 
					    Benedikt
 | 
				
			||||||
 | 
					    Bread
 | 
				
			||||||
 | 
					    Brian Ford
 | 
				
			||||||
 | 
					    Caleb Makela
 | 
				
			||||||
 | 
					    Cameron Meyer
 | 
				
			||||||
 | 
					    Carl van der Geest
 | 
				
			||||||
 | 
					    Checkpoint Charlie
 | 
				
			||||||
 | 
					    Chris Cavalluzzi
 | 
				
			||||||
 | 
					    Chris Jagusch
 | 
				
			||||||
 | 
					    Chris Lee
 | 
				
			||||||
 | 
					    Christian Mauduit
 | 
				
			||||||
 | 
					    Christian Ringshofer
 | 
				
			||||||
 | 
					    Christoph Czurda
 | 
				
			||||||
 | 
					    Christophe Gagnier
 | 
				
			||||||
 | 
					    Cody Parker
 | 
				
			||||||
 | 
					    Conall O
 | 
				
			||||||
 | 
					    Corchari
 | 
				
			||||||
 | 
					    Corey W
 | 
				
			||||||
 | 
					    Dakota Watkins
 | 
				
			||||||
 | 
					    Daniele Tolomelli
 | 
				
			||||||
 | 
					    Daniel Ramos
 | 
				
			||||||
 | 
					    Dave Jansen
 | 
				
			||||||
 | 
					    Davesnothere
 | 
				
			||||||
 | 
					    David Baker
 | 
				
			||||||
 | 
					    David Bôle
 | 
				
			||||||
 | 
					    David May
 | 
				
			||||||
 | 
					    David Maziarka
 | 
				
			||||||
 | 
					    Devin Carraway
 | 
				
			||||||
 | 
					    Devin R
 | 
				
			||||||
 | 
					    Dimitri Roche
 | 
				
			||||||
 | 
					    Donovan Hutcheon
 | 
				
			||||||
 | 
					    Ducky
 | 
				
			||||||
 | 
					    Duodecimal
 | 
				
			||||||
 | 
					    Egon Elbre
 | 
				
			||||||
 | 
					    Elijah Anderson
 | 
				
			||||||
 | 
					    Eric Persson
 | 
				
			||||||
 | 
					    Eric Stokes
 | 
				
			||||||
 | 
					    Eric Williams
 | 
				
			||||||
 | 
					    Erkki Seppälä
 | 
				
			||||||
 | 
					    Ewan Holmes
 | 
				
			||||||
 | 
					    Felix Adam
 | 
				
			||||||
 | 
					    Frank
 | 
				
			||||||
 | 
					    Frying☆Pan
 | 
				
			||||||
 | 
					    Game Endeavor
 | 
				
			||||||
 | 
					    gamerminstrel
 | 
				
			||||||
 | 
					    Gary Thomas
 | 
				
			||||||
 | 
					    gebba
 | 
				
			||||||
 | 
					    Greyson Richey
 | 
				
			||||||
 | 
					    Guo Hongci
 | 
				
			||||||
 | 
					    Haplo
 | 
				
			||||||
 | 
					    Helge Maus
 | 
				
			||||||
 | 
					    Heribert Hirth
 | 
				
			||||||
 | 
					    Ian Richard Kunert
 | 
				
			||||||
 | 
					    Ian Williams
 | 
				
			||||||
 | 
					    itsybitesyspider
 | 
				
			||||||
 | 
					    iveks
 | 
				
			||||||
 | 
					    Jacob Wallace
 | 
				
			||||||
 | 
					    Jako Danar
 | 
				
			||||||
 | 
					    James Gary
 | 
				
			||||||
 | 
					    James Hulsizer
 | 
				
			||||||
 | 
					    Jamie Massey
 | 
				
			||||||
 | 
					    JARKKO PARVIAINEN
 | 
				
			||||||
 | 
					    Jason Evans
 | 
				
			||||||
 | 
					    Joakim Askenbäck
 | 
				
			||||||
 | 
					    Jonas
 | 
				
			||||||
 | 
					    Jonas Arndt
 | 
				
			||||||
 | 
					    Jonas Yamazaki
 | 
				
			||||||
 | 
					    Jonathan Bieber
 | 
				
			||||||
 | 
					    Jon Sully
 | 
				
			||||||
 | 
					    Joseph Catrambone
 | 
				
			||||||
 | 
					    Josh Taylor
 | 
				
			||||||
 | 
					    Juanfran
 | 
				
			||||||
 | 
					    Julian le Roux
 | 
				
			||||||
 | 
					    Justin Spedding
 | 
				
			||||||
 | 
					    Keith Bradner
 | 
				
			||||||
 | 
					    kindzadza
 | 
				
			||||||
 | 
					    KsyTek Games
 | 
				
			||||||
 | 
					    Kyle Burnett
 | 
				
			||||||
 | 
					    Kyle Haltermann
 | 
				
			||||||
 | 
					    Kyle Jacobs
 | 
				
			||||||
 | 
					    Leland Vakarian
 | 
				
			||||||
 | 
					    Levi Berciu
 | 
				
			||||||
 | 
					    liberodark
 | 
				
			||||||
 | 
					    Linus Lind Lundgren
 | 
				
			||||||
 | 
					    Ludovic DELVAL
 | 
				
			||||||
 | 
					    Luigi Renna
 | 
				
			||||||
 | 
					    Luis Morao
 | 
				
			||||||
 | 
					    Lukas Komischke
 | 
				
			||||||
 | 
					    Luke Diasio
 | 
				
			||||||
 | 
					    Major Haul
 | 
				
			||||||
 | 
					    Malcolm
 | 
				
			||||||
 | 
					    Manuele Finocchiaro
 | 
				
			||||||
 | 
					    Marcos Heitor Carvalho
 | 
				
			||||||
 | 
					    Markie Music
 | 
				
			||||||
 | 
					    Mark Tyler
 | 
				
			||||||
 | 
					    Markus Michael Egger
 | 
				
			||||||
 | 
					    Martin Holas
 | 
				
			||||||
 | 
					    Martin Liška
 | 
				
			||||||
 | 
					    Martin Trbola
 | 
				
			||||||
 | 
					    Matěj Drábek
 | 
				
			||||||
 | 
					    Mathieu
 | 
				
			||||||
 | 
					    Matt Edwards
 | 
				
			||||||
 | 
					    Maverick
 | 
				
			||||||
 | 
					    Maxime Blade
 | 
				
			||||||
 | 
					    Maxwell
 | 
				
			||||||
 | 
					    Melissa Mears
 | 
				
			||||||
 | 
					    Metal Demon 2000
 | 
				
			||||||
 | 
					    Michael Morrison
 | 
				
			||||||
 | 
					    Mike Copley
 | 
				
			||||||
 | 
					    Molly Jameson
 | 
				
			||||||
 | 
					    Moritz Weissenberger
 | 
				
			||||||
 | 
					    Mrjemandem
 | 
				
			||||||
 | 
					    naonya3
 | 
				
			||||||
 | 
					    Nathaniel
 | 
				
			||||||
 | 
					    neighty
 | 
				
			||||||
 | 
					    Neil Blakey-Milner
 | 
				
			||||||
 | 
					    Neofytos Chimonas
 | 
				
			||||||
 | 
					    Nerdforge
 | 
				
			||||||
 | 
					    Nerdyninja
 | 
				
			||||||
 | 
					    Nick Eldrenkamp
 | 
				
			||||||
 | 
					    Nik Rudenko
 | 
				
			||||||
 | 
					    Noel Billig
 | 
				
			||||||
 | 
					    ozrk
 | 
				
			||||||
 | 
					    Patrick Horn
 | 
				
			||||||
 | 
					    Patrickm
 | 
				
			||||||
 | 
					    Patrick Nafarrete
 | 
				
			||||||
 | 
					    Paul Black
 | 
				
			||||||
 | 
					    Paul Gieske
 | 
				
			||||||
 | 
					    Paul Mozet
 | 
				
			||||||
 | 
					    Pete
 | 
				
			||||||
 | 
					    Phoenix Jauregui
 | 
				
			||||||
 | 
					    Pierre Caye
 | 
				
			||||||
 | 
					    Pixel Archipel
 | 
				
			||||||
 | 
					    Point08
 | 
				
			||||||
 | 
					    PsycHead
 | 
				
			||||||
 | 
					    Quincy Quincy
 | 
				
			||||||
 | 
					    Quinn Morrison
 | 
				
			||||||
 | 
					    Raghava Kovvali
 | 
				
			||||||
 | 
					    Ragnar Pettersson
 | 
				
			||||||
 | 
					    Rammeow
 | 
				
			||||||
 | 
					    Rebecca H
 | 
				
			||||||
 | 
					    Richard Hayes
 | 
				
			||||||
 | 
					    Riley
 | 
				
			||||||
 | 
					    RobotCritter
 | 
				
			||||||
 | 
					    Roland Rząsa
 | 
				
			||||||
 | 
					    Russ
 | 
				
			||||||
 | 
					    Ryan Groom
 | 
				
			||||||
 | 
					    Sammy Fischer
 | 
				
			||||||
 | 
					    Satnam Singh
 | 
				
			||||||
 | 
					    Sebastian Michailidis
 | 
				
			||||||
 | 
					    SeongWan Kim
 | 
				
			||||||
 | 
					    Shane Lillie
 | 
				
			||||||
 | 
					    Shane Spoor
 | 
				
			||||||
 | 
					    Shaun Kohanowski
 | 
				
			||||||
 | 
					    Simon Jonas Larsen
 | 
				
			||||||
 | 
					    Simon Schoenenberger
 | 
				
			||||||
 | 
					    Sina Yeganeh
 | 
				
			||||||
 | 
					    Skalli
 | 
				
			||||||
 | 
					    slavfox
 | 
				
			||||||
 | 
					    smo1704
 | 
				
			||||||
 | 
					    SpicyCactuar
 | 
				
			||||||
 | 
					    Stephen Rice
 | 
				
			||||||
 | 
					    Stephen Schlie
 | 
				
			||||||
 | 
					    Sven Walter
 | 
				
			||||||
 | 
					    SxP
 | 
				
			||||||
 | 
					    tadashi endo
 | 
				
			||||||
 | 
					    Tarch
 | 
				
			||||||
 | 
					    TheVoiceInMyHead
 | 
				
			||||||
 | 
					    Thibaut DECROMBECQUE
 | 
				
			||||||
 | 
					    thomas
 | 
				
			||||||
 | 
					    Thomas Pickett
 | 
				
			||||||
 | 
					    Tim Drumheller
 | 
				
			||||||
 | 
					    Tim Klein
 | 
				
			||||||
 | 
					    Tom Webster
 | 
				
			||||||
 | 
					    Trent Skinner
 | 
				
			||||||
 | 
					    Tyler Stepke
 | 
				
			||||||
 | 
					    Uther
 | 
				
			||||||
 | 
					    Vaughan Ling
 | 
				
			||||||
 | 
					    vlnx
 | 
				
			||||||
 | 
					    Wapiti .
 | 
				
			||||||
 | 
					    Wiley Thompson
 | 
				
			||||||
 | 
					    Xatonym
 | 
				
			||||||
 | 
					    Zekim
 | 
				
			||||||
 | 
					    ケルベロス
 | 
				
			||||||
 | 
					    貴宏 小松
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    And 181 anonymous donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Silver and bronze donors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are even more donors that support the project with a small monthly donation.
 | 
				
			||||||
 | 
					Every bit counts and we thank every one of them for their amazing support!
 | 
				
			||||||
							
								
								
									
										20
									
								
								engine/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								engine/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
							
								
								
									
										5
									
								
								engine/LOGO_LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								engine/LOGO_LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					Godot Engine Logo
 | 
				
			||||||
 | 
					Copyright (c) 2017 Andrea Calabró
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This work is licensed under the Creative Commons Attribution 4.0 International
 | 
				
			||||||
 | 
					license (CC BY 4.0 International): https://creativecommons.org/licenses/by/4.0/
 | 
				
			||||||
							
								
								
									
										78
									
								
								engine/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								engine/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,78 @@
 | 
				
			||||||
 | 
					# Godot Engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p align="center">
 | 
				
			||||||
 | 
					  <a href="https://godotengine.org">
 | 
				
			||||||
 | 
					    <img src="logo_outlined.svg" width="400" alt="Godot Engine logo">
 | 
				
			||||||
 | 
					  </a>
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2D and 3D cross-platform game engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**[Godot Engine](https://godotengine.org) is a feature-packed, cross-platform
 | 
				
			||||||
 | 
					game engine to create 2D and 3D games from a unified interface.** It provides a
 | 
				
			||||||
 | 
					comprehensive set of [common tools](https://godotengine.org/features), so that
 | 
				
			||||||
 | 
					users can focus on making games without having to reinvent the wheel. Games can
 | 
				
			||||||
 | 
					be exported with one click to a number of platforms, including the major desktop
 | 
				
			||||||
 | 
					platforms (Linux, macOS, Windows), mobile platforms (Android, iOS), as well as
 | 
				
			||||||
 | 
					Web-based platforms and [consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Free, open source and community-driven
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Godot is completely free and open source under the very permissive [MIT license](https://godotengine.org/license).
 | 
				
			||||||
 | 
					No strings attached, no royalties, nothing. The users' games are theirs, down
 | 
				
			||||||
 | 
					to the last line of engine code. Godot's development is fully independent and
 | 
				
			||||||
 | 
					community-driven, empowering users to help shape their engine to match their
 | 
				
			||||||
 | 
					expectations. It is supported by the [Godot Foundation](https://godot.foundation/)
 | 
				
			||||||
 | 
					not-for-profit.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Before being open sourced in [February 2014](https://github.com/godotengine/godot/commit/0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac),
 | 
				
			||||||
 | 
					Godot had been developed by [Juan Linietsky](https://github.com/reduz) and
 | 
				
			||||||
 | 
					[Ariel Manzur](https://github.com/punto-) (both still maintaining the project)
 | 
				
			||||||
 | 
					for several years as an in-house engine, used to publish several work-for-hire
 | 
				
			||||||
 | 
					titles.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Getting the engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Binary downloads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Official binaries for the Godot editor and the export templates can be found
 | 
				
			||||||
 | 
					[on the Godot website](https://godotengine.org/download).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Compiling from source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[See the official docs](https://docs.godotengine.org/en/latest/contributing/development/compiling)
 | 
				
			||||||
 | 
					for compilation instructions for every supported platform.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Community and contributing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Godot is not only an engine but an ever-growing community of users and engine
 | 
				
			||||||
 | 
					developers. The main community channels are listed [on the homepage](https://godotengine.org/community).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The best way to get in touch with the core engine developers is to join the
 | 
				
			||||||
 | 
					[Godot Contributors Chat](https://chat.godotengine.org).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md).
 | 
				
			||||||
 | 
					This document also includes guidelines for reporting bugs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Documentation and demos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The official documentation is hosted on [Read the Docs](https://docs.godotengine.org).
 | 
				
			||||||
 | 
					It is maintained by the Godot community in its own [GitHub repository](https://github.com/godotengine/godot-docs).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The [class reference](https://docs.godotengine.org/en/latest/classes/)
 | 
				
			||||||
 | 
					is also accessible from the Godot editor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We also maintain official demos in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
 | 
				
			||||||
 | 
					as well as a list of [awesome Godot community resources](https://github.com/godotengine/awesome-godot).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are also a number of other
 | 
				
			||||||
 | 
					[learning resources](https://docs.godotengine.org/en/latest/community/tutorials.html)
 | 
				
			||||||
 | 
					provided by the community, such as text and video tutorials, demos, etc.
 | 
				
			||||||
 | 
					Consult the [community channels](https://godotengine.org/community)
 | 
				
			||||||
 | 
					for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[](https://www.codetriage.com/godotengine/godot)
 | 
				
			||||||
 | 
					[](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
 | 
				
			||||||
 | 
					[](https://www.tickgit.com/browse?repo=github.com/godotengine/godot)
 | 
				
			||||||
							
								
								
									
										1104
									
								
								engine/SConstruct
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1104
									
								
								engine/SConstruct
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										298
									
								
								engine/core/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								engine/core/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,298 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import core_builders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.core_sources = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add required thirdparty code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					thirdparty_obj = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_thirdparty = env.Clone()
 | 
				
			||||||
 | 
					env_thirdparty.disable_warnings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Misc thirdparty code: header paths are hardcoded, we don't need to append
 | 
				
			||||||
 | 
					# to the include path (saves a few chars on the compiler invocation for touchy MSVC...)
 | 
				
			||||||
 | 
					thirdparty_misc_dir = "#thirdparty/misc/"
 | 
				
			||||||
 | 
					thirdparty_misc_sources = [
 | 
				
			||||||
 | 
					    # C sources
 | 
				
			||||||
 | 
					    "fastlz.c",
 | 
				
			||||||
 | 
					    "r128.c",
 | 
				
			||||||
 | 
					    "smaz.c",
 | 
				
			||||||
 | 
					    # C++ sources
 | 
				
			||||||
 | 
					    "pcg.cpp",
 | 
				
			||||||
 | 
					    "polypartition.cpp",
 | 
				
			||||||
 | 
					    "smolv.cpp",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
 | 
				
			||||||
 | 
					env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Brotli
 | 
				
			||||||
 | 
					if env["brotli"] and env["builtin_brotli"]:
 | 
				
			||||||
 | 
					    thirdparty_brotli_dir = "#thirdparty/brotli/"
 | 
				
			||||||
 | 
					    thirdparty_brotli_sources = [
 | 
				
			||||||
 | 
					        "common/constants.c",
 | 
				
			||||||
 | 
					        "common/context.c",
 | 
				
			||||||
 | 
					        "common/dictionary.c",
 | 
				
			||||||
 | 
					        "common/platform.c",
 | 
				
			||||||
 | 
					        "common/shared_dictionary.c",
 | 
				
			||||||
 | 
					        "common/transform.c",
 | 
				
			||||||
 | 
					        "dec/bit_reader.c",
 | 
				
			||||||
 | 
					        "dec/decode.c",
 | 
				
			||||||
 | 
					        "dec/huffman.c",
 | 
				
			||||||
 | 
					        "dec/state.c",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    thirdparty_brotli_sources = [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
 | 
				
			||||||
 | 
					    env.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
 | 
				
			||||||
 | 
					        env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_brotli_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Clipper2 Thirdparty source files used for polygon and polyline boolean operations.
 | 
				
			||||||
 | 
					if env["builtin_clipper2"]:
 | 
				
			||||||
 | 
					    thirdparty_clipper_dir = "#thirdparty/clipper2/"
 | 
				
			||||||
 | 
					    thirdparty_clipper_sources = [
 | 
				
			||||||
 | 
					        "src/clipper.engine.cpp",
 | 
				
			||||||
 | 
					        "src/clipper.offset.cpp",
 | 
				
			||||||
 | 
					        "src/clipper.rectclip.cpp",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
 | 
				
			||||||
 | 
					    env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
 | 
				
			||||||
 | 
					    env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_clipper_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Zlib library, can be unbundled
 | 
				
			||||||
 | 
					if env["builtin_zlib"]:
 | 
				
			||||||
 | 
					    thirdparty_zlib_dir = "#thirdparty/zlib/"
 | 
				
			||||||
 | 
					    thirdparty_zlib_sources = [
 | 
				
			||||||
 | 
					        "adler32.c",
 | 
				
			||||||
 | 
					        "compress.c",
 | 
				
			||||||
 | 
					        "crc32.c",
 | 
				
			||||||
 | 
					        "deflate.c",
 | 
				
			||||||
 | 
					        "inffast.c",
 | 
				
			||||||
 | 
					        "inflate.c",
 | 
				
			||||||
 | 
					        "inftrees.c",
 | 
				
			||||||
 | 
					        "trees.c",
 | 
				
			||||||
 | 
					        "uncompr.c",
 | 
				
			||||||
 | 
					        "zutil.c",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
 | 
				
			||||||
 | 
					    # Needs to be available in main env too
 | 
				
			||||||
 | 
					    env.Prepend(CPPPATH=[thirdparty_zlib_dir])
 | 
				
			||||||
 | 
					    if env.dev_build:
 | 
				
			||||||
 | 
					        env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Minizip library, could be unbundled in theory
 | 
				
			||||||
 | 
					# However, our version has some custom modifications, so it won't compile with the system one
 | 
				
			||||||
 | 
					thirdparty_minizip_dir = "#thirdparty/minizip/"
 | 
				
			||||||
 | 
					thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
 | 
				
			||||||
 | 
					thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
 | 
				
			||||||
 | 
					env_thirdparty.add_source_files(thirdparty_obj, thirdparty_minizip_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Zstd library, can be unbundled in theory
 | 
				
			||||||
 | 
					# though we currently use some private symbols
 | 
				
			||||||
 | 
					# https://github.com/godotengine/godot/issues/17374
 | 
				
			||||||
 | 
					if env["builtin_zstd"]:
 | 
				
			||||||
 | 
					    thirdparty_zstd_dir = "#thirdparty/zstd/"
 | 
				
			||||||
 | 
					    thirdparty_zstd_sources = [
 | 
				
			||||||
 | 
					        "common/debug.c",
 | 
				
			||||||
 | 
					        "common/entropy_common.c",
 | 
				
			||||||
 | 
					        "common/error_private.c",
 | 
				
			||||||
 | 
					        "common/fse_decompress.c",
 | 
				
			||||||
 | 
					        "common/pool.c",
 | 
				
			||||||
 | 
					        "common/threading.c",
 | 
				
			||||||
 | 
					        "common/xxhash.c",
 | 
				
			||||||
 | 
					        "common/zstd_common.c",
 | 
				
			||||||
 | 
					        "compress/fse_compress.c",
 | 
				
			||||||
 | 
					        "compress/hist.c",
 | 
				
			||||||
 | 
					        "compress/huf_compress.c",
 | 
				
			||||||
 | 
					        "compress/zstd_compress.c",
 | 
				
			||||||
 | 
					        "compress/zstd_double_fast.c",
 | 
				
			||||||
 | 
					        "compress/zstd_fast.c",
 | 
				
			||||||
 | 
					        "compress/zstd_lazy.c",
 | 
				
			||||||
 | 
					        "compress/zstd_ldm.c",
 | 
				
			||||||
 | 
					        "compress/zstd_opt.c",
 | 
				
			||||||
 | 
					        "compress/zstdmt_compress.c",
 | 
				
			||||||
 | 
					        "compress/zstd_compress_literals.c",
 | 
				
			||||||
 | 
					        "compress/zstd_compress_sequences.c",
 | 
				
			||||||
 | 
					        "compress/zstd_compress_superblock.c",
 | 
				
			||||||
 | 
					        "decompress/huf_decompress.c",
 | 
				
			||||||
 | 
					        "decompress/zstd_ddict.c",
 | 
				
			||||||
 | 
					        "decompress/zstd_decompress_block.c",
 | 
				
			||||||
 | 
					        "decompress/zstd_decompress.c",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    if env["platform"] in ["android", "ios", "linuxbsd", "macos"]:
 | 
				
			||||||
 | 
					        # Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
 | 
				
			||||||
 | 
					        thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
 | 
				
			||||||
 | 
					    thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
 | 
				
			||||||
 | 
					    env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
 | 
				
			||||||
 | 
					    env.Prepend(CPPPATH=thirdparty_zstd_dir)
 | 
				
			||||||
 | 
					    # Also needed in main env includes will trigger warnings
 | 
				
			||||||
 | 
					    env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zstd_sources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.core_sources += thirdparty_obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Godot source files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate disabled classes
 | 
				
			||||||
 | 
					def disabled_class_builder(target, source, env):
 | 
				
			||||||
 | 
					    with methods.generated_wrapper(target) as file:
 | 
				
			||||||
 | 
					        for c in source[0].read():
 | 
				
			||||||
 | 
					            cs = c.strip()
 | 
				
			||||||
 | 
					            if cs != "":
 | 
				
			||||||
 | 
					                file.write(f"#define ClassDB_Disable_{cs} 1\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate version info
 | 
				
			||||||
 | 
					def version_info_builder(target, source, env):
 | 
				
			||||||
 | 
					    with methods.generated_wrapper(target) as file:
 | 
				
			||||||
 | 
					        file.write(
 | 
				
			||||||
 | 
					            """\
 | 
				
			||||||
 | 
					#define VERSION_SHORT_NAME "{short_name}"
 | 
				
			||||||
 | 
					#define VERSION_NAME "{name}"
 | 
				
			||||||
 | 
					#define VERSION_MAJOR {major}
 | 
				
			||||||
 | 
					#define VERSION_MINOR {minor}
 | 
				
			||||||
 | 
					#define VERSION_PATCH {patch}
 | 
				
			||||||
 | 
					#define VERSION_STATUS "{status}"
 | 
				
			||||||
 | 
					#define VERSION_BUILD "{build}"
 | 
				
			||||||
 | 
					#define VERSION_MODULE_CONFIG "{module_config}"
 | 
				
			||||||
 | 
					#define VERSION_WEBSITE "{website}"
 | 
				
			||||||
 | 
					#define VERSION_DOCS_BRANCH "{docs_branch}"
 | 
				
			||||||
 | 
					#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
 | 
				
			||||||
 | 
					""".format(**env.version_info)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate version hash
 | 
				
			||||||
 | 
					def version_hash_builder(target, source, env):
 | 
				
			||||||
 | 
					    with methods.generated_wrapper(target) as file:
 | 
				
			||||||
 | 
					        file.write(
 | 
				
			||||||
 | 
					            """\
 | 
				
			||||||
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *const VERSION_HASH = "{git_hash}";
 | 
				
			||||||
 | 
					const uint64_t VERSION_TIMESTAMP = {git_timestamp};
 | 
				
			||||||
 | 
					""".format(**env.version_info)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gen_hash = env.CommandNoCache(
 | 
				
			||||||
 | 
					    "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, gen_hash)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate AES256 script encryption key
 | 
				
			||||||
 | 
					def encryption_key_builder(target, source, env):
 | 
				
			||||||
 | 
					    with methods.generated_wrapper(target) as file:
 | 
				
			||||||
 | 
					        file.write(
 | 
				
			||||||
 | 
					            f"""\
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t script_encryption_key[32] = {{
 | 
				
			||||||
 | 
						{source[0]}
 | 
				
			||||||
 | 
					}};"""
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
 | 
				
			||||||
 | 
					ec_valid = len(gdkey) == 64
 | 
				
			||||||
 | 
					if ec_valid:
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
 | 
				
			||||||
 | 
					    except Exception:
 | 
				
			||||||
 | 
					        ec_valid = False
 | 
				
			||||||
 | 
					if not ec_valid:
 | 
				
			||||||
 | 
					    methods.print_error(
 | 
				
			||||||
 | 
					        f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
 | 
				
			||||||
 | 
					        "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
 | 
				
			||||||
 | 
					        "or make sure that it contains exactly 64 hexadecimal characters."
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    Exit(255)
 | 
				
			||||||
 | 
					gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, gen_encrypt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Certificates
 | 
				
			||||||
 | 
					env.Depends(
 | 
				
			||||||
 | 
					    "#core/io/certs_compressed.gen.h",
 | 
				
			||||||
 | 
					    ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					env.CommandNoCache(
 | 
				
			||||||
 | 
					    "#core/io/certs_compressed.gen.h",
 | 
				
			||||||
 | 
					    "#thirdparty/certs/ca-certificates.crt",
 | 
				
			||||||
 | 
					    env.Run(core_builders.make_certs_header),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Authors
 | 
				
			||||||
 | 
					env.Depends("#core/authors.gen.h", "../AUTHORS.md")
 | 
				
			||||||
 | 
					env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Donors
 | 
				
			||||||
 | 
					env.Depends("#core/donors.gen.h", "../DONORS.md")
 | 
				
			||||||
 | 
					env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# License
 | 
				
			||||||
 | 
					env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
 | 
				
			||||||
 | 
					env.CommandNoCache(
 | 
				
			||||||
 | 
					    "#core/license.gen.h",
 | 
				
			||||||
 | 
					    ["../COPYRIGHT.txt", "../LICENSE.txt"],
 | 
				
			||||||
 | 
					    env.Run(core_builders.make_license_header),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Chain load SCsubs
 | 
				
			||||||
 | 
					SConscript("os/SCsub")
 | 
				
			||||||
 | 
					SConscript("math/SCsub")
 | 
				
			||||||
 | 
					SConscript("crypto/SCsub")
 | 
				
			||||||
 | 
					SConscript("io/SCsub")
 | 
				
			||||||
 | 
					SConscript("debugger/SCsub")
 | 
				
			||||||
 | 
					SConscript("input/SCsub")
 | 
				
			||||||
 | 
					SConscript("variant/SCsub")
 | 
				
			||||||
 | 
					SConscript("extension/SCsub")
 | 
				
			||||||
 | 
					SConscript("object/SCsub")
 | 
				
			||||||
 | 
					SConscript("templates/SCsub")
 | 
				
			||||||
 | 
					SConscript("string/SCsub")
 | 
				
			||||||
 | 
					SConscript("config/SCsub")
 | 
				
			||||||
 | 
					SConscript("error/SCsub")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build it all as a library
 | 
				
			||||||
 | 
					lib = env.add_library("core", env.core_sources)
 | 
				
			||||||
 | 
					env.Prepend(LIBS=[lib])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Needed to force rebuilding the core files when the thirdparty code is updated.
 | 
				
			||||||
 | 
					env.Depends(lib, thirdparty_obj)
 | 
				
			||||||
							
								
								
									
										7
									
								
								engine/core/config/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								engine/core/config/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_config = env.Clone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_config.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
							
								
								
									
										403
									
								
								engine/core/config/engine.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								engine/core/config/engine.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,403 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine.cpp                                                            */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "engine.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/authors.gen.h"
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/donors.gen.h"
 | 
				
			||||||
 | 
					#include "core/license.gen.h"
 | 
				
			||||||
 | 
					#include "core/variant/typed_array.h"
 | 
				
			||||||
 | 
					#include "core/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_physics_ticks_per_second(int p_ips) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
 | 
				
			||||||
 | 
						ips = p_ips;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Engine::get_physics_ticks_per_second() const {
 | 
				
			||||||
 | 
						return ips;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
 | 
				
			||||||
 | 
						max_physics_steps_per_frame = p_max_physics_steps;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Engine::get_max_physics_steps_per_frame() const {
 | 
				
			||||||
 | 
						return max_physics_steps_per_frame;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_physics_jitter_fix(double p_threshold) {
 | 
				
			||||||
 | 
						if (p_threshold < 0) {
 | 
				
			||||||
 | 
							p_threshold = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						physics_jitter_fix = p_threshold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double Engine::get_physics_jitter_fix() const {
 | 
				
			||||||
 | 
						return physics_jitter_fix;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_max_fps(int p_fps) {
 | 
				
			||||||
 | 
						_max_fps = p_fps > 0 ? p_fps : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Engine::get_max_fps() const {
 | 
				
			||||||
 | 
						return _max_fps;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_audio_output_latency(int p_msec) {
 | 
				
			||||||
 | 
						_audio_output_latency = p_msec > 1 ? p_msec : 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Engine::get_audio_output_latency() const {
 | 
				
			||||||
 | 
						return _audio_output_latency;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::increment_frames_drawn() {
 | 
				
			||||||
 | 
						if (frame_server_synced) {
 | 
				
			||||||
 | 
							server_syncs++;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							server_syncs = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						frame_server_synced = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						frames_drawn++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t Engine::get_frames_drawn() {
 | 
				
			||||||
 | 
						return frames_drawn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_frame_delay(uint32_t p_msec) {
 | 
				
			||||||
 | 
						_frame_delay = p_msec;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t Engine::get_frame_delay() const {
 | 
				
			||||||
 | 
						return _frame_delay;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_time_scale(double p_scale) {
 | 
				
			||||||
 | 
						_time_scale = p_scale;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double Engine::get_time_scale() const {
 | 
				
			||||||
 | 
						return _time_scale;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dictionary Engine::get_version_info() const {
 | 
				
			||||||
 | 
						Dictionary dict;
 | 
				
			||||||
 | 
						dict["major"] = VERSION_MAJOR;
 | 
				
			||||||
 | 
						dict["minor"] = VERSION_MINOR;
 | 
				
			||||||
 | 
						dict["patch"] = VERSION_PATCH;
 | 
				
			||||||
 | 
						dict["hex"] = VERSION_HEX;
 | 
				
			||||||
 | 
						dict["status"] = VERSION_STATUS;
 | 
				
			||||||
 | 
						dict["build"] = VERSION_BUILD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String hash = String(VERSION_HASH);
 | 
				
			||||||
 | 
						dict["hash"] = hash.is_empty() ? String("unknown") : hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dict["timestamp"] = VERSION_TIMESTAMP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String stringver = String(dict["major"]) + "." + String(dict["minor"]);
 | 
				
			||||||
 | 
						if ((int)dict["patch"] != 0) {
 | 
				
			||||||
 | 
							stringver += "." + String(dict["patch"]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						stringver += "-" + String(dict["status"]) + " (" + String(dict["build"]) + ")";
 | 
				
			||||||
 | 
						dict["string"] = stringver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dict;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Array array_from_info(const char *const *info_list) {
 | 
				
			||||||
 | 
						Array arr;
 | 
				
			||||||
 | 
						for (int i = 0; info_list[i] != nullptr; i++) {
 | 
				
			||||||
 | 
							arr.push_back(String::utf8(info_list[i]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Array array_from_info_count(const char *const *info_list, int info_count) {
 | 
				
			||||||
 | 
						Array arr;
 | 
				
			||||||
 | 
						for (int i = 0; i < info_count; i++) {
 | 
				
			||||||
 | 
							arr.push_back(String::utf8(info_list[i]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dictionary Engine::get_author_info() const {
 | 
				
			||||||
 | 
						Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dict["lead_developers"] = array_from_info(AUTHORS_LEAD_DEVELOPERS);
 | 
				
			||||||
 | 
						dict["project_managers"] = array_from_info(AUTHORS_PROJECT_MANAGERS);
 | 
				
			||||||
 | 
						dict["founders"] = array_from_info(AUTHORS_FOUNDERS);
 | 
				
			||||||
 | 
						dict["developers"] = array_from_info(AUTHORS_DEVELOPERS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dict;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypedArray<Dictionary> Engine::get_copyright_info() const {
 | 
				
			||||||
 | 
						TypedArray<Dictionary> components;
 | 
				
			||||||
 | 
						for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
 | 
				
			||||||
 | 
							const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
 | 
				
			||||||
 | 
							Dictionary component_dict;
 | 
				
			||||||
 | 
							component_dict["name"] = String::utf8(cp_info.name);
 | 
				
			||||||
 | 
							Array parts;
 | 
				
			||||||
 | 
							for (int i = 0; i < cp_info.part_count; i++) {
 | 
				
			||||||
 | 
								const ComponentCopyrightPart &cp_part = cp_info.parts[i];
 | 
				
			||||||
 | 
								Dictionary part_dict;
 | 
				
			||||||
 | 
								part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count);
 | 
				
			||||||
 | 
								part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count);
 | 
				
			||||||
 | 
								part_dict["license"] = String::utf8(cp_part.license);
 | 
				
			||||||
 | 
								parts.push_back(part_dict);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							component_dict["parts"] = parts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							components.push_back(component_dict);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return components;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dictionary Engine::get_donor_info() const {
 | 
				
			||||||
 | 
						Dictionary donors;
 | 
				
			||||||
 | 
						donors["patrons"] = array_from_info(DONORS_PATRONS);
 | 
				
			||||||
 | 
						donors["platinum_sponsors"] = array_from_info(DONORS_SPONSORS_PLATINUM);
 | 
				
			||||||
 | 
						donors["gold_sponsors"] = array_from_info(DONORS_SPONSORS_GOLD);
 | 
				
			||||||
 | 
						donors["silver_sponsors"] = array_from_info(DONORS_SPONSORS_SILVER);
 | 
				
			||||||
 | 
						donors["diamond_members"] = array_from_info(DONORS_MEMBERS_DIAMOND);
 | 
				
			||||||
 | 
						donors["titanium_members"] = array_from_info(DONORS_MEMBERS_TITANIUM);
 | 
				
			||||||
 | 
						donors["platinum_members"] = array_from_info(DONORS_MEMBERS_PLATINUM);
 | 
				
			||||||
 | 
						donors["gold_members"] = array_from_info(DONORS_MEMBERS_GOLD);
 | 
				
			||||||
 | 
						return donors;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dictionary Engine::get_license_info() const {
 | 
				
			||||||
 | 
						Dictionary licenses;
 | 
				
			||||||
 | 
						for (int i = 0; i < LICENSE_COUNT; i++) {
 | 
				
			||||||
 | 
							licenses[LICENSE_NAMES[i]] = LICENSE_BODIES[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return licenses;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String Engine::get_license_text() const {
 | 
				
			||||||
 | 
						return String(GODOT_LICENSE_TEXT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String Engine::get_architecture_name() const {
 | 
				
			||||||
 | 
					#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
 | 
				
			||||||
 | 
						return "x86_64";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
 | 
				
			||||||
 | 
						return "x86_32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
 | 
				
			||||||
 | 
						return "arm64";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__arm__) || defined(_M_ARM)
 | 
				
			||||||
 | 
						return "arm32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__riscv)
 | 
				
			||||||
 | 
					#if __riscv_xlen == 8
 | 
				
			||||||
 | 
						return "rv64";
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return "riscv";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__powerpc__)
 | 
				
			||||||
 | 
					#if defined(__powerpc64__)
 | 
				
			||||||
 | 
						return "ppc64";
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return "ppc";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__wasm__)
 | 
				
			||||||
 | 
					#if defined(__wasm64__)
 | 
				
			||||||
 | 
						return "wasm64";
 | 
				
			||||||
 | 
					#elif defined(__wasm32__)
 | 
				
			||||||
 | 
						return "wasm32";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_abort_on_gpu_errors_enabled() const {
 | 
				
			||||||
 | 
						return abort_on_gpu_errors;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t Engine::get_gpu_index() const {
 | 
				
			||||||
 | 
						return gpu_idx;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_validation_layers_enabled() const {
 | 
				
			||||||
 | 
						return use_validation_layers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_generate_spirv_debug_info_enabled() const {
 | 
				
			||||||
 | 
						return generate_spirv_debug_info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_print_error_messages(bool p_enabled) {
 | 
				
			||||||
 | 
						CoreGlobals::print_error_enabled = p_enabled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_printing_error_messages() const {
 | 
				
			||||||
 | 
						return CoreGlobals::print_error_enabled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::print_header(const String &p_string) const {
 | 
				
			||||||
 | 
						if (_print_header) {
 | 
				
			||||||
 | 
							print_line(p_string);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::print_header_rich(const String &p_string) const {
 | 
				
			||||||
 | 
						if (_print_header) {
 | 
				
			||||||
 | 
							print_line_rich(p_string);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::add_singleton(const Singleton &p_singleton) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
 | 
				
			||||||
 | 
						singletons.push_back(p_singleton);
 | 
				
			||||||
 | 
						singleton_ptrs[p_singleton.name] = p_singleton.ptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Object *Engine::get_singleton_object(const StringName &p_name) const {
 | 
				
			||||||
 | 
						HashMap<StringName, Object *>::ConstIterator E = singleton_ptrs.find(p_name);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("Failed to retrieve non-existent singleton '%s'.", p_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						if (!is_editor_hint() && is_singleton_editor_only(p_name)) {
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(nullptr, vformat("Can't retrieve singleton '%s' outside of editor.", p_name));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return E->value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_singleton_user_created(const StringName &p_name) const {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const Singleton &E : singletons) {
 | 
				
			||||||
 | 
							if (E.name == p_name && E.user_created) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::is_singleton_editor_only(const StringName &p_name) const {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const Singleton &E : singletons) {
 | 
				
			||||||
 | 
							if (E.name == p_name && E.editor_only) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::remove_singleton(const StringName &p_name) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND(!singleton_ptrs.has(p_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) {
 | 
				
			||||||
 | 
							if (E->get().name == p_name) {
 | 
				
			||||||
 | 
								singletons.erase(E);
 | 
				
			||||||
 | 
								singleton_ptrs.erase(p_name);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::has_singleton(const StringName &p_name) const {
 | 
				
			||||||
 | 
						return singleton_ptrs.has(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::get_singletons(List<Singleton> *p_singletons) {
 | 
				
			||||||
 | 
						for (const Singleton &E : singletons) {
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
							if (!is_editor_hint() && E.editor_only) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							p_singletons->push_back(E);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String Engine::get_write_movie_path() const {
 | 
				
			||||||
 | 
						return write_movie_path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_write_movie_path(const String &p_path) {
 | 
				
			||||||
 | 
						write_movie_path = p_path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Engine::set_shader_cache_path(const String &p_path) {
 | 
				
			||||||
 | 
						shader_cache_path = p_path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					String Engine::get_shader_cache_path() const {
 | 
				
			||||||
 | 
						return shader_cache_path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Engine *Engine::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Engine *Engine::get_singleton() {
 | 
				
			||||||
 | 
						return singleton;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Engine::notify_frame_server_synced() {
 | 
				
			||||||
 | 
						frame_server_synced = true;
 | 
				
			||||||
 | 
						return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Engine::Engine() {
 | 
				
			||||||
 | 
						singleton = this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Engine::~Engine() {
 | 
				
			||||||
 | 
						if (singleton == this) {
 | 
				
			||||||
 | 
							singleton = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
 | 
				
			||||||
 | 
							name(p_name),
 | 
				
			||||||
 | 
							ptr(p_ptr),
 | 
				
			||||||
 | 
							class_name(p_class_name) {
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
 | 
				
			||||||
 | 
						if (rc && !rc->is_referenced()) {
 | 
				
			||||||
 | 
							WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										193
									
								
								engine/core/config/engine.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								engine/core/config/engine.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,193 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine.h                                                              */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ENGINE_H
 | 
				
			||||||
 | 
					#define ENGINE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/os/main_loop.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					#include "core/templates/list.h"
 | 
				
			||||||
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class TypedArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Engine {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						struct Singleton {
 | 
				
			||||||
 | 
							StringName name;
 | 
				
			||||||
 | 
							Object *ptr = nullptr;
 | 
				
			||||||
 | 
							StringName class_name; // Used for binding generation hinting.
 | 
				
			||||||
 | 
							// Singleton scope flags.
 | 
				
			||||||
 | 
							bool user_created = false;
 | 
				
			||||||
 | 
							bool editor_only = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						friend class Main;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t frames_drawn = 0;
 | 
				
			||||||
 | 
						uint32_t _frame_delay = 0;
 | 
				
			||||||
 | 
						uint64_t _frame_ticks = 0;
 | 
				
			||||||
 | 
						double _process_step = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int ips = 60;
 | 
				
			||||||
 | 
						double physics_jitter_fix = 0.5;
 | 
				
			||||||
 | 
						double _fps = 1;
 | 
				
			||||||
 | 
						int _max_fps = 0;
 | 
				
			||||||
 | 
						int _audio_output_latency = 0;
 | 
				
			||||||
 | 
						double _time_scale = 1.0;
 | 
				
			||||||
 | 
						uint64_t _physics_frames = 0;
 | 
				
			||||||
 | 
						int max_physics_steps_per_frame = 8;
 | 
				
			||||||
 | 
						double _physics_interpolation_fraction = 0.0f;
 | 
				
			||||||
 | 
						bool abort_on_gpu_errors = false;
 | 
				
			||||||
 | 
						bool use_validation_layers = false;
 | 
				
			||||||
 | 
						bool generate_spirv_debug_info = false;
 | 
				
			||||||
 | 
						int32_t gpu_idx = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t _process_frames = 0;
 | 
				
			||||||
 | 
						bool _in_physics = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Singleton> singletons;
 | 
				
			||||||
 | 
						HashMap<StringName, Object *> singleton_ptrs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool editor_hint = false;
 | 
				
			||||||
 | 
						bool project_manager_hint = false;
 | 
				
			||||||
 | 
						bool extension_reloading = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _print_header = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Engine *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String write_movie_path;
 | 
				
			||||||
 | 
						String shader_cache_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr int SERVER_SYNC_FRAME_COUNT_WARNING = 5;
 | 
				
			||||||
 | 
						int server_syncs = 0;
 | 
				
			||||||
 | 
						bool frame_server_synced = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Engine *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void set_physics_ticks_per_second(int p_ips);
 | 
				
			||||||
 | 
						virtual int get_physics_ticks_per_second() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void set_max_physics_steps_per_frame(int p_max_physics_steps);
 | 
				
			||||||
 | 
						virtual int get_max_physics_steps_per_frame() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_physics_jitter_fix(double p_threshold);
 | 
				
			||||||
 | 
						double get_physics_jitter_fix() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void set_max_fps(int p_fps);
 | 
				
			||||||
 | 
						virtual int get_max_fps() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void set_audio_output_latency(int p_msec);
 | 
				
			||||||
 | 
						virtual int get_audio_output_latency() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual double get_frames_per_second() const { return _fps; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t get_frames_drawn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t get_physics_frames() const { return _physics_frames; }
 | 
				
			||||||
 | 
						uint64_t get_process_frames() const { return _process_frames; }
 | 
				
			||||||
 | 
						bool is_in_physics_frame() const { return _in_physics; }
 | 
				
			||||||
 | 
						uint64_t get_frame_ticks() const { return _frame_ticks; }
 | 
				
			||||||
 | 
						double get_process_step() const { return _process_step; }
 | 
				
			||||||
 | 
						double get_physics_interpolation_fraction() const { return _physics_interpolation_fraction; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_time_scale(double p_scale);
 | 
				
			||||||
 | 
						double get_time_scale() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_print_error_messages(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_printing_error_messages() const;
 | 
				
			||||||
 | 
						void print_header(const String &p_string) const;
 | 
				
			||||||
 | 
						void print_header_rich(const String &p_string) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_frame_delay(uint32_t p_msec);
 | 
				
			||||||
 | 
						uint32_t get_frame_delay() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void add_singleton(const Singleton &p_singleton);
 | 
				
			||||||
 | 
						void get_singletons(List<Singleton> *p_singletons);
 | 
				
			||||||
 | 
						bool has_singleton(const StringName &p_name) const;
 | 
				
			||||||
 | 
						Object *get_singleton_object(const StringName &p_name) const;
 | 
				
			||||||
 | 
						void remove_singleton(const StringName &p_name);
 | 
				
			||||||
 | 
						bool is_singleton_user_created(const StringName &p_name) const;
 | 
				
			||||||
 | 
						bool is_singleton_editor_only(const StringName &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; }
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_editor_hint() const { return editor_hint; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) { project_manager_hint = p_enabled; }
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_project_manager_hint() const { return project_manager_hint; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; }
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return extension_reloading; }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_editor_hint() const { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) {}
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_project_manager_hint() const { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dictionary get_version_info() const;
 | 
				
			||||||
 | 
						Dictionary get_author_info() const;
 | 
				
			||||||
 | 
						TypedArray<Dictionary> get_copyright_info() const;
 | 
				
			||||||
 | 
						Dictionary get_donor_info() const;
 | 
				
			||||||
 | 
						Dictionary get_license_info() const;
 | 
				
			||||||
 | 
						String get_license_text() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_write_movie_path(const String &p_path);
 | 
				
			||||||
 | 
						String get_write_movie_path() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_architecture_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_shader_cache_path(const String &p_path);
 | 
				
			||||||
 | 
						String get_shader_cache_path() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_abort_on_gpu_errors_enabled() const;
 | 
				
			||||||
 | 
						bool is_validation_layers_enabled() const;
 | 
				
			||||||
 | 
						bool is_generate_spirv_debug_info_enabled() const;
 | 
				
			||||||
 | 
						int32_t get_gpu_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void increment_frames_drawn();
 | 
				
			||||||
 | 
						bool notify_frame_server_synced();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Engine();
 | 
				
			||||||
 | 
						virtual ~Engine();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ENGINE_H
 | 
				
			||||||
							
								
								
									
										1593
									
								
								engine/core/config/project_settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1593
									
								
								engine/core/config/project_settings.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										248
									
								
								engine/core/config/project_settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								engine/core/config/project_settings.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,248 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  project_settings.h                                                    */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef PROJECT_SETTINGS_H
 | 
				
			||||||
 | 
					#define PROJECT_SETTINGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class TypedArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectSettings : public Object {
 | 
				
			||||||
 | 
						GDCLASS(ProjectSettings, Object);
 | 
				
			||||||
 | 
						_THREAD_SAFE_CLASS_
 | 
				
			||||||
 | 
						friend class TestProjectSettingsInternalsAccessor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_changed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						typedef HashMap<String, Variant> CustomMap;
 | 
				
			||||||
 | 
						static const String PROJECT_DATA_DIR_NAME_SUFFIX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum {
 | 
				
			||||||
 | 
							// Properties that are not for built in values begin from this value, so builtin ones are displayed first.
 | 
				
			||||||
 | 
							NO_BUILTIN_ORDER_BASE = 1 << 16
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						const static PackedStringArray get_required_features();
 | 
				
			||||||
 | 
						const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
 | 
				
			||||||
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct AutoloadInfo {
 | 
				
			||||||
 | 
							StringName name;
 | 
				
			||||||
 | 
							String path;
 | 
				
			||||||
 | 
							bool is_singleton = false;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						struct VariantContainer {
 | 
				
			||||||
 | 
							int order = 0;
 | 
				
			||||||
 | 
							bool persist = false;
 | 
				
			||||||
 | 
							bool basic = false;
 | 
				
			||||||
 | 
							bool internal = false;
 | 
				
			||||||
 | 
							Variant variant;
 | 
				
			||||||
 | 
							Variant initial;
 | 
				
			||||||
 | 
							bool hide_from_editor = false;
 | 
				
			||||||
 | 
							bool restart_if_changed = false;
 | 
				
			||||||
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
 | 
							bool ignore_value_in_docs = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VariantContainer() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VariantContainer(const Variant &p_variant, int p_order, bool p_persist = false) :
 | 
				
			||||||
 | 
									order(p_order),
 | 
				
			||||||
 | 
									persist(p_persist),
 | 
				
			||||||
 | 
									variant(p_variant) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int last_order = NO_BUILTIN_ORDER_BASE;
 | 
				
			||||||
 | 
						int last_builtin_order = 0;
 | 
				
			||||||
 | 
						uint64_t last_save_time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RBMap<StringName, VariantContainer> props; // NOTE: Key order is used e.g. in the save_custom method.
 | 
				
			||||||
 | 
						String resource_path;
 | 
				
			||||||
 | 
						HashMap<StringName, PropertyInfo> custom_prop_info;
 | 
				
			||||||
 | 
						bool using_datapack = false;
 | 
				
			||||||
 | 
						bool project_loaded = false;
 | 
				
			||||||
 | 
						List<String> input_presets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashSet<String> custom_features;
 | 
				
			||||||
 | 
						HashMap<StringName, LocalVector<Pair<StringName, StringName>>> feature_overrides;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LocalVector<String> hidden_prefixes;
 | 
				
			||||||
 | 
						HashMap<StringName, AutoloadInfo> autoloads;
 | 
				
			||||||
 | 
						HashMap<StringName, String> global_groups;
 | 
				
			||||||
 | 
						HashMap<StringName, HashSet<StringName>> scene_groups_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Array global_class_list;
 | 
				
			||||||
 | 
						bool is_global_class_list_loaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String project_data_dir_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _set(const StringName &p_name, const Variant &p_value);
 | 
				
			||||||
 | 
						bool _get(const StringName &p_name, Variant &r_ret) const;
 | 
				
			||||||
 | 
						void _get_property_list(List<PropertyInfo> *p_list) const;
 | 
				
			||||||
 | 
						bool _property_can_revert(const StringName &p_name) const;
 | 
				
			||||||
 | 
						bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _queue_changed();
 | 
				
			||||||
 | 
						void _emit_changed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ProjectSettings *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _load_settings_text(const String &p_path);
 | 
				
			||||||
 | 
						Error _load_settings_binary(const String &p_path);
 | 
				
			||||||
 | 
						Error _load_settings_text_or_binary(const String &p_text_path, const String &p_bin_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
 | 
				
			||||||
 | 
						Error _save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _save_custom_bnd(const String &p_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						const static PackedStringArray _get_supported_features();
 | 
				
			||||||
 | 
						const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
 | 
				
			||||||
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _convert_to_last_version(int p_from_version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _add_property_info_bind(const Dictionary &p_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _add_builtin_input_map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static const int CONFIG_VERSION = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_setting(const String &p_setting, const Variant &p_value);
 | 
				
			||||||
 | 
						Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
 | 
				
			||||||
 | 
						TypedArray<Dictionary> get_global_class_list();
 | 
				
			||||||
 | 
						void refresh_global_class_list();
 | 
				
			||||||
 | 
						void store_global_class_list(const Array &p_classes);
 | 
				
			||||||
 | 
						String get_global_class_list_path() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_setting(const String &p_var) const;
 | 
				
			||||||
 | 
						String localize_path(const String &p_path) const;
 | 
				
			||||||
 | 
						String globalize_path(const String &p_path) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_initial_value(const String &p_name, const Variant &p_value);
 | 
				
			||||||
 | 
						void set_as_basic(const String &p_name, bool p_basic);
 | 
				
			||||||
 | 
						void set_as_internal(const String &p_name, bool p_internal);
 | 
				
			||||||
 | 
						void set_restart_if_changed(const String &p_name, bool p_restart);
 | 
				
			||||||
 | 
						void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
 | 
				
			||||||
 | 
						bool get_ignore_value_in_docs(const String &p_name) const;
 | 
				
			||||||
 | 
						void add_hidden_prefix(const String &p_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_project_data_dir_name() const;
 | 
				
			||||||
 | 
						String get_project_data_path() const;
 | 
				
			||||||
 | 
						String get_resource_path() const;
 | 
				
			||||||
 | 
						String get_imported_files_path() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ProjectSettings *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clear(const String &p_name);
 | 
				
			||||||
 | 
						int get_order(const String &p_name) const;
 | 
				
			||||||
 | 
						void set_order(const String &p_name, int p_order);
 | 
				
			||||||
 | 
						void set_builtin_order(const String &p_name);
 | 
				
			||||||
 | 
						bool is_builtin_setting(const String &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error load_custom(const String &p_path);
 | 
				
			||||||
 | 
						Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true);
 | 
				
			||||||
 | 
						Error save();
 | 
				
			||||||
 | 
						void set_custom_property_info(const PropertyInfo &p_info);
 | 
				
			||||||
 | 
						const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
 | 
				
			||||||
 | 
						uint64_t get_last_saved_time() { return last_save_time; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<String> get_input_presets() const { return input_presets; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Variant get_setting_with_override(const StringName &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_using_datapack() const;
 | 
				
			||||||
 | 
						bool is_project_loaded() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_custom_feature(const String &p_feature) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const HashMap<StringName, AutoloadInfo> &get_autoload_list() const;
 | 
				
			||||||
 | 
						void add_autoload(const AutoloadInfo &p_autoload);
 | 
				
			||||||
 | 
						void remove_autoload(const StringName &p_autoload);
 | 
				
			||||||
 | 
						bool has_autoload(const StringName &p_autoload) const;
 | 
				
			||||||
 | 
						AutoloadInfo get_autoload(const StringName &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const HashMap<StringName, String> &get_global_groups_list() const;
 | 
				
			||||||
 | 
						void add_global_group(const StringName &p_name, const String &p_description);
 | 
				
			||||||
 | 
						void remove_global_group(const StringName &p_name);
 | 
				
			||||||
 | 
						bool has_global_group(const StringName &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const HashMap<StringName, HashSet<StringName>> &get_scene_groups_cache() const;
 | 
				
			||||||
 | 
						void add_scene_groups_cache(const StringName &p_path, const HashSet<StringName> &p_cache);
 | 
				
			||||||
 | 
						void remove_scene_groups_cache(const StringName &p_path);
 | 
				
			||||||
 | 
						void save_scene_groups_cache();
 | 
				
			||||||
 | 
						String get_scene_groups_cache_path() const;
 | 
				
			||||||
 | 
						void load_scene_groups_cache();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ProjectSettings();
 | 
				
			||||||
 | 
						ProjectSettings(const String &p_path);
 | 
				
			||||||
 | 
						~ProjectSettings();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Not a macro any longer.
 | 
				
			||||||
 | 
					Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
 | 
				
			||||||
 | 
					Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
 | 
				
			||||||
 | 
					#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true)
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // PROJECT_SETTINGS_H
 | 
				
			||||||
							
								
								
									
										2057
									
								
								engine/core/core_bind.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2057
									
								
								engine/core/core_bind.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										621
									
								
								engine/core/core_bind.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										621
									
								
								engine/core/core_bind.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,621 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_bind.h                                                           */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CORE_BIND_H
 | 
				
			||||||
 | 
					#define CORE_BIND_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/engine_profiler.h"
 | 
				
			||||||
 | 
					#include "core/io/image.h"
 | 
				
			||||||
 | 
					#include "core/io/resource_loader.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/thread.h"
 | 
				
			||||||
 | 
					#include "core/templates/safe_refcount.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MainLoop;
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class TypedArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace core_bind {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResourceLoader : public Object {
 | 
				
			||||||
 | 
						GDCLASS(ResourceLoader, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static ResourceLoader *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum ThreadLoadStatus {
 | 
				
			||||||
 | 
							THREAD_LOAD_INVALID_RESOURCE,
 | 
				
			||||||
 | 
							THREAD_LOAD_IN_PROGRESS,
 | 
				
			||||||
 | 
							THREAD_LOAD_FAILED,
 | 
				
			||||||
 | 
							THREAD_LOAD_LOADED
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum CacheMode {
 | 
				
			||||||
 | 
							CACHE_MODE_IGNORE,
 | 
				
			||||||
 | 
							CACHE_MODE_REUSE,
 | 
				
			||||||
 | 
							CACHE_MODE_REPLACE,
 | 
				
			||||||
 | 
							CACHE_MODE_IGNORE_DEEP,
 | 
				
			||||||
 | 
							CACHE_MODE_REPLACE_DEEP,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ResourceLoader *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, CacheMode p_cache_mode = CACHE_MODE_REUSE);
 | 
				
			||||||
 | 
						ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
 | 
				
			||||||
 | 
						Ref<Resource> load_threaded_get(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
 | 
				
			||||||
 | 
						Vector<String> get_recognized_extensions_for_type(const String &p_type);
 | 
				
			||||||
 | 
						void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front);
 | 
				
			||||||
 | 
						void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
 | 
				
			||||||
 | 
						void set_abort_on_missing_resources(bool p_abort);
 | 
				
			||||||
 | 
						PackedStringArray get_dependencies(const String &p_path);
 | 
				
			||||||
 | 
						bool has_cached(const String &p_path);
 | 
				
			||||||
 | 
						bool exists(const String &p_path, const String &p_type_hint = "");
 | 
				
			||||||
 | 
						ResourceUID::ID get_resource_uid(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ResourceLoader() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResourceSaver : public Object {
 | 
				
			||||||
 | 
						GDCLASS(ResourceSaver, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static ResourceSaver *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum SaverFlags {
 | 
				
			||||||
 | 
							FLAG_NONE = 0,
 | 
				
			||||||
 | 
							FLAG_RELATIVE_PATHS = 1,
 | 
				
			||||||
 | 
							FLAG_BUNDLE_RESOURCES = 2,
 | 
				
			||||||
 | 
							FLAG_CHANGE_PATH = 4,
 | 
				
			||||||
 | 
							FLAG_OMIT_EDITOR_PROPERTIES = 8,
 | 
				
			||||||
 | 
							FLAG_SAVE_BIG_ENDIAN = 16,
 | 
				
			||||||
 | 
							FLAG_COMPRESS = 32,
 | 
				
			||||||
 | 
							FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ResourceSaver *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags);
 | 
				
			||||||
 | 
						Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
 | 
				
			||||||
 | 
						void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
 | 
				
			||||||
 | 
						void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ResourceSaver() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OS : public Object {
 | 
				
			||||||
 | 
						GDCLASS(OS, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutable HashMap<String, bool> feature_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static OS *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum RenderingDriver {
 | 
				
			||||||
 | 
							RENDERING_DRIVER_VULKAN,
 | 
				
			||||||
 | 
							RENDERING_DRIVER_OPENGL3,
 | 
				
			||||||
 | 
							RENDERING_DRIVER_D3D12,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PackedByteArray get_entropy(int p_bytes);
 | 
				
			||||||
 | 
						String get_system_ca_certificates();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual PackedStringArray get_connected_midi_inputs();
 | 
				
			||||||
 | 
						virtual void open_midi_inputs();
 | 
				
			||||||
 | 
						virtual void close_midi_inputs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_low_processor_usage_mode(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_in_low_processor_usage_mode() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_low_processor_usage_mode_sleep_usec(int p_usec);
 | 
				
			||||||
 | 
						int get_low_processor_usage_mode_sleep_usec() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_delta_smoothing(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_delta_smoothing_enabled() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void alert(const String &p_alert, const String &p_title = "ALERT!");
 | 
				
			||||||
 | 
						void crash(const String &p_message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<String> get_system_fonts() const;
 | 
				
			||||||
 | 
						String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
 | 
				
			||||||
 | 
						Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
 | 
				
			||||||
 | 
						String get_executable_path() const;
 | 
				
			||||||
 | 
						String read_string_from_stdin();
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments);
 | 
				
			||||||
 | 
						int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
 | 
				
			||||||
 | 
						int create_instance(const Vector<String> &p_arguments);
 | 
				
			||||||
 | 
						Error kill(int p_pid);
 | 
				
			||||||
 | 
						Error shell_open(const String &p_uri);
 | 
				
			||||||
 | 
						Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_process_running(int p_pid) const;
 | 
				
			||||||
 | 
						int get_process_exit_code(int p_pid) const;
 | 
				
			||||||
 | 
						int get_process_id() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
 | 
				
			||||||
 | 
						bool is_restart_on_exit_set() const;
 | 
				
			||||||
 | 
						Vector<String> get_restart_on_exit_arguments() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_environment(const String &p_var) const;
 | 
				
			||||||
 | 
						String get_environment(const String &p_var) const;
 | 
				
			||||||
 | 
						void set_environment(const String &p_var, const String &p_value) const;
 | 
				
			||||||
 | 
						void unset_environment(const String &p_var) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_name() const;
 | 
				
			||||||
 | 
						String get_distribution_name() const;
 | 
				
			||||||
 | 
						String get_version() const;
 | 
				
			||||||
 | 
						Vector<String> get_cmdline_args();
 | 
				
			||||||
 | 
						Vector<String> get_cmdline_user_args();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<String> get_video_adapter_driver_info() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_locale() const;
 | 
				
			||||||
 | 
						String get_locale_language() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_model_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_debug_build() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_unique_id() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_keycode_string(Key p_code) const;
 | 
				
			||||||
 | 
						bool is_keycode_unicode(char32_t p_unicode) const;
 | 
				
			||||||
 | 
						Key find_keycode_from_string(const String &p_code) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_use_file_access_save_and_swap(bool p_enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t get_static_memory_usage() const;
 | 
				
			||||||
 | 
						uint64_t get_static_memory_peak_usage() const;
 | 
				
			||||||
 | 
						Dictionary get_memory_info() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void delay_usec(int p_usec) const;
 | 
				
			||||||
 | 
						void delay_msec(int p_msec) const;
 | 
				
			||||||
 | 
						uint64_t get_ticks_msec() const;
 | 
				
			||||||
 | 
						uint64_t get_ticks_usec() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_userfs_persistent() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_stdout_verbose() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int get_processor_count() const;
 | 
				
			||||||
 | 
						String get_processor_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum SystemDir {
 | 
				
			||||||
 | 
							SYSTEM_DIR_DESKTOP,
 | 
				
			||||||
 | 
							SYSTEM_DIR_DCIM,
 | 
				
			||||||
 | 
							SYSTEM_DIR_DOCUMENTS,
 | 
				
			||||||
 | 
							SYSTEM_DIR_DOWNLOADS,
 | 
				
			||||||
 | 
							SYSTEM_DIR_MOVIES,
 | 
				
			||||||
 | 
							SYSTEM_DIR_MUSIC,
 | 
				
			||||||
 | 
							SYSTEM_DIR_PICTURES,
 | 
				
			||||||
 | 
							SYSTEM_DIR_RINGTONES,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error move_to_trash(const String &p_path) const;
 | 
				
			||||||
 | 
						String get_user_data_dir() const;
 | 
				
			||||||
 | 
						String get_config_dir() const;
 | 
				
			||||||
 | 
						String get_data_dir() const;
 | 
				
			||||||
 | 
						String get_cache_dir() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error set_thread_name(const String &p_name);
 | 
				
			||||||
 | 
						::Thread::ID get_thread_caller_id() const;
 | 
				
			||||||
 | 
						::Thread::ID get_main_thread_id() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_feature(const String &p_feature) const;
 | 
				
			||||||
 | 
						bool is_sandboxed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool request_permission(const String &p_name);
 | 
				
			||||||
 | 
						bool request_permissions();
 | 
				
			||||||
 | 
						Vector<String> get_granted_permissions() const;
 | 
				
			||||||
 | 
						void revoke_granted_permissions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static OS *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OS() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Geometry2D : public Object {
 | 
				
			||||||
 | 
						GDCLASS(Geometry2D, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Geometry2D *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Geometry2D *get_singleton();
 | 
				
			||||||
 | 
						Variant segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b);
 | 
				
			||||||
 | 
						Variant line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b);
 | 
				
			||||||
 | 
						Vector<Vector2> get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2);
 | 
				
			||||||
 | 
						Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
 | 
				
			||||||
 | 
						Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
 | 
				
			||||||
 | 
						bool point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius);
 | 
				
			||||||
 | 
						real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_polygon_clockwise(const Vector<Vector2> &p_polygon);
 | 
				
			||||||
 | 
						bool is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon);
 | 
				
			||||||
 | 
						Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
 | 
				
			||||||
 | 
						Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
 | 
				
			||||||
 | 
						Vector<Point2> convex_hull(const Vector<Point2> &p_points);
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum PolyBooleanOperation {
 | 
				
			||||||
 | 
							OPERATION_UNION,
 | 
				
			||||||
 | 
							OPERATION_DIFFERENCE,
 | 
				
			||||||
 | 
							OPERATION_INTERSECTION,
 | 
				
			||||||
 | 
							OPERATION_XOR
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						// 2D polygon boolean operations.
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2D polyline vs polygon operations.
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2D offset polygons/polylines.
 | 
				
			||||||
 | 
						enum PolyJoinType {
 | 
				
			||||||
 | 
							JOIN_SQUARE,
 | 
				
			||||||
 | 
							JOIN_ROUND,
 | 
				
			||||||
 | 
							JOIN_MITER
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						enum PolyEndType {
 | 
				
			||||||
 | 
							END_POLYGON,
 | 
				
			||||||
 | 
							END_JOINED,
 | 
				
			||||||
 | 
							END_BUTT,
 | 
				
			||||||
 | 
							END_SQUARE,
 | 
				
			||||||
 | 
							END_ROUND
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
 | 
				
			||||||
 | 
						TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dictionary make_atlas(const Vector<Size2> &p_rects);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Geometry2D() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Geometry3D : public Object {
 | 
				
			||||||
 | 
						GDCLASS(Geometry3D, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Geometry3D *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Geometry3D *get_singleton();
 | 
				
			||||||
 | 
						Vector<Vector3> compute_convex_mesh_points(const TypedArray<Plane> &p_planes);
 | 
				
			||||||
 | 
						TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
 | 
				
			||||||
 | 
						TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
 | 
				
			||||||
 | 
						TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
 | 
				
			||||||
 | 
						Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
 | 
				
			||||||
 | 
						Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
 | 
				
			||||||
 | 
						Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
 | 
				
			||||||
 | 
						Vector3 get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
 | 
				
			||||||
 | 
						Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
 | 
				
			||||||
 | 
						Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
 | 
				
			||||||
 | 
						Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
 | 
				
			||||||
 | 
						Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
 | 
				
			||||||
 | 
						Vector<int32_t> tetrahedralize_delaunay(const Vector<Vector3> &p_points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Geometry3D() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Marshalls : public Object {
 | 
				
			||||||
 | 
						GDCLASS(Marshalls, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Marshalls *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Marshalls *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String variant_to_base64(const Variant &p_var, bool p_full_objects = false);
 | 
				
			||||||
 | 
						Variant base64_to_variant(const String &p_str, bool p_allow_objects = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String raw_to_base64(const Vector<uint8_t> &p_arr);
 | 
				
			||||||
 | 
						Vector<uint8_t> base64_to_raw(const String &p_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String utf8_to_base64(const String &p_str);
 | 
				
			||||||
 | 
						String base64_to_utf8(const String &p_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Marshalls() { singleton = this; }
 | 
				
			||||||
 | 
						~Marshalls() { singleton = nullptr; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Mutex : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(Mutex, RefCounted);
 | 
				
			||||||
 | 
						::Mutex mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void lock();
 | 
				
			||||||
 | 
						bool try_lock();
 | 
				
			||||||
 | 
						void unlock();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Semaphore : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(Semaphore, RefCounted);
 | 
				
			||||||
 | 
						::Semaphore semaphore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void wait();
 | 
				
			||||||
 | 
						bool try_wait();
 | 
				
			||||||
 | 
						void post();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Thread : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(Thread, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						Variant ret;
 | 
				
			||||||
 | 
						SafeFlag running;
 | 
				
			||||||
 | 
						Callable target_callable;
 | 
				
			||||||
 | 
						::Thread thread;
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static void _start_func(void *ud);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum Priority {
 | 
				
			||||||
 | 
							PRIORITY_LOW,
 | 
				
			||||||
 | 
							PRIORITY_NORMAL,
 | 
				
			||||||
 | 
							PRIORITY_HIGH,
 | 
				
			||||||
 | 
							PRIORITY_MAX
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error start(const Callable &p_callable, Priority p_priority = PRIORITY_NORMAL);
 | 
				
			||||||
 | 
						String get_id() const;
 | 
				
			||||||
 | 
						bool is_started() const;
 | 
				
			||||||
 | 
						bool is_alive() const;
 | 
				
			||||||
 | 
						Variant wait_to_finish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void set_thread_safety_checks_enabled(bool p_enabled);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace special {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClassDB : public Object {
 | 
				
			||||||
 | 
						GDCLASS(ClassDB, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						PackedStringArray get_class_list() const;
 | 
				
			||||||
 | 
						PackedStringArray get_inheriters_from_class(const StringName &p_class) const;
 | 
				
			||||||
 | 
						StringName get_parent_class(const StringName &p_class) const;
 | 
				
			||||||
 | 
						bool class_exists(const StringName &p_class) const;
 | 
				
			||||||
 | 
						bool is_parent_class(const StringName &p_class, const StringName &p_inherits) const;
 | 
				
			||||||
 | 
						bool can_instantiate(const StringName &p_class) const;
 | 
				
			||||||
 | 
						Variant instantiate(const StringName &p_class) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool class_has_signal(const StringName &p_class, const StringName &p_signal) const;
 | 
				
			||||||
 | 
						Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const;
 | 
				
			||||||
 | 
						TypedArray<Dictionary> class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
						Variant class_get_property(Object *p_object, const StringName &p_property) const;
 | 
				
			||||||
 | 
						Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
						bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
 | 
				
			||||||
 | 
						int64_t class_get_integer_constant(const StringName &p_class, const StringName &p_name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool class_has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
						PackedStringArray class_get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
						PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
						StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_class_enabled(const StringName &p_class) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB() {}
 | 
				
			||||||
 | 
						~ClassDB() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace special
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Engine : public Object {
 | 
				
			||||||
 | 
						GDCLASS(Engine, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static Engine *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Engine *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
						void set_physics_ticks_per_second(int p_ips);
 | 
				
			||||||
 | 
						int get_physics_ticks_per_second() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_max_physics_steps_per_frame(int p_max_physics_steps);
 | 
				
			||||||
 | 
						int get_max_physics_steps_per_frame() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_physics_jitter_fix(double p_threshold);
 | 
				
			||||||
 | 
						double get_physics_jitter_fix() const;
 | 
				
			||||||
 | 
						double get_physics_interpolation_fraction() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_max_fps(int p_fps);
 | 
				
			||||||
 | 
						int get_max_fps() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double get_frames_per_second() const;
 | 
				
			||||||
 | 
						uint64_t get_physics_frames() const;
 | 
				
			||||||
 | 
						uint64_t get_process_frames() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int get_frames_drawn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_time_scale(double p_scale);
 | 
				
			||||||
 | 
						double get_time_scale();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MainLoop *get_main_loop() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dictionary get_version_info() const;
 | 
				
			||||||
 | 
						Dictionary get_author_info() const;
 | 
				
			||||||
 | 
						TypedArray<Dictionary> get_copyright_info() const;
 | 
				
			||||||
 | 
						Dictionary get_donor_info() const;
 | 
				
			||||||
 | 
						Dictionary get_license_info() const;
 | 
				
			||||||
 | 
						String get_license_text() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_architecture_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_in_physics_frame() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_singleton(const StringName &p_name) const;
 | 
				
			||||||
 | 
						Object *get_singleton_object(const StringName &p_name) const;
 | 
				
			||||||
 | 
						void register_singleton(const StringName &p_name, Object *p_object);
 | 
				
			||||||
 | 
						void unregister_singleton(const StringName &p_name);
 | 
				
			||||||
 | 
						Vector<String> get_singleton_list() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error register_script_language(ScriptLanguage *p_language);
 | 
				
			||||||
 | 
						Error unregister_script_language(const ScriptLanguage *p_language);
 | 
				
			||||||
 | 
						int get_script_language_count();
 | 
				
			||||||
 | 
						ScriptLanguage *get_script_language(int p_index) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_editor_hint(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_editor_hint() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// `set_write_movie_path()` is not exposed to the scripting API as changing it at run-time has no effect.
 | 
				
			||||||
 | 
						String get_write_movie_path() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_print_error_messages(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_printing_error_messages() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Engine() { singleton = this; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EngineDebugger : public Object {
 | 
				
			||||||
 | 
						GDCLASS(EngineDebugger, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<StringName, Callable> captures;
 | 
				
			||||||
 | 
						HashMap<StringName, Ref<EngineProfiler>> profilers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static EngineDebugger *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static EngineDebugger *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_active();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler);
 | 
				
			||||||
 | 
						void unregister_profiler(const StringName &p_name);
 | 
				
			||||||
 | 
						bool is_profiling(const StringName &p_name);
 | 
				
			||||||
 | 
						bool has_profiler(const StringName &p_name);
 | 
				
			||||||
 | 
						void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
 | 
				
			||||||
 | 
						void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void register_message_capture(const StringName &p_name, const Callable &p_callable);
 | 
				
			||||||
 | 
						void unregister_message_capture(const StringName &p_name);
 | 
				
			||||||
 | 
						bool has_capture(const StringName &p_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void send_message(const String &p_msg, const Array &p_data);
 | 
				
			||||||
 | 
						void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
 | 
				
			||||||
 | 
						void script_debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void line_poll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_lines_left(int p_lines);
 | 
				
			||||||
 | 
						int get_lines_left() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_depth(int p_depth);
 | 
				
			||||||
 | 
						int get_depth() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_breakpoint(int p_line, const StringName &p_source) const;
 | 
				
			||||||
 | 
						bool is_skipping_breakpoints() const;
 | 
				
			||||||
 | 
						void insert_breakpoint(int p_line, const StringName &p_source);
 | 
				
			||||||
 | 
						void remove_breakpoint(int p_line, const StringName &p_source);
 | 
				
			||||||
 | 
						void clear_breakpoints();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EngineDebugger() { singleton = this; }
 | 
				
			||||||
 | 
						~EngineDebugger();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace core_bind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(core_bind::Thread::Priority);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CORE_BIND_H
 | 
				
			||||||
							
								
								
									
										315
									
								
								engine/core/core_builders.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								engine/core/core_builders.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,315 @@
 | 
				
			||||||
 | 
					"""Functions used to generate source files during build time"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def escape_string(s):
 | 
				
			||||||
 | 
					    def charcode_to_c_escapes(c):
 | 
				
			||||||
 | 
					        rev_result = []
 | 
				
			||||||
 | 
					        while c >= 256:
 | 
				
			||||||
 | 
					            c, low = (c // 256, c % 256)
 | 
				
			||||||
 | 
					            rev_result.append("\\%03o" % low)
 | 
				
			||||||
 | 
					        rev_result.append("\\%03o" % c)
 | 
				
			||||||
 | 
					        return "".join(reversed(rev_result))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    result = ""
 | 
				
			||||||
 | 
					    if isinstance(s, str):
 | 
				
			||||||
 | 
					        s = s.encode("utf-8")
 | 
				
			||||||
 | 
					    for c in s:
 | 
				
			||||||
 | 
					        if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
 | 
				
			||||||
 | 
					            result += charcode_to_c_escapes(c)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            result += chr(c)
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_certs_header(target, source, env):
 | 
				
			||||||
 | 
					    src = str(source[0])
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					    with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
 | 
				
			||||||
 | 
					        buf = f.read()
 | 
				
			||||||
 | 
					        decomp_size = len(buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Use maximum zlib compression level to further reduce file size
 | 
				
			||||||
 | 
					        # (at the cost of initial build times).
 | 
				
			||||||
 | 
					        buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
 | 
				
			||||||
 | 
					        g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
 | 
				
			||||||
 | 
					        g.write("#define CERTS_COMPRESSED_GEN_H\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # System certs path. Editor will use them if defined. (for package maintainers)
 | 
				
			||||||
 | 
					        path = env["system_certs_path"]
 | 
				
			||||||
 | 
					        g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
 | 
				
			||||||
 | 
					        if env["builtin_certs"]:
 | 
				
			||||||
 | 
					            # Defined here and not in env so changing it does not trigger a full rebuild.
 | 
				
			||||||
 | 
					            g.write("#define BUILTIN_CERTS_ENABLED\n")
 | 
				
			||||||
 | 
					            g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
 | 
				
			||||||
 | 
					            g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
 | 
				
			||||||
 | 
					            g.write("static const unsigned char _certs_compressed[] = {\n")
 | 
				
			||||||
 | 
					            for i in range(len(buf)):
 | 
				
			||||||
 | 
					                g.write("\t" + str(buf[i]) + ",\n")
 | 
				
			||||||
 | 
					            g.write("};\n")
 | 
				
			||||||
 | 
					        g.write("#endif // CERTS_COMPRESSED_GEN_H")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_authors_header(target, source, env):
 | 
				
			||||||
 | 
					    sections = [
 | 
				
			||||||
 | 
					        "Project Founders",
 | 
				
			||||||
 | 
					        "Lead Developer",
 | 
				
			||||||
 | 
					        "Project Manager",
 | 
				
			||||||
 | 
					        "Developers",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    sections_id = [
 | 
				
			||||||
 | 
					        "AUTHORS_FOUNDERS",
 | 
				
			||||||
 | 
					        "AUTHORS_LEAD_DEVELOPERS",
 | 
				
			||||||
 | 
					        "AUTHORS_PROJECT_MANAGERS",
 | 
				
			||||||
 | 
					        "AUTHORS_DEVELOPERS",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    src = str(source[0])
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					    with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
 | 
				
			||||||
 | 
					        g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
 | 
				
			||||||
 | 
					        g.write("#ifndef AUTHORS_GEN_H\n")
 | 
				
			||||||
 | 
					        g.write("#define AUTHORS_GEN_H\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reading = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def close_section():
 | 
				
			||||||
 | 
					            g.write("\t0\n")
 | 
				
			||||||
 | 
					            g.write("};\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for line in f:
 | 
				
			||||||
 | 
					            if reading:
 | 
				
			||||||
 | 
					                if line.startswith("    "):
 | 
				
			||||||
 | 
					                    g.write('\t"' + escape_string(line.strip()) + '",\n')
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					            if line.startswith("## "):
 | 
				
			||||||
 | 
					                if reading:
 | 
				
			||||||
 | 
					                    close_section()
 | 
				
			||||||
 | 
					                    reading = False
 | 
				
			||||||
 | 
					                for section, section_id in zip(sections, sections_id):
 | 
				
			||||||
 | 
					                    if line.strip().endswith(section):
 | 
				
			||||||
 | 
					                        current_section = escape_string(section_id)
 | 
				
			||||||
 | 
					                        reading = True
 | 
				
			||||||
 | 
					                        g.write("const char *const " + current_section + "[] = {\n")
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if reading:
 | 
				
			||||||
 | 
					            close_section()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("#endif // AUTHORS_GEN_H\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_donors_header(target, source, env):
 | 
				
			||||||
 | 
					    sections = [
 | 
				
			||||||
 | 
					        "Patrons",
 | 
				
			||||||
 | 
					        "Platinum sponsors",
 | 
				
			||||||
 | 
					        "Gold sponsors",
 | 
				
			||||||
 | 
					        "Silver sponsors",
 | 
				
			||||||
 | 
					        "Diamond members",
 | 
				
			||||||
 | 
					        "Titanium members",
 | 
				
			||||||
 | 
					        "Platinum members",
 | 
				
			||||||
 | 
					        "Gold members",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    sections_id = [
 | 
				
			||||||
 | 
					        "DONORS_PATRONS",
 | 
				
			||||||
 | 
					        "DONORS_SPONSORS_PLATINUM",
 | 
				
			||||||
 | 
					        "DONORS_SPONSORS_GOLD",
 | 
				
			||||||
 | 
					        "DONORS_SPONSORS_SILVER",
 | 
				
			||||||
 | 
					        "DONORS_MEMBERS_DIAMOND",
 | 
				
			||||||
 | 
					        "DONORS_MEMBERS_TITANIUM",
 | 
				
			||||||
 | 
					        "DONORS_MEMBERS_PLATINUM",
 | 
				
			||||||
 | 
					        "DONORS_MEMBERS_GOLD",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    src = str(source[0])
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					    with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
 | 
				
			||||||
 | 
					        g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
 | 
				
			||||||
 | 
					        g.write("#ifndef DONORS_GEN_H\n")
 | 
				
			||||||
 | 
					        g.write("#define DONORS_GEN_H\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reading = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def close_section():
 | 
				
			||||||
 | 
					            g.write("\t0\n")
 | 
				
			||||||
 | 
					            g.write("};\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for line in f:
 | 
				
			||||||
 | 
					            if reading >= 0:
 | 
				
			||||||
 | 
					                if line.startswith("    "):
 | 
				
			||||||
 | 
					                    g.write('\t"' + escape_string(line.strip()) + '",\n')
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					            if line.startswith("## "):
 | 
				
			||||||
 | 
					                if reading:
 | 
				
			||||||
 | 
					                    close_section()
 | 
				
			||||||
 | 
					                    reading = False
 | 
				
			||||||
 | 
					                for section, section_id in zip(sections, sections_id):
 | 
				
			||||||
 | 
					                    if line.strip().endswith(section):
 | 
				
			||||||
 | 
					                        current_section = escape_string(section_id)
 | 
				
			||||||
 | 
					                        reading = True
 | 
				
			||||||
 | 
					                        g.write("const char *const " + current_section + "[] = {\n")
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if reading:
 | 
				
			||||||
 | 
					            close_section()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("#endif // DONORS_GEN_H\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_license_header(target, source, env):
 | 
				
			||||||
 | 
					    src_copyright = str(source[0])
 | 
				
			||||||
 | 
					    src_license = str(source[1])
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class LicenseReader:
 | 
				
			||||||
 | 
					        def __init__(self, license_file):
 | 
				
			||||||
 | 
					            self._license_file = license_file
 | 
				
			||||||
 | 
					            self.line_num = 0
 | 
				
			||||||
 | 
					            self.current = self.next_line()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def next_line(self):
 | 
				
			||||||
 | 
					            line = self._license_file.readline()
 | 
				
			||||||
 | 
					            self.line_num += 1
 | 
				
			||||||
 | 
					            while line.startswith("#"):
 | 
				
			||||||
 | 
					                line = self._license_file.readline()
 | 
				
			||||||
 | 
					                self.line_num += 1
 | 
				
			||||||
 | 
					            self.current = line
 | 
				
			||||||
 | 
					            return line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def next_tag(self):
 | 
				
			||||||
 | 
					            if ":" not in self.current:
 | 
				
			||||||
 | 
					                return ("", [])
 | 
				
			||||||
 | 
					            tag, line = self.current.split(":", 1)
 | 
				
			||||||
 | 
					            lines = [line.strip()]
 | 
				
			||||||
 | 
					            while self.next_line() and self.current.startswith(" "):
 | 
				
			||||||
 | 
					                lines.append(self.current.strip())
 | 
				
			||||||
 | 
					            return (tag, lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from collections import OrderedDict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    projects: dict = OrderedDict()
 | 
				
			||||||
 | 
					    license_list = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(src_copyright, "r", encoding="utf-8") as copyright_file:
 | 
				
			||||||
 | 
					        reader = LicenseReader(copyright_file)
 | 
				
			||||||
 | 
					        part = {}
 | 
				
			||||||
 | 
					        while reader.current:
 | 
				
			||||||
 | 
					            tag, content = reader.next_tag()
 | 
				
			||||||
 | 
					            if tag in ("Files", "Copyright", "License"):
 | 
				
			||||||
 | 
					                part[tag] = content[:]
 | 
				
			||||||
 | 
					            elif tag == "Comment":
 | 
				
			||||||
 | 
					                # attach part to named project
 | 
				
			||||||
 | 
					                projects[content[0]] = projects.get(content[0], []) + [part]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if not tag or not reader.current:
 | 
				
			||||||
 | 
					                # end of a paragraph start a new part
 | 
				
			||||||
 | 
					                if "License" in part and "Files" not in part:
 | 
				
			||||||
 | 
					                    # no Files tag in this one, so assume standalone license
 | 
				
			||||||
 | 
					                    license_list.append(part["License"])
 | 
				
			||||||
 | 
					                part = {}
 | 
				
			||||||
 | 
					                reader.next_line()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data_list: list = []
 | 
				
			||||||
 | 
					    for project in iter(projects.values()):
 | 
				
			||||||
 | 
					        for part in project:
 | 
				
			||||||
 | 
					            part["file_index"] = len(data_list)
 | 
				
			||||||
 | 
					            data_list += part["Files"]
 | 
				
			||||||
 | 
					            part["copyright_index"] = len(data_list)
 | 
				
			||||||
 | 
					            data_list += part["Copyright"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(dst, "w", encoding="utf-8", newline="\n") as f:
 | 
				
			||||||
 | 
					        f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
 | 
				
			||||||
 | 
					        f.write("#ifndef LICENSE_GEN_H\n")
 | 
				
			||||||
 | 
					        f.write("#define LICENSE_GEN_H\n")
 | 
				
			||||||
 | 
					        f.write("const char *const GODOT_LICENSE_TEXT =")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with open(src_license, "r", encoding="utf-8") as license_file:
 | 
				
			||||||
 | 
					            for line in license_file:
 | 
				
			||||||
 | 
					                escaped_string = escape_string(line.strip())
 | 
				
			||||||
 | 
					                f.write('\n\t\t"' + escaped_string + '\\n"')
 | 
				
			||||||
 | 
					        f.write(";\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write(
 | 
				
			||||||
 | 
					            "struct ComponentCopyrightPart {\n"
 | 
				
			||||||
 | 
					            "\tconst char *license;\n"
 | 
				
			||||||
 | 
					            "\tconst char *const *files;\n"
 | 
				
			||||||
 | 
					            "\tconst char *const *copyright_statements;\n"
 | 
				
			||||||
 | 
					            "\tint file_count;\n"
 | 
				
			||||||
 | 
					            "\tint copyright_count;\n"
 | 
				
			||||||
 | 
					            "};\n\n"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write(
 | 
				
			||||||
 | 
					            "struct ComponentCopyright {\n"
 | 
				
			||||||
 | 
					            "\tconst char *name;\n"
 | 
				
			||||||
 | 
					            "\tconst ComponentCopyrightPart *parts;\n"
 | 
				
			||||||
 | 
					            "\tint part_count;\n"
 | 
				
			||||||
 | 
					            "};\n\n"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
 | 
				
			||||||
 | 
					        for line in data_list:
 | 
				
			||||||
 | 
					            f.write('\t"' + escape_string(line) + '",\n')
 | 
				
			||||||
 | 
					        f.write("};\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
 | 
				
			||||||
 | 
					        part_index = 0
 | 
				
			||||||
 | 
					        part_indexes = {}
 | 
				
			||||||
 | 
					        for project_name, project in iter(projects.items()):
 | 
				
			||||||
 | 
					            part_indexes[project_name] = part_index
 | 
				
			||||||
 | 
					            for part in project:
 | 
				
			||||||
 | 
					                f.write(
 | 
				
			||||||
 | 
					                    '\t{ "'
 | 
				
			||||||
 | 
					                    + escape_string(part["License"][0])
 | 
				
			||||||
 | 
					                    + '", '
 | 
				
			||||||
 | 
					                    + "©RIGHT_INFO_DATA["
 | 
				
			||||||
 | 
					                    + str(part["file_index"])
 | 
				
			||||||
 | 
					                    + "], "
 | 
				
			||||||
 | 
					                    + "©RIGHT_INFO_DATA["
 | 
				
			||||||
 | 
					                    + str(part["copyright_index"])
 | 
				
			||||||
 | 
					                    + "], "
 | 
				
			||||||
 | 
					                    + str(len(part["Files"]))
 | 
				
			||||||
 | 
					                    + ", "
 | 
				
			||||||
 | 
					                    + str(len(part["Copyright"]))
 | 
				
			||||||
 | 
					                    + " },\n"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                part_index += 1
 | 
				
			||||||
 | 
					        f.write("};\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n")
 | 
				
			||||||
 | 
					        for project_name, project in iter(projects.items()):
 | 
				
			||||||
 | 
					            f.write(
 | 
				
			||||||
 | 
					                '\t{ "'
 | 
				
			||||||
 | 
					                + escape_string(project_name)
 | 
				
			||||||
 | 
					                + '", '
 | 
				
			||||||
 | 
					                + "©RIGHT_PROJECT_PARTS["
 | 
				
			||||||
 | 
					                + str(part_indexes[project_name])
 | 
				
			||||||
 | 
					                + "], "
 | 
				
			||||||
 | 
					                + str(len(project))
 | 
				
			||||||
 | 
					                + " },\n"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        f.write("};\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const char *const LICENSE_NAMES[] = {\n")
 | 
				
			||||||
 | 
					        for license in license_list:
 | 
				
			||||||
 | 
					            f.write('\t"' + escape_string(license[0]) + '",\n')
 | 
				
			||||||
 | 
					        f.write("};\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("const char *const LICENSE_BODIES[] = {\n\n")
 | 
				
			||||||
 | 
					        for license in license_list:
 | 
				
			||||||
 | 
					            for line in license[1:]:
 | 
				
			||||||
 | 
					                if line == ".":
 | 
				
			||||||
 | 
					                    f.write('\t"\\n"\n')
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    f.write('\t"' + escape_string(line) + '\\n"\n')
 | 
				
			||||||
 | 
					            f.write('\t"",\n\n')
 | 
				
			||||||
 | 
					        f.write("};\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        f.write("#endif // LICENSE_GEN_H\n")
 | 
				
			||||||
							
								
								
									
										859
									
								
								engine/core/core_constants.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										859
									
								
								engine/core/core_constants.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,859 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_constants.cpp                                                    */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/input_event.h"
 | 
				
			||||||
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _CoreConstant {
 | 
				
			||||||
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
 | 
						bool ignore_value_in_docs = false;
 | 
				
			||||||
 | 
						bool is_bitfield = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						StringName enum_name;
 | 
				
			||||||
 | 
						const char *name = nullptr;
 | 
				
			||||||
 | 
						int64_t value = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_CoreConstant() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
 | 
						_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value, bool p_ignore_value_in_docs = false, bool p_is_bitfield = false) :
 | 
				
			||||||
 | 
								ignore_value_in_docs(p_ignore_value_in_docs),
 | 
				
			||||||
 | 
								is_bitfield(p_is_bitfield),
 | 
				
			||||||
 | 
								enum_name(p_enum_name),
 | 
				
			||||||
 | 
								name(p_name),
 | 
				
			||||||
 | 
								value(p_value) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value) :
 | 
				
			||||||
 | 
								enum_name(p_enum_name),
 | 
				
			||||||
 | 
								name(p_name),
 | 
				
			||||||
 | 
								value(p_value) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Vector<_CoreConstant> _global_constants;
 | 
				
			||||||
 | 
					static HashMap<StringName, int> _global_constants_map;
 | 
				
			||||||
 | 
					static HashMap<StringName, Vector<_CoreConstant>> _global_enums;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_CONSTANT(m_constant)                                                 \
 | 
				
			||||||
 | 
						_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
 | 
				
			||||||
 | 
						_global_constants_map[#m_constant] = _global_constants.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT(m_constant)                                                          \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant));              \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_FLAG(m_constant)                                                          \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant);                \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, false, true)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This just binds enum classes as if they were regular enum constants.
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member)                                                  \
 | 
				
			||||||
 | 
						{                                                                                                              \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member);                \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                             \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);               \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member)                                                               \
 | 
				
			||||||
 | 
						{                                                                                                                           \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member);                         \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, false, true)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                                          \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);                            \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member)                               \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name);                  \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member));   \
 | 
				
			||||||
 | 
							_global_constants_map[#m_name] = _global_constants.size() - 1;                               \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member)                                          \
 | 
				
			||||||
 | 
						{                                                                                                           \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name);                         \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member, false, true)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_name] = _global_constants.size() - 1;                                          \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);            \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member)                                                 \
 | 
				
			||||||
 | 
						{                                                                                                                    \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member);                      \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                                   \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);                     \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant)                                    \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant));            \
 | 
				
			||||||
 | 
							_global_constants_map[m_custom_name] = _global_constants.size() - 1;                         \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_CONSTANT_NO_VAL(m_constant)                                                \
 | 
				
			||||||
 | 
						_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant, true)); \
 | 
				
			||||||
 | 
						_global_constants_map[#m_constant] = _global_constants.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant)                                                   \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, true));        \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant)                             \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant, true));      \
 | 
				
			||||||
 | 
							_global_constants_map[m_custom_name] = _global_constants.size() - 1;                         \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_CONSTANT(m_constant)                                                 \
 | 
				
			||||||
 | 
						_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
 | 
				
			||||||
 | 
						_global_constants_map[#m_constant] = _global_constants.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT(m_constant)                                                          \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant));              \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_FLAG(m_constant)                                                          \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant);                \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant));              \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This just binds enum classes as if they were regular enum constants.
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member)                                                  \
 | 
				
			||||||
 | 
						{                                                                                                              \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member);                \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                             \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);               \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member)                                                  \
 | 
				
			||||||
 | 
						{                                                                                                              \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member);            \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                             \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);               \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member)                               \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name);                  \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member));   \
 | 
				
			||||||
 | 
							_global_constants_map[#m_name] = _global_constants.size() - 1;                               \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member)                               \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name);              \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member));   \
 | 
				
			||||||
 | 
							_global_constants_map[#m_name] = _global_constants.size() - 1;                               \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member)                                           \
 | 
				
			||||||
 | 
						{                                                                                                              \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member);                \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
 | 
				
			||||||
 | 
							_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1;                             \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]);               \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant)                                    \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant));            \
 | 
				
			||||||
 | 
							_global_constants_map[m_custom_name] = _global_constants.size() - 1;                         \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_CONSTANT_NO_VAL(m_constant)                                          \
 | 
				
			||||||
 | 
						_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
 | 
				
			||||||
 | 
						_global_constants_map[#m_constant] = _global_constants.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant)                                                   \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant));              \
 | 
				
			||||||
 | 
							_global_constants_map[#m_constant] = _global_constants.size() - 1;                           \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant)                             \
 | 
				
			||||||
 | 
						{                                                                                                \
 | 
				
			||||||
 | 
							StringName enum_name = __constant_get_enum_name(m_constant, #m_constant);                    \
 | 
				
			||||||
 | 
							_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant));            \
 | 
				
			||||||
 | 
							_global_constants_map[m_custom_name] = _global_constants.size() - 1;                         \
 | 
				
			||||||
 | 
							_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void register_global_constants() {
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(SIDE_TOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(SIDE_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(SIDE_BOTTOM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(CORNER_TOP_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(CORNER_TOP_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(VERTICAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(CLOCKWISE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(COUNTERCLOCKWISE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_CENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_FILL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_TOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_CENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_BOTTOM);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_FILL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP_TO);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER_TO);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BASELINE_TO);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM_TO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_TOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_CENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BASELINE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BOTTOM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XYZ);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XZY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YXZ);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YZX);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZXY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZYX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TAB);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKTAB);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSPACE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ENTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, INSERT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_DELETE, KEY_DELETE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAUSE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PRINT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SYSREQ);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CLEAR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOME);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, END);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEUP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEDOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SHIFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CTRL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, META);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ALT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CAPSLOCK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMLOCK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SCROLLLOCK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F5);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F6);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F7);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F8);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F9);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F10);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F11);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F12);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F13);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F14);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F15);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F16);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F17);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F18);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F19);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F20);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F21);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F22);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F23);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F24);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F25);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F26);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F27);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F28);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F29);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F30);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F31);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F32);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F33);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F34);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F35);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_MULTIPLY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_DIVIDE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_SUBTRACT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_PERIOD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ADD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_0);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_5);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_6);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_7);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_8);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_9);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MENU);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HELP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FORWARD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, REFRESH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEDOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEMUTE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEUP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPLAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIASTOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPREVIOUS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIANEXT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIARECORD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOMEPAGE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FAVORITES);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEARCH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STANDBY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OPENURL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMAIL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMEDIA);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH0);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH5);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH6);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH7);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH8);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH9);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHA);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHB);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHC);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHF);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNKNOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPACE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EXCLAM);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTEDBL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMBERSIGN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOLLAR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERCENT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AMPERSAND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, APOSTROPHE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENLEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENRIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASTERISK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PLUS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COMMA);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MINUS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERIOD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SLASH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_0, KEY_0);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_1, KEY_1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_2, KEY_2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_3, KEY_3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_4, KEY_4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_5, KEY_5);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_6, KEY_6);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_7, KEY_7);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_8, KEY_8);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_9, KEY_9);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COLON);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEMICOLON);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LESS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EQUAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GREATER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUESTION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, A);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, B);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, C);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, D);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, E);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, G);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, H);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, I);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, J);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, K);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, L);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, M);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, N);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, O);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, P);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Q);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, R);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, S);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, T);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, U);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, V);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, W);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, X);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Y);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Z);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETLEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSLASH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETRIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIICIRCUM);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNDERSCORE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTELEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACELEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BAR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACERIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIITILDE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YEN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SECTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CMD_OR_CTRL);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, SHIFT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, ALT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, META);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CTRL);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, KPAD);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, UNSPECIFIED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, RIGHT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, MIDDLE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_UP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_DOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON1, MB_XBUTTON1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON2, MB_XBUTTON2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MIDDLE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON1);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, INVALID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, A);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, B);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, X);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, Y);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, BACK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, GUIDE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, START);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_STICK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_STICK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_SHOULDER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_SHOULDER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_UP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_DOWN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE1);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, TOUCHPAD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, SDL_MAX);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, INVALID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_X);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_Y);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_X);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_Y);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, SDL_MAX);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NONE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_OFF);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_ON);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, AFTERTOUCH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTROL_CHANGE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PROGRAM_CHANGE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CHANNEL_PRESSURE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PITCH_BEND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_EXCLUSIVE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, QUARTER_FRAME);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_POSITION_POINTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_SELECT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TUNE_REQUEST);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TIMING_CLOCK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, START);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTINUE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, STOP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, ACTIVE_SENSING);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_RESET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// error list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(OK); // (0)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(FAILED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_UNAVAILABLE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_UNCONFIGURED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_UNAUTHORIZED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_PARAMETER_RANGE_ERROR); // (5)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_OUT_OF_MEMORY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_NOT_FOUND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_DRIVE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_PATH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_NO_PERMISSION); // (10)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_ALREADY_IN_USE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_OPEN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_WRITE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_READ);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_UNRECOGNIZED); // (15)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_CORRUPT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_MISSING_DEPENDENCIES);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_FILE_EOF);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_OPEN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_CREATE); // (20)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_QUERY_FAILED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_IN_USE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_LOCKED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_TIMEOUT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_CONNECT); // (25)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_RESOLVE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CONNECTION_ERROR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_ACQUIRE_RESOURCE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CANT_FORK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DATA); // (30)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_EXISTS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_DOES_NOT_EXIST);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_READ);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_WRITE); // (35)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_COMPILATION_FAILED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_METHOD_NOT_FOUND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_LINK_FAILED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_SCRIPT_FAILED);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_CYCLIC_LINK); // (40)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DECLARATION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_DUPLICATE_SYMBOL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_PARSE_ERROR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_BUSY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_SKIP); // (45)
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_HELP);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_BUG);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(ERR_PRINTER_ON_FIRE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LINK);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_NAVIGATION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_NAVIGATION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_AVOIDANCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_FILE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_SAVE_FILE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORAGE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_INTERNAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKABLE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKED);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_GROUP);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CATEGORY);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SUBGROUP);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_BITFIELD);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_INSTANCE_STATE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESTART_IF_CHANGED);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_VARIABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORE_IF_NULL);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_ENUM);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NIL_IS_VARIANT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ALWAYS_DUPLICATE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NEVER_DUPLICATE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_HIGH_END_GFX);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_KEYING_INCREMENTS);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFERRED_SET_RESOURCE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_BASIC_SETTING);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_READ_ONLY);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SECRET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFAULT);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_EDITOR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_NORMAL);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_EDITOR);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_CONST);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VARARG);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_STATIC);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_OBJECT_CORE);
 | 
				
			||||||
 | 
						BIND_CORE_BITFIELD_FLAG(METHOD_FLAGS_DEFAULT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT", Variant::FLOAT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING", Variant::STRING);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2", Variant::VECTOR2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2I", Variant::VECTOR2I);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2", Variant::RECT2);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2I", Variant::RECT2I);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3", Variant::VECTOR3);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4", Variant::VECTOR4);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4I", Variant::VECTOR4I);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PROJECTION", Variant::PROJECTION);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::RID);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_BYTE_ARRAY", Variant::PACKED_BYTE_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT32_ARRAY", Variant::PACKED_INT32_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT64_ARRAY", Variant::PACKED_INT64_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT32_ARRAY", Variant::PACKED_FLOAT32_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT64_ARRAY", Variant::PACKED_FLOAT64_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_STRING_ARRAY", Variant::PACKED_STRING_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR2_ARRAY", Variant::PACKED_VECTOR2_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR3_ARRAY", Variant::PACKED_VECTOR3_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_COLOR_ARRAY", Variant::PACKED_COLOR_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR4_ARRAY", Variant::PACKED_VECTOR4_ARRAY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//comparison
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
 | 
				
			||||||
 | 
						//mathematic
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POWER", Variant::OP_POWER);
 | 
				
			||||||
 | 
						//bitwise
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
 | 
				
			||||||
 | 
						//logic
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
 | 
				
			||||||
 | 
						//containment
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
 | 
				
			||||||
 | 
						BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void unregister_global_constants() {
 | 
				
			||||||
 | 
						_global_constants.clear();
 | 
				
			||||||
 | 
						_global_constants_map.clear();
 | 
				
			||||||
 | 
						_global_enums.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int CoreConstants::get_global_constant_count() {
 | 
				
			||||||
 | 
						return _global_constants.size();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StringName CoreConstants::get_global_constant_enum(int p_idx) {
 | 
				
			||||||
 | 
						return _global_constants[p_idx].enum_name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
 | 
					bool CoreConstants::is_global_constant_bitfield(int p_idx) {
 | 
				
			||||||
 | 
						return _global_constants[p_idx].is_bitfield;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
 | 
				
			||||||
 | 
						return _global_constants[p_idx].ignore_value_in_docs;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					bool CoreConstants::is_global_constant_bitfield(int p_idx) {
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *CoreConstants::get_global_constant_name(int p_idx) {
 | 
				
			||||||
 | 
						return _global_constants[p_idx].name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int64_t CoreConstants::get_global_constant_value(int p_idx) {
 | 
				
			||||||
 | 
						return _global_constants[p_idx].value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoreConstants::is_global_constant(const StringName &p_name) {
 | 
				
			||||||
 | 
						return _global_constants_map.has(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int CoreConstants::get_global_constant_index(const StringName &p_name) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!_global_constants_map.has(p_name), -1, "Trying to get index of non-existing constant.");
 | 
				
			||||||
 | 
						return _global_constants_map[p_name];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoreConstants::is_global_enum(const StringName &p_enum) {
 | 
				
			||||||
 | 
						return _global_enums.has(p_enum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoreConstants::get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values) {
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_MSG(p_values, "Trying to get enum values with null map.");
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!_global_enums.has(p_enum), "Trying to get values of non-existing enum.");
 | 
				
			||||||
 | 
						for (const _CoreConstant &constant : _global_enums[p_enum]) {
 | 
				
			||||||
 | 
							(*p_values)[constant.name] = constant.value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								engine/core/core_constants.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								engine/core/core_constants.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_constants.h                                                      */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CORE_CONSTANTS_H
 | 
				
			||||||
 | 
					#define CORE_CONSTANTS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CoreConstants {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static int get_global_constant_count();
 | 
				
			||||||
 | 
						static StringName get_global_constant_enum(int p_idx);
 | 
				
			||||||
 | 
						static bool is_global_constant_bitfield(int p_idx);
 | 
				
			||||||
 | 
						static bool get_ignore_value_in_docs(int p_idx);
 | 
				
			||||||
 | 
						static const char *get_global_constant_name(int p_idx);
 | 
				
			||||||
 | 
						static int64_t get_global_constant_value(int p_idx);
 | 
				
			||||||
 | 
						static bool is_global_constant(const StringName &p_name);
 | 
				
			||||||
 | 
						static int get_global_constant_index(const StringName &p_name);
 | 
				
			||||||
 | 
						static bool is_global_enum(const StringName &p_enum);
 | 
				
			||||||
 | 
						static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CORE_CONSTANTS_H
 | 
				
			||||||
							
								
								
									
										35
									
								
								engine/core/core_globals.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								engine/core/core_globals.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_globals.cpp                                                      */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core_globals.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoreGlobals::leak_reporting_enabled = true;
 | 
				
			||||||
 | 
					bool CoreGlobals::print_line_enabled = true;
 | 
				
			||||||
 | 
					bool CoreGlobals::print_error_enabled = true;
 | 
				
			||||||
							
								
								
									
										44
									
								
								engine/core/core_globals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								engine/core/core_globals.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_globals.h                                                        */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CORE_GLOBALS_H
 | 
				
			||||||
 | 
					#define CORE_GLOBALS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Home for state needed from global functions
 | 
				
			||||||
 | 
					// that cannot be stored in Engine or OS due to e.g. circular includes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CoreGlobals {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static bool leak_reporting_enabled;
 | 
				
			||||||
 | 
						static bool print_line_enabled;
 | 
				
			||||||
 | 
						static bool print_error_enabled;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CORE_GLOBALS_H
 | 
				
			||||||
							
								
								
									
										75
									
								
								engine/core/core_string_names.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								engine/core/core_string_names.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,75 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_string_names.cpp                                                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core_string_names.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CoreStringNames *CoreStringNames::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CoreStringNames::CoreStringNames() :
 | 
				
			||||||
 | 
							free_(StaticCString::create("free")),
 | 
				
			||||||
 | 
							changed(StaticCString::create("changed")),
 | 
				
			||||||
 | 
							script(StaticCString::create("script")),
 | 
				
			||||||
 | 
							script_changed(StaticCString::create("script_changed")),
 | 
				
			||||||
 | 
							_iter_init(StaticCString::create("_iter_init")),
 | 
				
			||||||
 | 
							_iter_next(StaticCString::create("_iter_next")),
 | 
				
			||||||
 | 
							_iter_get(StaticCString::create("_iter_get")),
 | 
				
			||||||
 | 
							get_rid(StaticCString::create("get_rid")),
 | 
				
			||||||
 | 
							_to_string(StaticCString::create("_to_string")),
 | 
				
			||||||
 | 
							_custom_features(StaticCString::create("_custom_features")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							x(StaticCString::create("x")),
 | 
				
			||||||
 | 
							y(StaticCString::create("y")),
 | 
				
			||||||
 | 
							z(StaticCString::create("z")),
 | 
				
			||||||
 | 
							w(StaticCString::create("w")),
 | 
				
			||||||
 | 
							r(StaticCString::create("r")),
 | 
				
			||||||
 | 
							g(StaticCString::create("g")),
 | 
				
			||||||
 | 
							b(StaticCString::create("b")),
 | 
				
			||||||
 | 
							a(StaticCString::create("a")),
 | 
				
			||||||
 | 
							position(StaticCString::create("position")),
 | 
				
			||||||
 | 
							size(StaticCString::create("size")),
 | 
				
			||||||
 | 
							end(StaticCString::create("end")),
 | 
				
			||||||
 | 
							basis(StaticCString::create("basis")),
 | 
				
			||||||
 | 
							origin(StaticCString::create("origin")),
 | 
				
			||||||
 | 
							normal(StaticCString::create("normal")),
 | 
				
			||||||
 | 
							d(StaticCString::create("d")),
 | 
				
			||||||
 | 
							h(StaticCString::create("h")),
 | 
				
			||||||
 | 
							s(StaticCString::create("s")),
 | 
				
			||||||
 | 
							v(StaticCString::create("v")),
 | 
				
			||||||
 | 
							r8(StaticCString::create("r8")),
 | 
				
			||||||
 | 
							g8(StaticCString::create("g8")),
 | 
				
			||||||
 | 
							b8(StaticCString::create("b8")),
 | 
				
			||||||
 | 
							a8(StaticCString::create("a8")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							call(StaticCString::create("call")),
 | 
				
			||||||
 | 
							call_deferred(StaticCString::create("call_deferred")),
 | 
				
			||||||
 | 
							bind(StaticCString::create("bind")),
 | 
				
			||||||
 | 
							notification(StaticCString::create("notification")),
 | 
				
			||||||
 | 
							property_list_changed(StaticCString::create("property_list_changed")) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								engine/core/core_string_names.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								engine/core/core_string_names.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  core_string_names.h                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CORE_STRING_NAMES_H
 | 
				
			||||||
 | 
					#define CORE_STRING_NAMES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CoreStringNames {
 | 
				
			||||||
 | 
						friend void register_core_types();
 | 
				
			||||||
 | 
						friend void unregister_core_types();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void create() { singleton = memnew(CoreStringNames); }
 | 
				
			||||||
 | 
						static void free() {
 | 
				
			||||||
 | 
							memdelete(singleton);
 | 
				
			||||||
 | 
							singleton = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CoreStringNames();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						_FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static CoreStringNames *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						StringName free_; // "free", conflict with C++ keyword.
 | 
				
			||||||
 | 
						StringName changed;
 | 
				
			||||||
 | 
						StringName script;
 | 
				
			||||||
 | 
						StringName script_changed;
 | 
				
			||||||
 | 
						StringName _iter_init;
 | 
				
			||||||
 | 
						StringName _iter_next;
 | 
				
			||||||
 | 
						StringName _iter_get;
 | 
				
			||||||
 | 
						StringName get_rid;
 | 
				
			||||||
 | 
						StringName _to_string;
 | 
				
			||||||
 | 
						StringName _custom_features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						StringName x;
 | 
				
			||||||
 | 
						StringName y;
 | 
				
			||||||
 | 
						StringName z;
 | 
				
			||||||
 | 
						StringName w;
 | 
				
			||||||
 | 
						StringName r;
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CORE_STRING_NAMES_H
 | 
				
			||||||
							
								
								
									
										64
									
								
								engine/core/crypto/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								engine/core/crypto/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_crypto = env.Clone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is_builtin = env["builtin_mbedtls"]
 | 
				
			||||||
 | 
					has_module = env["module_mbedtls_enabled"]
 | 
				
			||||||
 | 
					thirdparty_obj = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if is_builtin or not has_module:
 | 
				
			||||||
 | 
					    # Use our headers for builtin or if the module is not going to be compiled.
 | 
				
			||||||
 | 
					    # We decided not to depend on system mbedtls just for these few files that can
 | 
				
			||||||
 | 
					    # be easily extracted.
 | 
				
			||||||
 | 
					    env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MbedTLS core functions (for CryptoCore).
 | 
				
			||||||
 | 
					# If the mbedtls module is compiled we don't need to add the .c files with our
 | 
				
			||||||
 | 
					# custom config since they will be built by the module itself.
 | 
				
			||||||
 | 
					# Only if the module is not enabled, we must compile here the required sources
 | 
				
			||||||
 | 
					# to make a "light" build with only the necessary mbedtls files.
 | 
				
			||||||
 | 
					if not has_module:
 | 
				
			||||||
 | 
					    # Minimal mbedTLS config file
 | 
				
			||||||
 | 
					    config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
 | 
				
			||||||
 | 
					    config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
 | 
				
			||||||
 | 
					    env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
 | 
				
			||||||
 | 
					    # Build minimal mbedTLS library (MD5/SHA/Base64/AES).
 | 
				
			||||||
 | 
					    env_thirdparty = env_crypto.Clone()
 | 
				
			||||||
 | 
					    env_thirdparty.disable_warnings()
 | 
				
			||||||
 | 
					    thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
 | 
				
			||||||
 | 
					    thirdparty_mbedtls_sources = [
 | 
				
			||||||
 | 
					        "aes.c",
 | 
				
			||||||
 | 
					        "base64.c",
 | 
				
			||||||
 | 
					        "constant_time.c",
 | 
				
			||||||
 | 
					        "ctr_drbg.c",
 | 
				
			||||||
 | 
					        "entropy.c",
 | 
				
			||||||
 | 
					        "md.c",
 | 
				
			||||||
 | 
					        "md5.c",
 | 
				
			||||||
 | 
					        "sha1.c",
 | 
				
			||||||
 | 
					        "sha256.c",
 | 
				
			||||||
 | 
					        "godot_core_mbedtls_platform.c",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
 | 
				
			||||||
 | 
					    env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
 | 
				
			||||||
 | 
					    # Needed to force rebuilding the library when the configuration file is updated.
 | 
				
			||||||
 | 
					    env_thirdparty.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_core_mbedtls_config.h")
 | 
				
			||||||
 | 
					    env.core_sources += thirdparty_obj
 | 
				
			||||||
 | 
					elif is_builtin:
 | 
				
			||||||
 | 
					    # Module mbedTLS config file
 | 
				
			||||||
 | 
					    config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
 | 
				
			||||||
 | 
					    config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
 | 
				
			||||||
 | 
					    env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
 | 
				
			||||||
 | 
					    # Needed to force rebuilding the core files when the configuration file is updated.
 | 
				
			||||||
 | 
					    thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Godot source files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					core_obj = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_crypto.add_source_files(core_obj, "*.cpp")
 | 
				
			||||||
 | 
					env.core_sources += core_obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Needed to force rebuilding the core files when the thirdparty library is updated.
 | 
				
			||||||
 | 
					env.Depends(core_obj, thirdparty_obj)
 | 
				
			||||||
							
								
								
									
										115
									
								
								engine/core/crypto/aes_context.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								engine/core/crypto/aes_context.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,115 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  aes_context.cpp                                                       */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/crypto/aes_context.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error AESContext::start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(mode != MODE_MAX, ERR_ALREADY_IN_USE, "AESContext already started. Call 'finish' before starting a new one.");
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(p_mode < 0 || p_mode >= MODE_MAX, ERR_INVALID_PARAMETER, "Invalid mode requested.");
 | 
				
			||||||
 | 
						// Key check.
 | 
				
			||||||
 | 
						int key_bits = p_key.size() << 3;
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(key_bits != 128 && key_bits != 256, ERR_INVALID_PARAMETER, "AES key must be either 16 or 32 bytes");
 | 
				
			||||||
 | 
						// Initialization vector.
 | 
				
			||||||
 | 
						if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_CBC_DECRYPT) {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(p_iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes.");
 | 
				
			||||||
 | 
							iv.resize(0);
 | 
				
			||||||
 | 
							iv.append_array(p_iv);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Encryption/decryption key.
 | 
				
			||||||
 | 
						if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_ECB_ENCRYPT) {
 | 
				
			||||||
 | 
							ctx.set_encode_key(p_key.ptr(), key_bits);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ctx.set_decode_key(p_key.ptr(), key_bits);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mode = p_mode;
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedByteArray AESContext::update(const PackedByteArray &p_src) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(mode < 0 || mode >= MODE_MAX, PackedByteArray(), "AESContext not started. Call 'start' before calling 'update'.");
 | 
				
			||||||
 | 
						int len = p_src.size();
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(len % 16, PackedByteArray(), "The number of bytes to be encrypted must be multiple of 16. Add padding if needed");
 | 
				
			||||||
 | 
						PackedByteArray out;
 | 
				
			||||||
 | 
						out.resize(len);
 | 
				
			||||||
 | 
						const uint8_t *src_ptr = p_src.ptr();
 | 
				
			||||||
 | 
						uint8_t *out_ptr = out.ptrw();
 | 
				
			||||||
 | 
						switch (mode) {
 | 
				
			||||||
 | 
							case MODE_ECB_ENCRYPT: {
 | 
				
			||||||
 | 
								for (int i = 0; i < len; i += 16) {
 | 
				
			||||||
 | 
									Error err = ctx.encrypt_ecb(src_ptr + i, out_ptr + i);
 | 
				
			||||||
 | 
									ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_ECB_DECRYPT: {
 | 
				
			||||||
 | 
								for (int i = 0; i < len; i += 16) {
 | 
				
			||||||
 | 
									Error err = ctx.decrypt_ecb(src_ptr + i, out_ptr + i);
 | 
				
			||||||
 | 
									ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_CBC_ENCRYPT: {
 | 
				
			||||||
 | 
								Error err = ctx.encrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_CBC_DECRYPT: {
 | 
				
			||||||
 | 
								Error err = ctx.decrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(PackedByteArray(), "Bug!");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedByteArray AESContext::get_iv_state() {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(mode != MODE_CBC_ENCRYPT && mode != MODE_CBC_DECRYPT, PackedByteArray(), "Calling 'get_iv_state' only makes sense when the context is started in CBC mode.");
 | 
				
			||||||
 | 
						PackedByteArray out;
 | 
				
			||||||
 | 
						out.append_array(iv);
 | 
				
			||||||
 | 
						return out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AESContext::finish() {
 | 
				
			||||||
 | 
						mode = MODE_MAX;
 | 
				
			||||||
 | 
						iv.resize(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AESContext::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("start", "mode", "key", "iv"), &AESContext::start, DEFVAL(PackedByteArray()));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("update", "src"), &AESContext::update);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_iv_state"), &AESContext::get_iv_state);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("finish"), &AESContext::finish);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MODE_ECB_ENCRYPT);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MODE_ECB_DECRYPT);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MODE_CBC_ENCRYPT);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MODE_CBC_DECRYPT);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(MODE_MAX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AESContext::AESContext() {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										68
									
								
								engine/core/crypto/aes_context.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								engine/core/crypto/aes_context.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,68 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  aes_context.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef AES_CONTEXT_H
 | 
				
			||||||
 | 
					#define AES_CONTEXT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/crypto/crypto_core.h"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AESContext : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(AESContext, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum Mode {
 | 
				
			||||||
 | 
							MODE_ECB_ENCRYPT,
 | 
				
			||||||
 | 
							MODE_ECB_DECRYPT,
 | 
				
			||||||
 | 
							MODE_CBC_ENCRYPT,
 | 
				
			||||||
 | 
							MODE_CBC_DECRYPT,
 | 
				
			||||||
 | 
							MODE_MAX
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						Mode mode = MODE_MAX;
 | 
				
			||||||
 | 
						CryptoCore::AESContext ctx;
 | 
				
			||||||
 | 
						PackedByteArray iv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Error start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv = PackedByteArray());
 | 
				
			||||||
 | 
						PackedByteArray update(const PackedByteArray &p_src);
 | 
				
			||||||
 | 
						PackedByteArray get_iv_state();
 | 
				
			||||||
 | 
						void finish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AESContext();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(AESContext::Mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // AES_CONTEXT_H
 | 
				
			||||||
							
								
								
									
										263
									
								
								engine/core/crypto/crypto.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								engine/core/crypto/crypto.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,263 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  crypto.cpp                                                            */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/engine.h"
 | 
				
			||||||
 | 
					#include "core/io/certs_compressed.gen.h"
 | 
				
			||||||
 | 
					#include "core/io/compression.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Resources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoKey *(*CryptoKey::_create)() = nullptr;
 | 
				
			||||||
 | 
					CryptoKey *CryptoKey::create() {
 | 
				
			||||||
 | 
						if (_create) {
 | 
				
			||||||
 | 
							return _create();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CryptoKey::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save", "path", "public_only"), &CryptoKey::save, DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load", "path", "public_only"), &CryptoKey::load, DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_public_only"), &CryptoKey::is_public_only);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save_to_string", "public_only"), &CryptoKey::save_to_string, DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					X509Certificate *(*X509Certificate::_create)() = nullptr;
 | 
				
			||||||
 | 
					X509Certificate *X509Certificate::create() {
 | 
				
			||||||
 | 
						if (_create) {
 | 
				
			||||||
 | 
							return _create();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void X509Certificate::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save", "path"), &X509Certificate::save);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save_to_string"), &X509Certificate::save_to_string);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_from_string", "string"), &X509Certificate::load_from_string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TLSOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<TLSOptions> TLSOptions::client(Ref<X509Certificate> p_trusted_chain, const String &p_common_name_override) {
 | 
				
			||||||
 | 
						Ref<TLSOptions> opts;
 | 
				
			||||||
 | 
						opts.instantiate();
 | 
				
			||||||
 | 
						opts->mode = MODE_CLIENT;
 | 
				
			||||||
 | 
						opts->trusted_ca_chain = p_trusted_chain;
 | 
				
			||||||
 | 
						opts->common_name = p_common_name_override;
 | 
				
			||||||
 | 
						return opts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<TLSOptions> TLSOptions::client_unsafe(Ref<X509Certificate> p_trusted_chain) {
 | 
				
			||||||
 | 
						Ref<TLSOptions> opts;
 | 
				
			||||||
 | 
						opts.instantiate();
 | 
				
			||||||
 | 
						opts->mode = MODE_CLIENT_UNSAFE;
 | 
				
			||||||
 | 
						opts->trusted_ca_chain = p_trusted_chain;
 | 
				
			||||||
 | 
						return opts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<TLSOptions> TLSOptions::server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate) {
 | 
				
			||||||
 | 
						Ref<TLSOptions> opts;
 | 
				
			||||||
 | 
						opts.instantiate();
 | 
				
			||||||
 | 
						opts->mode = MODE_SERVER;
 | 
				
			||||||
 | 
						opts->own_certificate = p_own_certificate;
 | 
				
			||||||
 | 
						opts->private_key = p_own_key;
 | 
				
			||||||
 | 
						return opts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TLSOptions::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("TLSOptions", D_METHOD("client", "trusted_chain", "common_name_override"), &TLSOptions::client, DEFVAL(Ref<X509Certificate>()), DEFVAL(String()));
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("TLSOptions", D_METHOD("client_unsafe", "trusted_chain"), &TLSOptions::client_unsafe, DEFVAL(Ref<X509Certificate>()));
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("TLSOptions", D_METHOD("server", "key", "certificate"), &TLSOptions::server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_server"), &TLSOptions::is_server);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_unsafe_client"), &TLSOptions::is_unsafe_client);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_common_name_override"), &TLSOptions::get_common_name_override);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_trusted_ca_chain"), &TLSOptions::get_trusted_ca_chain);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_private_key"), &TLSOptions::get_private_key);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_own_certificate"), &TLSOptions::get_own_certificate);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HMACContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HMACContext::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("start", "hash_type", "key"), &HMACContext::start);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("update", "data"), &HMACContext::update);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HMACContext *(*HMACContext::_create)() = nullptr;
 | 
				
			||||||
 | 
					HMACContext *HMACContext::create() {
 | 
				
			||||||
 | 
						if (_create) {
 | 
				
			||||||
 | 
							return _create();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Crypto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void (*Crypto::_load_default_certificates)(const String &p_path) = nullptr;
 | 
				
			||||||
 | 
					Crypto *(*Crypto::_create)() = nullptr;
 | 
				
			||||||
 | 
					Crypto *Crypto::create() {
 | 
				
			||||||
 | 
						if (_create) {
 | 
				
			||||||
 | 
							return _create();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Crypto::load_default_certificates(const String &p_path) {
 | 
				
			||||||
 | 
						if (_load_default_certificates) {
 | 
				
			||||||
 | 
							_load_default_certificates(p_path);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg) {
 | 
				
			||||||
 | 
						Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available without mbedtls module.");
 | 
				
			||||||
 | 
						Error err = ctx->start(p_hash_type, p_key);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
						err = ctx->update(p_msg);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
						return ctx->finish();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Compares two HMACS for equality without leaking timing information in order to prevent timing attacks.
 | 
				
			||||||
 | 
					// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
 | 
				
			||||||
 | 
					bool Crypto::constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received) {
 | 
				
			||||||
 | 
						const uint8_t *t = p_trusted.ptr();
 | 
				
			||||||
 | 
						const uint8_t *r = p_received.ptr();
 | 
				
			||||||
 | 
						int tlen = p_trusted.size();
 | 
				
			||||||
 | 
						int rlen = p_received.size();
 | 
				
			||||||
 | 
						// If the lengths are different then nothing else matters.
 | 
				
			||||||
 | 
						if (tlen != rlen) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t v = 0;
 | 
				
			||||||
 | 
						for (int i = 0; i < tlen; i++) {
 | 
				
			||||||
 | 
							v |= t[i] ^ r[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return v == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Crypto::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("generate_self_signed_certificate", "key", "issuer_name", "not_before", "not_after"), &Crypto::generate_self_signed_certificate, DEFVAL("CN=myserver,O=myorganisation,C=IT"), DEFVAL("20140101000000"), DEFVAL("20340101000000"));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("sign", "hash_type", "hash", "key"), &Crypto::sign);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Resource loader/saver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
 | 
				
			||||||
 | 
						String el = p_path.get_extension().to_lower();
 | 
				
			||||||
 | 
						if (el == "crt") {
 | 
				
			||||||
 | 
							X509Certificate *cert = X509Certificate::create();
 | 
				
			||||||
 | 
							if (cert) {
 | 
				
			||||||
 | 
								cert->load(p_path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return cert;
 | 
				
			||||||
 | 
						} else if (el == "key") {
 | 
				
			||||||
 | 
							CryptoKey *key = CryptoKey::create();
 | 
				
			||||||
 | 
							if (key) {
 | 
				
			||||||
 | 
								key->load(p_path, false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return key;
 | 
				
			||||||
 | 
						} else if (el == "pub") {
 | 
				
			||||||
 | 
							CryptoKey *key = CryptoKey::create();
 | 
				
			||||||
 | 
							if (key) {
 | 
				
			||||||
 | 
								key->load(p_path, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return key;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
 | 
				
			||||||
 | 
						p_extensions->push_back("crt");
 | 
				
			||||||
 | 
						p_extensions->push_back("key");
 | 
				
			||||||
 | 
						p_extensions->push_back("pub");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
 | 
				
			||||||
 | 
						return p_type == "X509Certificate" || p_type == "CryptoKey";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
 | 
				
			||||||
 | 
						String el = p_path.get_extension().to_lower();
 | 
				
			||||||
 | 
						if (el == "crt") {
 | 
				
			||||||
 | 
							return "X509Certificate";
 | 
				
			||||||
 | 
						} else if (el == "key" || el == "pub") {
 | 
				
			||||||
 | 
							return "CryptoKey";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<X509Certificate> cert = p_resource;
 | 
				
			||||||
 | 
						Ref<CryptoKey> key = p_resource;
 | 
				
			||||||
 | 
						if (cert.is_valid()) {
 | 
				
			||||||
 | 
							err = cert->save(p_path);
 | 
				
			||||||
 | 
						} else if (key.is_valid()) {
 | 
				
			||||||
 | 
							String el = p_path.get_extension().to_lower();
 | 
				
			||||||
 | 
							err = key->save(p_path, el == "pub");
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ERR_FAIL_V(ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save Crypto resource to file '" + p_path + "'.");
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
 | 
				
			||||||
 | 
						const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
 | 
				
			||||||
 | 
						const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
 | 
				
			||||||
 | 
						if (cert) {
 | 
				
			||||||
 | 
							p_extensions->push_back("crt");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (key) {
 | 
				
			||||||
 | 
							if (!key->is_public_only()) {
 | 
				
			||||||
 | 
								p_extensions->push_back("key");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_extensions->push_back("pub");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
 | 
				
			||||||
 | 
						return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										167
									
								
								engine/core/crypto/crypto.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								engine/core/crypto/crypto.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,167 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  crypto.h                                                              */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CRYPTO_H
 | 
				
			||||||
 | 
					#define CRYPTO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/crypto/hashing_context.h"
 | 
				
			||||||
 | 
					#include "core/io/resource.h"
 | 
				
			||||||
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
 | 
					#include "core/io/resource_saver.h"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CryptoKey : public Resource {
 | 
				
			||||||
 | 
						GDCLASS(CryptoKey, Resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static CryptoKey *(*_create)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static CryptoKey *create();
 | 
				
			||||||
 | 
						virtual Error load(const String &p_path, bool p_public_only = false) = 0;
 | 
				
			||||||
 | 
						virtual Error save(const String &p_path, bool p_public_only = false) = 0;
 | 
				
			||||||
 | 
						virtual String save_to_string(bool p_public_only = false) = 0;
 | 
				
			||||||
 | 
						virtual Error load_from_string(const String &p_string_key, bool p_public_only = false) = 0;
 | 
				
			||||||
 | 
						virtual bool is_public_only() const = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class X509Certificate : public Resource {
 | 
				
			||||||
 | 
						GDCLASS(X509Certificate, Resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static X509Certificate *(*_create)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static X509Certificate *create();
 | 
				
			||||||
 | 
						virtual Error load(const String &p_path) = 0;
 | 
				
			||||||
 | 
						virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
 | 
				
			||||||
 | 
						virtual Error save(const String &p_path) = 0;
 | 
				
			||||||
 | 
						virtual String save_to_string() = 0;
 | 
				
			||||||
 | 
						virtual Error load_from_string(const String &string) = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TLSOptions : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(TLSOptions, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						enum Mode {
 | 
				
			||||||
 | 
							MODE_CLIENT = 0,
 | 
				
			||||||
 | 
							MODE_CLIENT_UNSAFE = 1,
 | 
				
			||||||
 | 
							MODE_SERVER = 2,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Mode mode = MODE_CLIENT;
 | 
				
			||||||
 | 
						String common_name;
 | 
				
			||||||
 | 
						Ref<X509Certificate> trusted_ca_chain;
 | 
				
			||||||
 | 
						Ref<X509Certificate> own_certificate;
 | 
				
			||||||
 | 
						Ref<CryptoKey> private_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Ref<TLSOptions> client(Ref<X509Certificate> p_trusted_chain = Ref<X509Certificate>(), const String &p_common_name_override = String());
 | 
				
			||||||
 | 
						static Ref<TLSOptions> client_unsafe(Ref<X509Certificate> p_trusted_chain);
 | 
				
			||||||
 | 
						static Ref<TLSOptions> server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_common_name_override() const { return common_name; }
 | 
				
			||||||
 | 
						Ref<X509Certificate> get_trusted_ca_chain() const { return trusted_ca_chain; }
 | 
				
			||||||
 | 
						Ref<X509Certificate> get_own_certificate() const { return own_certificate; }
 | 
				
			||||||
 | 
						Ref<CryptoKey> get_private_key() const { return private_key; }
 | 
				
			||||||
 | 
						bool is_server() const { return mode == MODE_SERVER; }
 | 
				
			||||||
 | 
						bool is_unsafe_client() const { return mode == MODE_CLIENT_UNSAFE; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HMACContext : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(HMACContext, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static HMACContext *(*_create)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static HMACContext *create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) = 0;
 | 
				
			||||||
 | 
						virtual Error update(const PackedByteArray &p_data) = 0;
 | 
				
			||||||
 | 
						virtual PackedByteArray finish() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HMACContext() {}
 | 
				
			||||||
 | 
						virtual ~HMACContext() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Crypto : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(Crypto, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						static Crypto *(*_create)();
 | 
				
			||||||
 | 
						static void (*_load_default_certificates)(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Crypto *create();
 | 
				
			||||||
 | 
						static void load_default_certificates(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual PackedByteArray generate_random_bytes(int p_bytes) = 0;
 | 
				
			||||||
 | 
						virtual Ref<CryptoKey> generate_rsa(int p_bytes) = 0;
 | 
				
			||||||
 | 
						virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) = 0;
 | 
				
			||||||
 | 
						virtual bool verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) = 0;
 | 
				
			||||||
 | 
						virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) = 0;
 | 
				
			||||||
 | 
						virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Compares two PackedByteArrays for equality without leaking timing information in order to prevent timing attacks.
 | 
				
			||||||
 | 
						// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
 | 
				
			||||||
 | 
						bool constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Crypto() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
 | 
				
			||||||
 | 
						virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 | 
				
			||||||
 | 
						virtual bool handles_type(const String &p_type) const override;
 | 
				
			||||||
 | 
						virtual String get_resource_type(const String &p_path) const override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResourceFormatSaverCrypto : public ResourceFormatSaver {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
 | 
				
			||||||
 | 
						virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
 | 
				
			||||||
 | 
						virtual bool recognize(const Ref<Resource> &p_resource) const override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CRYPTO_H
 | 
				
			||||||
							
								
								
									
										251
									
								
								engine/core/crypto/crypto_core.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								engine/core/crypto/crypto_core.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,251 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  crypto_core.cpp                                                       */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mbedtls/aes.h>
 | 
				
			||||||
 | 
					#include <mbedtls/base64.h>
 | 
				
			||||||
 | 
					#include <mbedtls/ctr_drbg.h>
 | 
				
			||||||
 | 
					#include <mbedtls/entropy.h>
 | 
				
			||||||
 | 
					#include <mbedtls/md5.h>
 | 
				
			||||||
 | 
					#include <mbedtls/sha1.h>
 | 
				
			||||||
 | 
					#include <mbedtls/sha256.h>
 | 
				
			||||||
 | 
					#if MBEDTLS_VERSION_MAJOR >= 3
 | 
				
			||||||
 | 
					#include <mbedtls/compat-2.x.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RandomGenerator
 | 
				
			||||||
 | 
					CryptoCore::RandomGenerator::RandomGenerator() {
 | 
				
			||||||
 | 
						entropy = memalloc(sizeof(mbedtls_entropy_context));
 | 
				
			||||||
 | 
						mbedtls_entropy_init((mbedtls_entropy_context *)entropy);
 | 
				
			||||||
 | 
						mbedtls_entropy_add_source((mbedtls_entropy_context *)entropy, &CryptoCore::RandomGenerator::_entropy_poll, nullptr, 256, MBEDTLS_ENTROPY_SOURCE_STRONG);
 | 
				
			||||||
 | 
						ctx = memalloc(sizeof(mbedtls_ctr_drbg_context));
 | 
				
			||||||
 | 
						mbedtls_ctr_drbg_init((mbedtls_ctr_drbg_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoCore::RandomGenerator::~RandomGenerator() {
 | 
				
			||||||
 | 
						mbedtls_ctr_drbg_free((mbedtls_ctr_drbg_context *)ctx);
 | 
				
			||||||
 | 
						memfree(ctx);
 | 
				
			||||||
 | 
						mbedtls_entropy_free((mbedtls_entropy_context *)entropy);
 | 
				
			||||||
 | 
						memfree(entropy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len) {
 | 
				
			||||||
 | 
						*r_len = 0;
 | 
				
			||||||
 | 
						Error err = OS::get_singleton()->get_entropy(r_buffer, p_len);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(err, MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
 | 
				
			||||||
 | 
						*r_len = p_len;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::RandomGenerator::init() {
 | 
				
			||||||
 | 
						int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
 | 
				
			||||||
 | 
						int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MD5
 | 
				
			||||||
 | 
					CryptoCore::MD5Context::MD5Context() {
 | 
				
			||||||
 | 
						ctx = memalloc(sizeof(mbedtls_md5_context));
 | 
				
			||||||
 | 
						mbedtls_md5_init((mbedtls_md5_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoCore::MD5Context::~MD5Context() {
 | 
				
			||||||
 | 
						mbedtls_md5_free((mbedtls_md5_context *)ctx);
 | 
				
			||||||
 | 
						memfree((mbedtls_md5_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::MD5Context::start() {
 | 
				
			||||||
 | 
						int ret = mbedtls_md5_starts_ret((mbedtls_md5_context *)ctx);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::MD5Context::update(const uint8_t *p_src, size_t p_len) {
 | 
				
			||||||
 | 
						int ret = mbedtls_md5_update_ret((mbedtls_md5_context *)ctx, p_src, p_len);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::MD5Context::finish(unsigned char r_hash[16]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_md5_finish_ret((mbedtls_md5_context *)ctx, r_hash);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SHA1
 | 
				
			||||||
 | 
					CryptoCore::SHA1Context::SHA1Context() {
 | 
				
			||||||
 | 
						ctx = memalloc(sizeof(mbedtls_sha1_context));
 | 
				
			||||||
 | 
						mbedtls_sha1_init((mbedtls_sha1_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoCore::SHA1Context::~SHA1Context() {
 | 
				
			||||||
 | 
						mbedtls_sha1_free((mbedtls_sha1_context *)ctx);
 | 
				
			||||||
 | 
						memfree((mbedtls_sha1_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA1Context::start() {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha1_starts_ret((mbedtls_sha1_context *)ctx);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA1Context::update(const uint8_t *p_src, size_t p_len) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha1_update_ret((mbedtls_sha1_context *)ctx, p_src, p_len);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA1Context::finish(unsigned char r_hash[20]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha1_finish_ret((mbedtls_sha1_context *)ctx, r_hash);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SHA256
 | 
				
			||||||
 | 
					CryptoCore::SHA256Context::SHA256Context() {
 | 
				
			||||||
 | 
						ctx = memalloc(sizeof(mbedtls_sha256_context));
 | 
				
			||||||
 | 
						mbedtls_sha256_init((mbedtls_sha256_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoCore::SHA256Context::~SHA256Context() {
 | 
				
			||||||
 | 
						mbedtls_sha256_free((mbedtls_sha256_context *)ctx);
 | 
				
			||||||
 | 
						memfree((mbedtls_sha256_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA256Context::start() {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha256_starts_ret((mbedtls_sha256_context *)ctx, 0);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA256Context::update(const uint8_t *p_src, size_t p_len) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha256_update_ret((mbedtls_sha256_context *)ctx, p_src, p_len);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::SHA256Context::finish(unsigned char r_hash[32]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha256_finish_ret((mbedtls_sha256_context *)ctx, r_hash);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AES256
 | 
				
			||||||
 | 
					CryptoCore::AESContext::AESContext() {
 | 
				
			||||||
 | 
						ctx = memalloc(sizeof(mbedtls_aes_context));
 | 
				
			||||||
 | 
						mbedtls_aes_init((mbedtls_aes_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CryptoCore::AESContext::~AESContext() {
 | 
				
			||||||
 | 
						mbedtls_aes_free((mbedtls_aes_context *)ctx);
 | 
				
			||||||
 | 
						memfree((mbedtls_aes_context *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::set_encode_key(const uint8_t *p_key, size_t p_bits) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_setkey_enc((mbedtls_aes_context *)ctx, p_key, p_bits);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::set_decode_key(const uint8_t *p_key, size_t p_bits) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_setkey_dec((mbedtls_aes_context *)ctx, p_key, p_bits);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
 | 
				
			||||||
 | 
						size_t iv_off = 0; // Ignore and assume 16-byte alignment.
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, r_iv, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
 | 
				
			||||||
 | 
						size_t iv_off = 0; // Ignore and assume 16-byte alignment.
 | 
				
			||||||
 | 
						int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CryptoCore
 | 
				
			||||||
 | 
					String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
 | 
				
			||||||
 | 
						int b64len = p_src_len / 3 * 4 + 4 + 1;
 | 
				
			||||||
 | 
						Vector<uint8_t> b64buff;
 | 
				
			||||||
 | 
						b64buff.resize(b64len);
 | 
				
			||||||
 | 
						uint8_t *w64 = b64buff.ptrw();
 | 
				
			||||||
 | 
						size_t strlen = 0;
 | 
				
			||||||
 | 
						int ret = b64_encode(&w64[0], b64len, &strlen, p_src, p_src_len);
 | 
				
			||||||
 | 
						w64[strlen] = 0;
 | 
				
			||||||
 | 
						return ret ? String() : (const char *)&w64[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) {
 | 
				
			||||||
 | 
						int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) {
 | 
				
			||||||
 | 
						int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error CryptoCore::sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]) {
 | 
				
			||||||
 | 
						int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
 | 
				
			||||||
 | 
						return ret ? FAILED : OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										119
									
								
								engine/core/crypto/crypto_core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								engine/core/crypto/crypto_core.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,119 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  crypto_core.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CRYPTO_CORE_H
 | 
				
			||||||
 | 
					#define CRYPTO_CORE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CryptoCore {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						class RandomGenerator {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void *entropy = nullptr;
 | 
				
			||||||
 | 
							void *ctx = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static int _entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							RandomGenerator();
 | 
				
			||||||
 | 
							~RandomGenerator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error init();
 | 
				
			||||||
 | 
							Error get_random_bytes(uint8_t *r_buffer, size_t p_bytes);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class MD5Context {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void *ctx = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							MD5Context();
 | 
				
			||||||
 | 
							~MD5Context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error start();
 | 
				
			||||||
 | 
							Error update(const uint8_t *p_src, size_t p_len);
 | 
				
			||||||
 | 
							Error finish(unsigned char r_hash[16]);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class SHA1Context {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void *ctx = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							SHA1Context();
 | 
				
			||||||
 | 
							~SHA1Context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error start();
 | 
				
			||||||
 | 
							Error update(const uint8_t *p_src, size_t p_len);
 | 
				
			||||||
 | 
							Error finish(unsigned char r_hash[20]);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class SHA256Context {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void *ctx = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							SHA256Context();
 | 
				
			||||||
 | 
							~SHA256Context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error start();
 | 
				
			||||||
 | 
							Error update(const uint8_t *p_src, size_t p_len);
 | 
				
			||||||
 | 
							Error finish(unsigned char r_hash[32]);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class AESContext {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void *ctx = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							AESContext();
 | 
				
			||||||
 | 
							~AESContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error set_encode_key(const uint8_t *p_key, size_t p_bits);
 | 
				
			||||||
 | 
							Error set_decode_key(const uint8_t *p_key, size_t p_bits);
 | 
				
			||||||
 | 
							Error encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
 | 
				
			||||||
 | 
							Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
 | 
				
			||||||
 | 
							Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
 | 
				
			||||||
 | 
							Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
 | 
				
			||||||
 | 
							Error encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
 | 
				
			||||||
 | 
							Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static String b64_encode_str(const uint8_t *p_src, int p_src_len);
 | 
				
			||||||
 | 
						static Error b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len);
 | 
				
			||||||
 | 
						static Error b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Error md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]);
 | 
				
			||||||
 | 
						static Error sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]);
 | 
				
			||||||
 | 
						static Error sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CRYPTO_CORE_H
 | 
				
			||||||
							
								
								
									
										134
									
								
								engine/core/crypto/hashing_context.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								engine/core/crypto/hashing_context.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,134 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  hashing_context.cpp                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hashing_context.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/crypto/crypto_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error HashingContext::start(HashType p_type) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
 | 
				
			||||||
 | 
						_create_ctx(p_type);
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(ctx, ERR_UNAVAILABLE);
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
							case HASH_MD5:
 | 
				
			||||||
 | 
								return ((CryptoCore::MD5Context *)ctx)->start();
 | 
				
			||||||
 | 
							case HASH_SHA1:
 | 
				
			||||||
 | 
								return ((CryptoCore::SHA1Context *)ctx)->start();
 | 
				
			||||||
 | 
							case HASH_SHA256:
 | 
				
			||||||
 | 
								return ((CryptoCore::SHA256Context *)ctx)->start();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ERR_UNAVAILABLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error HashingContext::update(const PackedByteArray &p_chunk) {
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
 | 
				
			||||||
 | 
						size_t len = p_chunk.size();
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(len == 0, FAILED);
 | 
				
			||||||
 | 
						const uint8_t *r = p_chunk.ptr();
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
							case HASH_MD5:
 | 
				
			||||||
 | 
								return ((CryptoCore::MD5Context *)ctx)->update(&r[0], len);
 | 
				
			||||||
 | 
							case HASH_SHA1:
 | 
				
			||||||
 | 
								return ((CryptoCore::SHA1Context *)ctx)->update(&r[0], len);
 | 
				
			||||||
 | 
							case HASH_SHA256:
 | 
				
			||||||
 | 
								return ((CryptoCore::SHA256Context *)ctx)->update(&r[0], len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ERR_UNAVAILABLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedByteArray HashingContext::finish() {
 | 
				
			||||||
 | 
						ERR_FAIL_NULL_V(ctx, PackedByteArray());
 | 
				
			||||||
 | 
						PackedByteArray out;
 | 
				
			||||||
 | 
						Error err = FAILED;
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
							case HASH_MD5:
 | 
				
			||||||
 | 
								out.resize(16);
 | 
				
			||||||
 | 
								err = ((CryptoCore::MD5Context *)ctx)->finish(out.ptrw());
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA1:
 | 
				
			||||||
 | 
								out.resize(20);
 | 
				
			||||||
 | 
								err = ((CryptoCore::SHA1Context *)ctx)->finish(out.ptrw());
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA256:
 | 
				
			||||||
 | 
								out.resize(32);
 | 
				
			||||||
 | 
								err = ((CryptoCore::SHA256Context *)ctx)->finish(out.ptrw());
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_delete_ctx();
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(err != OK, PackedByteArray());
 | 
				
			||||||
 | 
						return out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HashingContext::_create_ctx(HashType p_type) {
 | 
				
			||||||
 | 
						type = p_type;
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
							case HASH_MD5:
 | 
				
			||||||
 | 
								ctx = memnew(CryptoCore::MD5Context);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA1:
 | 
				
			||||||
 | 
								ctx = memnew(CryptoCore::SHA1Context);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA256:
 | 
				
			||||||
 | 
								ctx = memnew(CryptoCore::SHA256Context);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								ctx = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HashingContext::_delete_ctx() {
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
							case HASH_MD5:
 | 
				
			||||||
 | 
								memdelete((CryptoCore::MD5Context *)ctx);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA1:
 | 
				
			||||||
 | 
								memdelete((CryptoCore::SHA1Context *)ctx);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HASH_SHA256:
 | 
				
			||||||
 | 
								memdelete((CryptoCore::SHA256Context *)ctx);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx = nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HashingContext::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("start", "type"), &HashingContext::start);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("update", "chunk"), &HashingContext::update);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("finish"), &HashingContext::finish);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(HASH_MD5);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(HASH_SHA1);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(HASH_SHA256);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HashingContext::~HashingContext() {
 | 
				
			||||||
 | 
						if (ctx != nullptr) {
 | 
				
			||||||
 | 
							_delete_ctx();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										66
									
								
								engine/core/crypto/hashing_context.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								engine/core/crypto/hashing_context.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  hashing_context.h                                                     */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef HASHING_CONTEXT_H
 | 
				
			||||||
 | 
					#define HASHING_CONTEXT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HashingContext : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(HashingContext, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum HashType {
 | 
				
			||||||
 | 
							HASH_MD5,
 | 
				
			||||||
 | 
							HASH_SHA1,
 | 
				
			||||||
 | 
							HASH_SHA256
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void *ctx = nullptr;
 | 
				
			||||||
 | 
						HashType type = HASH_MD5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						void _create_ctx(HashType p_type);
 | 
				
			||||||
 | 
						void _delete_ctx();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Error start(HashType p_type);
 | 
				
			||||||
 | 
						Error update(const PackedByteArray &p_chunk);
 | 
				
			||||||
 | 
						PackedByteArray finish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashingContext() {}
 | 
				
			||||||
 | 
						~HashingContext();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(HashingContext::HashType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // HASHING_CONTEXT_H
 | 
				
			||||||
							
								
								
									
										5
									
								
								engine/core/debugger/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								engine/core/debugger/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
							
								
								
									
										149
									
								
								engine/core/debugger/debugger_marshalls.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								engine/core/debugger/debugger_marshalls.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,149 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  debugger_marshalls.cpp                                                */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "debugger_marshalls.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/marshalls.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CHECK_SIZE(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() < (uint32_t)(expected), false, String("Malformed ") + what + " message from script debugger, message too short. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
 | 
				
			||||||
 | 
					#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array DebuggerMarshalls::ScriptStackDump::serialize() {
 | 
				
			||||||
 | 
						Array arr;
 | 
				
			||||||
 | 
						arr.push_back(frames.size() * 3);
 | 
				
			||||||
 | 
						for (const ScriptLanguage::StackInfo &frame : frames) {
 | 
				
			||||||
 | 
							arr.push_back(frame.file);
 | 
				
			||||||
 | 
							arr.push_back(frame.line);
 | 
				
			||||||
 | 
							arr.push_back(frame.func);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DebuggerMarshalls::ScriptStackDump::deserialize(const Array &p_arr) {
 | 
				
			||||||
 | 
						CHECK_SIZE(p_arr, 1, "ScriptStackDump");
 | 
				
			||||||
 | 
						uint32_t size = p_arr[0];
 | 
				
			||||||
 | 
						CHECK_SIZE(p_arr, size, "ScriptStackDump");
 | 
				
			||||||
 | 
						int idx = 1;
 | 
				
			||||||
 | 
						for (uint32_t i = 0; i < size / 3; i++) {
 | 
				
			||||||
 | 
							ScriptLanguage::StackInfo sf;
 | 
				
			||||||
 | 
							sf.file = p_arr[idx];
 | 
				
			||||||
 | 
							sf.line = p_arr[idx + 1];
 | 
				
			||||||
 | 
							sf.func = p_arr[idx + 2];
 | 
				
			||||||
 | 
							frames.push_back(sf);
 | 
				
			||||||
 | 
							idx += 3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						CHECK_END(p_arr, idx, "ScriptStackDump");
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
 | 
				
			||||||
 | 
						Array arr;
 | 
				
			||||||
 | 
						arr.push_back(name);
 | 
				
			||||||
 | 
						arr.push_back(type);
 | 
				
			||||||
 | 
						arr.push_back(value.get_type());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Variant var = value;
 | 
				
			||||||
 | 
						if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
 | 
				
			||||||
 | 
							var = Variant();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
						Error err = encode_variant(var, nullptr, len, false);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							ERR_PRINT("Failed to encode variant.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len > max_size) {
 | 
				
			||||||
 | 
							arr.push_back(Variant());
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							arr.push_back(var);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
 | 
				
			||||||
 | 
						CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
 | 
				
			||||||
 | 
						name = p_arr[0];
 | 
				
			||||||
 | 
						type = p_arr[1];
 | 
				
			||||||
 | 
						var_type = p_arr[2];
 | 
				
			||||||
 | 
						value = p_arr[3];
 | 
				
			||||||
 | 
						CHECK_END(p_arr, 4, "ScriptStackVariable");
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array DebuggerMarshalls::OutputError::serialize() {
 | 
				
			||||||
 | 
						Array arr;
 | 
				
			||||||
 | 
						arr.push_back(hr);
 | 
				
			||||||
 | 
						arr.push_back(min);
 | 
				
			||||||
 | 
						arr.push_back(sec);
 | 
				
			||||||
 | 
						arr.push_back(msec);
 | 
				
			||||||
 | 
						arr.push_back(source_file);
 | 
				
			||||||
 | 
						arr.push_back(source_func);
 | 
				
			||||||
 | 
						arr.push_back(source_line);
 | 
				
			||||||
 | 
						arr.push_back(error);
 | 
				
			||||||
 | 
						arr.push_back(error_descr);
 | 
				
			||||||
 | 
						arr.push_back(warning);
 | 
				
			||||||
 | 
						unsigned int size = callstack.size();
 | 
				
			||||||
 | 
						const ScriptLanguage::StackInfo *r = callstack.ptr();
 | 
				
			||||||
 | 
						arr.push_back(size * 3);
 | 
				
			||||||
 | 
						for (int i = 0; i < callstack.size(); i++) {
 | 
				
			||||||
 | 
							arr.push_back(r[i].file);
 | 
				
			||||||
 | 
							arr.push_back(r[i].func);
 | 
				
			||||||
 | 
							arr.push_back(r[i].line);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DebuggerMarshalls::OutputError::deserialize(const Array &p_arr) {
 | 
				
			||||||
 | 
						CHECK_SIZE(p_arr, 11, "OutputError");
 | 
				
			||||||
 | 
						hr = p_arr[0];
 | 
				
			||||||
 | 
						min = p_arr[1];
 | 
				
			||||||
 | 
						sec = p_arr[2];
 | 
				
			||||||
 | 
						msec = p_arr[3];
 | 
				
			||||||
 | 
						source_file = p_arr[4];
 | 
				
			||||||
 | 
						source_func = p_arr[5];
 | 
				
			||||||
 | 
						source_line = p_arr[6];
 | 
				
			||||||
 | 
						error = p_arr[7];
 | 
				
			||||||
 | 
						error_descr = p_arr[8];
 | 
				
			||||||
 | 
						warning = p_arr[9];
 | 
				
			||||||
 | 
						unsigned int stack_size = p_arr[10];
 | 
				
			||||||
 | 
						CHECK_SIZE(p_arr, stack_size, "OutputError");
 | 
				
			||||||
 | 
						int idx = 11;
 | 
				
			||||||
 | 
						callstack.resize(stack_size / 3);
 | 
				
			||||||
 | 
						ScriptLanguage::StackInfo *w = callstack.ptrw();
 | 
				
			||||||
 | 
						for (unsigned int i = 0; i < stack_size / 3; i++) {
 | 
				
			||||||
 | 
							w[i].file = p_arr[idx];
 | 
				
			||||||
 | 
							w[i].func = p_arr[idx + 1];
 | 
				
			||||||
 | 
							w[i].line = p_arr[idx + 2];
 | 
				
			||||||
 | 
							idx += 3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						CHECK_END(p_arr, idx, "OutputError");
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										73
									
								
								engine/core/debugger/debugger_marshalls.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								engine/core/debugger/debugger_marshalls.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  debugger_marshalls.h                                                  */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DEBUGGER_MARSHALLS_H
 | 
				
			||||||
 | 
					#define DEBUGGER_MARSHALLS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DebuggerMarshalls {
 | 
				
			||||||
 | 
						struct ScriptStackVariable {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							Variant value;
 | 
				
			||||||
 | 
							int type = -1;
 | 
				
			||||||
 | 
							int var_type = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Array serialize(int max_size = 1 << 20); // 1 MiB default.
 | 
				
			||||||
 | 
							bool deserialize(const Array &p_arr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ScriptStackDump {
 | 
				
			||||||
 | 
							List<ScriptLanguage::StackInfo> frames;
 | 
				
			||||||
 | 
							ScriptStackDump() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Array serialize();
 | 
				
			||||||
 | 
							bool deserialize(const Array &p_arr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct OutputError {
 | 
				
			||||||
 | 
							int hr = -1;
 | 
				
			||||||
 | 
							int min = -1;
 | 
				
			||||||
 | 
							int sec = -1;
 | 
				
			||||||
 | 
							int msec = -1;
 | 
				
			||||||
 | 
							String source_file;
 | 
				
			||||||
 | 
							String source_func;
 | 
				
			||||||
 | 
							int source_line = -1;
 | 
				
			||||||
 | 
							String error;
 | 
				
			||||||
 | 
							String error_descr;
 | 
				
			||||||
 | 
							bool warning = false;
 | 
				
			||||||
 | 
							Vector<ScriptLanguage::StackInfo> callstack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Array serialize();
 | 
				
			||||||
 | 
							bool deserialize(const Array &p_arr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DEBUGGER_MARSHALLS_H
 | 
				
			||||||
							
								
								
									
										203
									
								
								engine/core/debugger/engine_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								engine/core/debugger/engine_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,203 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine_debugger.cpp                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "engine_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/local_debugger.h"
 | 
				
			||||||
 | 
					#include "core/debugger/remote_debugger.h"
 | 
				
			||||||
 | 
					#include "core/debugger/remote_debugger_peer.h"
 | 
				
			||||||
 | 
					#include "core/debugger/script_debugger.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EngineDebugger *EngineDebugger::singleton = nullptr;
 | 
				
			||||||
 | 
					ScriptDebugger *EngineDebugger::script_debugger = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HashMap<StringName, EngineDebugger::Profiler> EngineDebugger::profilers;
 | 
				
			||||||
 | 
					HashMap<StringName, EngineDebugger::Capture> EngineDebugger::captures;
 | 
				
			||||||
 | 
					HashMap<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void (*EngineDebugger::allow_focus_steal_fn)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name);
 | 
				
			||||||
 | 
						profilers.insert(p_name, p_func);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::unregister_profiler(const StringName &p_name) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
 | 
				
			||||||
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
 | 
						if (p.active && p.toggle) {
 | 
				
			||||||
 | 
							p.toggle(p.data, false, Array());
 | 
				
			||||||
 | 
							p.active = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						profilers.erase(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(captures.has(p_name), "Capture already registered: " + p_name);
 | 
				
			||||||
 | 
						captures.insert(p_name, p_func);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::unregister_message_capture(const StringName &p_name) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
 | 
				
			||||||
 | 
						captures.erase(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol);
 | 
				
			||||||
 | 
						protocols.insert(p_protocol, p_func);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name);
 | 
				
			||||||
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
 | 
						if (p.toggle) {
 | 
				
			||||||
 | 
							p.toggle(p.data, p_enabled, p_opts);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.active = p_enabled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't add frame data, no profiler: " + p_name);
 | 
				
			||||||
 | 
						Profiler &p = profilers[p_name];
 | 
				
			||||||
 | 
						if (p.add) {
 | 
				
			||||||
 | 
							p.add(p.data, p_data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EngineDebugger::is_profiling(const StringName &p_name) {
 | 
				
			||||||
 | 
						return profilers.has(p_name) && profilers[p_name].active;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EngineDebugger::has_profiler(const StringName &p_name) {
 | 
				
			||||||
 | 
						return profilers.has(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EngineDebugger::has_capture(const StringName &p_name) {
 | 
				
			||||||
 | 
						return captures.has(p_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) {
 | 
				
			||||||
 | 
						r_captured = false;
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, "Capture not registered: " + p_name);
 | 
				
			||||||
 | 
						const Capture &cap = captures[p_name];
 | 
				
			||||||
 | 
						return cap.capture(cap.data, p_msg, p_args, r_captured);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time) {
 | 
				
			||||||
 | 
						frame_time = USEC_TO_SEC(p_frame_ticks);
 | 
				
			||||||
 | 
						process_time = USEC_TO_SEC(p_process_ticks);
 | 
				
			||||||
 | 
						physics_time = USEC_TO_SEC(p_physics_ticks);
 | 
				
			||||||
 | 
						physics_frame_time = p_physics_frame_time;
 | 
				
			||||||
 | 
						// Notify tick to running profilers
 | 
				
			||||||
 | 
						for (KeyValue<StringName, Profiler> &E : profilers) {
 | 
				
			||||||
 | 
							Profiler &p = E.value;
 | 
				
			||||||
 | 
							if (!p.active || !p.tick) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p.tick(p.data, frame_time, process_time, physics_time, physics_frame_time);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						singleton->poll_events(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) {
 | 
				
			||||||
 | 
						register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
 | 
				
			||||||
 | 
						if (p_uri.is_empty()) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (p_uri == "local://") {
 | 
				
			||||||
 | 
							singleton = memnew(LocalDebugger);
 | 
				
			||||||
 | 
							script_debugger = memnew(ScriptDebugger);
 | 
				
			||||||
 | 
							// Tell the OS that we want to handle termination signals.
 | 
				
			||||||
 | 
							OS::get_singleton()->initialize_debugging();
 | 
				
			||||||
 | 
						} else if (p_uri.contains("://")) {
 | 
				
			||||||
 | 
							const String proto = p_uri.substr(0, p_uri.find("://") + 3);
 | 
				
			||||||
 | 
							if (!protocols.has(proto)) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							RemoteDebuggerPeer *peer = protocols[proto](p_uri);
 | 
				
			||||||
 | 
							if (!peer) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
 | 
				
			||||||
 | 
							script_debugger = memnew(ScriptDebugger);
 | 
				
			||||||
 | 
							// Notify editor of our pid (to allow focus stealing).
 | 
				
			||||||
 | 
							Array msg;
 | 
				
			||||||
 | 
							msg.push_back(OS::get_singleton()->get_process_id());
 | 
				
			||||||
 | 
							singleton->send_message("set_pid", msg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!singleton) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// There is a debugger, parse breakpoints.
 | 
				
			||||||
 | 
						ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger();
 | 
				
			||||||
 | 
						singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < p_breakpoints.size(); i++) {
 | 
				
			||||||
 | 
							const String &bp = p_breakpoints[i];
 | 
				
			||||||
 | 
							int sp = bp.rfind(":");
 | 
				
			||||||
 | 
							ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						allow_focus_steal_fn = p_allow_focus_steal_fn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineDebugger::deinitialize() {
 | 
				
			||||||
 | 
						if (singleton) {
 | 
				
			||||||
 | 
							// Stop all profilers
 | 
				
			||||||
 | 
							for (const KeyValue<StringName, Profiler> &E : profilers) {
 | 
				
			||||||
 | 
								if (E.value.active) {
 | 
				
			||||||
 | 
									singleton->profiler_enable(E.key, false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Flush any remaining message
 | 
				
			||||||
 | 
							singleton->poll_events(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memdelete(singleton);
 | 
				
			||||||
 | 
							singleton = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Clear profilers/captures/protocol handlers.
 | 
				
			||||||
 | 
						profilers.clear();
 | 
				
			||||||
 | 
						captures.clear();
 | 
				
			||||||
 | 
						protocols.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EngineDebugger::~EngineDebugger() {
 | 
				
			||||||
 | 
						if (script_debugger) {
 | 
				
			||||||
 | 
							memdelete(script_debugger);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						script_debugger = nullptr;
 | 
				
			||||||
 | 
						singleton = nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										145
									
								
								engine/core/debugger/engine_debugger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								engine/core/debugger/engine_debugger.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,145 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine_debugger.h                                                     */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ENGINE_DEBUGGER_H
 | 
				
			||||||
 | 
					#define ENGINE_DEBUGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
 | 
					#include "core/variant/array.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoteDebuggerPeer;
 | 
				
			||||||
 | 
					class ScriptDebugger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EngineDebugger {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts);
 | 
				
			||||||
 | 
						typedef void (*ProfilingTick)(void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
 | 
				
			||||||
 | 
						typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class Profiler {
 | 
				
			||||||
 | 
							friend class EngineDebugger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ProfilingToggle toggle = nullptr;
 | 
				
			||||||
 | 
							ProfilingAdd add = nullptr;
 | 
				
			||||||
 | 
							ProfilingTick tick = nullptr;
 | 
				
			||||||
 | 
							void *data = nullptr;
 | 
				
			||||||
 | 
							bool active = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							Profiler() {}
 | 
				
			||||||
 | 
							Profiler(void *p_data, ProfilingToggle p_toggle, ProfilingAdd p_add, ProfilingTick p_tick) {
 | 
				
			||||||
 | 
								data = p_data;
 | 
				
			||||||
 | 
								toggle = p_toggle;
 | 
				
			||||||
 | 
								add = p_add;
 | 
				
			||||||
 | 
								tick = p_tick;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class Capture {
 | 
				
			||||||
 | 
							friend class EngineDebugger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CaptureFunc capture = nullptr;
 | 
				
			||||||
 | 
							void *data = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							Capture() {}
 | 
				
			||||||
 | 
							Capture(void *p_data, CaptureFunc p_capture) {
 | 
				
			||||||
 | 
								data = p_data;
 | 
				
			||||||
 | 
								capture = p_capture;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						double frame_time = 0.0;
 | 
				
			||||||
 | 
						double process_time = 0.0;
 | 
				
			||||||
 | 
						double physics_time = 0.0;
 | 
				
			||||||
 | 
						double physics_frame_time = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t poll_every = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static EngineDebugger *singleton;
 | 
				
			||||||
 | 
						static ScriptDebugger *script_debugger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static HashMap<StringName, Profiler> profilers;
 | 
				
			||||||
 | 
						static HashMap<StringName, Capture> captures;
 | 
				
			||||||
 | 
						static HashMap<String, CreatePeerFunc> protocols;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void (*allow_focus_steal_fn)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
						_FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
 | 
				
			||||||
 | 
						static void deinitialize();
 | 
				
			||||||
 | 
						static void register_profiler(const StringName &p_name, const Profiler &p_profiler);
 | 
				
			||||||
 | 
						static void unregister_profiler(const StringName &p_name);
 | 
				
			||||||
 | 
						static bool is_profiling(const StringName &p_name);
 | 
				
			||||||
 | 
						static bool has_profiler(const StringName &p_name);
 | 
				
			||||||
 | 
						static void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void register_message_capture(const StringName &p_name, Capture p_func);
 | 
				
			||||||
 | 
						static void unregister_message_capture(const StringName &p_name);
 | 
				
			||||||
 | 
						static bool has_capture(const StringName &p_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time);
 | 
				
			||||||
 | 
						void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
 | 
				
			||||||
 | 
						Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void line_poll() {
 | 
				
			||||||
 | 
							// The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught.
 | 
				
			||||||
 | 
							if (unlikely(poll_every % 2048) == 0) {
 | 
				
			||||||
 | 
								poll_events(false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							poll_every++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void poll_events(bool p_is_idle) {}
 | 
				
			||||||
 | 
						virtual void send_message(const String &p_msg, const Array &p_data) = 0;
 | 
				
			||||||
 | 
						virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) = 0;
 | 
				
			||||||
 | 
						virtual void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual ~EngineDebugger();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ENGINE_DEBUGGER_H
 | 
				
			||||||
							
								
								
									
										82
									
								
								engine/core/debugger/engine_profiler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								engine/core/debugger/engine_profiler.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,82 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine_profiler.cpp                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "engine_profiler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineProfiler::_bind_methods() {
 | 
				
			||||||
 | 
						GDVIRTUAL_BIND(_toggle, "enable", "options");
 | 
				
			||||||
 | 
						GDVIRTUAL_BIND(_add_frame, "data");
 | 
				
			||||||
 | 
						GDVIRTUAL_BIND(_tick, "frame_time", "process_time", "physics_time", "physics_frame_time");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineProfiler::toggle(bool p_enable, const Array &p_array) {
 | 
				
			||||||
 | 
						GDVIRTUAL_CALL(_toggle, p_enable, p_array);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineProfiler::add(const Array &p_data) {
 | 
				
			||||||
 | 
						GDVIRTUAL_CALL(_add_frame, p_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
 | 
				
			||||||
 | 
						GDVIRTUAL_CALL(_tick, p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error EngineProfiler::bind(const String &p_name) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(is_bound(), ERR_ALREADY_IN_USE);
 | 
				
			||||||
 | 
						EngineDebugger::Profiler prof(
 | 
				
			||||||
 | 
								this,
 | 
				
			||||||
 | 
								[](void *p_user, bool p_enable, const Array &p_opts) {
 | 
				
			||||||
 | 
									static_cast<EngineProfiler *>(p_user)->toggle(p_enable, p_opts);
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[](void *p_user, const Array &p_data) {
 | 
				
			||||||
 | 
									static_cast<EngineProfiler *>(p_user)->add(p_data);
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
 | 
				
			||||||
 | 
									static_cast<EngineProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
						registration = p_name;
 | 
				
			||||||
 | 
						EngineDebugger::register_profiler(p_name, prof);
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error EngineProfiler::unbind() {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!is_bound(), ERR_UNCONFIGURED);
 | 
				
			||||||
 | 
						EngineDebugger::unregister_profiler(registration);
 | 
				
			||||||
 | 
						registration.clear();
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EngineProfiler::~EngineProfiler() {
 | 
				
			||||||
 | 
						if (is_bound()) {
 | 
				
			||||||
 | 
							unbind();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								engine/core/debugger/engine_profiler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								engine/core/debugger/engine_profiler.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  engine_profiler.h                                                     */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ENGINE_PROFILER_H
 | 
				
			||||||
 | 
					#define ENGINE_PROFILER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/gdvirtual.gen.inc"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EngineProfiler : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(EngineProfiler, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						String registration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual void toggle(bool p_enable, const Array &p_opts);
 | 
				
			||||||
 | 
						virtual void add(const Array &p_data);
 | 
				
			||||||
 | 
						virtual void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error bind(const String &p_name);
 | 
				
			||||||
 | 
						Error unbind();
 | 
				
			||||||
 | 
						bool is_bound() const { return registration.length() > 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDVIRTUAL2(_toggle, bool, Array);
 | 
				
			||||||
 | 
						GDVIRTUAL1(_add_frame, Array);
 | 
				
			||||||
 | 
						GDVIRTUAL4(_tick, double, double, double, double);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EngineProfiler() {}
 | 
				
			||||||
 | 
						virtual ~EngineProfiler();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ENGINE_PROFILER_H
 | 
				
			||||||
							
								
								
									
										390
									
								
								engine/core/debugger/local_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								engine/core/debugger/local_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,390 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  local_debugger.cpp                                                    */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "local_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/script_debugger.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LocalDebugger::ScriptsProfiler {
 | 
				
			||||||
 | 
						struct ProfileInfoSort {
 | 
				
			||||||
 | 
							bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const {
 | 
				
			||||||
 | 
								return A.total_time > B.total_time;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double frame_time = 0;
 | 
				
			||||||
 | 
						uint64_t idle_accum = 0;
 | 
				
			||||||
 | 
						Vector<ScriptLanguage::ProfilingInfo> pinfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void toggle(bool p_enable, const Array &p_opts) {
 | 
				
			||||||
 | 
							if (p_enable) {
 | 
				
			||||||
 | 
								for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
									ScriptServer::get_language(i)->profiling_start();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								print_line("BEGIN PROFILING");
 | 
				
			||||||
 | 
								pinfo.resize(32768);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								_print_frame_data(true);
 | 
				
			||||||
 | 
								for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
									ScriptServer::get_language(i)->profiling_stop();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
 | 
				
			||||||
 | 
							frame_time = p_frame_time;
 | 
				
			||||||
 | 
							_print_frame_data(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _print_frame_data(bool p_accumulated) {
 | 
				
			||||||
 | 
							uint64_t diff = OS::get_singleton()->get_ticks_usec() - idle_accum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!p_accumulated && diff < 1000000) { //show every one second
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							idle_accum = OS::get_singleton()->get_ticks_usec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int ofs = 0;
 | 
				
			||||||
 | 
							for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
								if (p_accumulated) {
 | 
				
			||||||
 | 
									ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo.write[ofs], pinfo.size() - ofs);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo.write[ofs], pinfo.size() - ofs);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SortArray<ScriptLanguage::ProfilingInfo, ProfileInfoSort> sort;
 | 
				
			||||||
 | 
							sort.sort(pinfo.ptrw(), ofs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// compute total script frame time
 | 
				
			||||||
 | 
							uint64_t script_time_us = 0;
 | 
				
			||||||
 | 
							for (int i = 0; i < ofs; i++) {
 | 
				
			||||||
 | 
								script_time_us += pinfo[i].self_time;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							double script_time = USEC_TO_SEC(script_time_us);
 | 
				
			||||||
 | 
							double total_time = p_accumulated ? script_time : frame_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!p_accumulated) {
 | 
				
			||||||
 | 
								print_line("FRAME: total: " + rtos(total_time) + " script: " + rtos(script_time) + "/" + itos(script_time * 100 / total_time) + " %");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								print_line("ACCUMULATED: total: " + rtos(total_time));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < ofs; i++) {
 | 
				
			||||||
 | 
								print_line(itos(i) + ":" + pinfo[i].signature);
 | 
				
			||||||
 | 
								double tt = USEC_TO_SEC(pinfo[i].total_time);
 | 
				
			||||||
 | 
								double st = USEC_TO_SEC(pinfo[i].self_time);
 | 
				
			||||||
 | 
								print_line("\ttotal: " + rtos(tt) + "/" + itos(tt * 100 / total_time) + " % \tself: " + rtos(st) + "/" + itos(st * 100 / total_time) + " % tcalls: " + itos(pinfo[i].call_count));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ScriptsProfiler() {
 | 
				
			||||||
 | 
							idle_accum = OS::get_singleton()->get_ticks_usec();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
 | 
						ScriptLanguage *script_lang = script_debugger->get_break_language();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!target_function.is_empty()) {
 | 
				
			||||||
 | 
							String current_function = script_lang->debug_get_stack_level_function(0);
 | 
				
			||||||
 | 
							if (current_function != target_function) {
 | 
				
			||||||
 | 
								script_debugger->set_depth(0);
 | 
				
			||||||
 | 
								script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							target_function = "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
 | 
				
			||||||
 | 
						print_line("*Frame " + itos(0) + " - " + script_lang->debug_get_stack_level_source(0) + ":" + itos(script_lang->debug_get_stack_level_line(0)) + " in function '" + script_lang->debug_get_stack_level_function(0) + "'");
 | 
				
			||||||
 | 
						print_line("Enter \"help\" for assistance.");
 | 
				
			||||||
 | 
						int current_frame = 0;
 | 
				
			||||||
 | 
						int total_frames = script_lang->debug_get_stack_level_count();
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							OS::get_singleton()->print("debug> ");
 | 
				
			||||||
 | 
							String line = OS::get_singleton()->get_stdin_string().strip_edges();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Cache options
 | 
				
			||||||
 | 
							String variable_prefix = options["variable_prefix"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (line.is_empty() && !feof(stdin)) {
 | 
				
			||||||
 | 
								print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
 | 
				
			||||||
 | 
								print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
 | 
				
			||||||
 | 
								print_line("Enter \"help\" for assistance.");
 | 
				
			||||||
 | 
							} else if (line == "c" || line == "continue") {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} else if (line == "bt" || line == "breakpoint") {
 | 
				
			||||||
 | 
								for (int i = 0; i < total_frames; i++) {
 | 
				
			||||||
 | 
									String cfi = (current_frame == i) ? "*" : " "; //current frame indicator
 | 
				
			||||||
 | 
									print_line(cfi + "Frame " + itos(i) + " - " + script_lang->debug_get_stack_level_source(i) + ":" + itos(script_lang->debug_get_stack_level_line(i)) + " in function '" + script_lang->debug_get_stack_level_function(i) + "'");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line.begins_with("fr") || line.begins_with("frame")) {
 | 
				
			||||||
 | 
								if (line.get_slice_count(" ") == 1) {
 | 
				
			||||||
 | 
									print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									int frame = line.get_slicec(' ', 1).to_int();
 | 
				
			||||||
 | 
									if (frame < 0 || frame >= total_frames) {
 | 
				
			||||||
 | 
										print_line("Error: Invalid frame.");
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										current_frame = frame;
 | 
				
			||||||
 | 
										print_line("*Frame " + itos(frame) + " - " + script_lang->debug_get_stack_level_source(frame) + ":" + itos(script_lang->debug_get_stack_level_line(frame)) + " in function '" + script_lang->debug_get_stack_level_function(frame) + "'");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line.begins_with("set")) {
 | 
				
			||||||
 | 
								if (line.get_slice_count(" ") == 1) {
 | 
				
			||||||
 | 
									for (const KeyValue<String, String> &E : options) {
 | 
				
			||||||
 | 
										print_line("\t" + E.key + "=" + E.value);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									String key_value = line.get_slicec(' ', 1);
 | 
				
			||||||
 | 
									int value_pos = key_value.find("=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (value_pos < 0) {
 | 
				
			||||||
 | 
										print_line("Error: Invalid set format. Use: set key=value");
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										String key = key_value.left(value_pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (!options.has(key)) {
 | 
				
			||||||
 | 
											print_line("Error: Unknown option " + key);
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											// Allow explicit tab character
 | 
				
			||||||
 | 
											String value = key_value.substr(value_pos + 1).replace("\\t", "\t");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											options[key] = value;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "lv" || line == "locals") {
 | 
				
			||||||
 | 
								List<String> locals;
 | 
				
			||||||
 | 
								List<Variant> values;
 | 
				
			||||||
 | 
								script_lang->debug_get_stack_level_locals(current_frame, &locals, &values);
 | 
				
			||||||
 | 
								print_variables(locals, values, variable_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "gv" || line == "globals") {
 | 
				
			||||||
 | 
								List<String> globals;
 | 
				
			||||||
 | 
								List<Variant> values;
 | 
				
			||||||
 | 
								script_lang->debug_get_globals(&globals, &values);
 | 
				
			||||||
 | 
								print_variables(globals, values, variable_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "mv" || line == "members") {
 | 
				
			||||||
 | 
								List<String> members;
 | 
				
			||||||
 | 
								List<Variant> values;
 | 
				
			||||||
 | 
								script_lang->debug_get_stack_level_members(current_frame, &members, &values);
 | 
				
			||||||
 | 
								print_variables(members, values, variable_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line.begins_with("p") || line.begins_with("print")) {
 | 
				
			||||||
 | 
								if (line.get_slice_count(" ") <= 1) {
 | 
				
			||||||
 | 
									print_line("Usage: print <expre>");
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									String expr = line.get_slicec(' ', 2);
 | 
				
			||||||
 | 
									String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
 | 
				
			||||||
 | 
									print_line(res);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "s" || line == "step") {
 | 
				
			||||||
 | 
								script_debugger->set_depth(-1);
 | 
				
			||||||
 | 
								script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} else if (line == "n" || line == "next") {
 | 
				
			||||||
 | 
								script_debugger->set_depth(0);
 | 
				
			||||||
 | 
								script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} else if (line == "fin" || line == "finish") {
 | 
				
			||||||
 | 
								String current_function = script_lang->debug_get_stack_level_function(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int i = 0; i < total_frames; i++) {
 | 
				
			||||||
 | 
									target_function = script_lang->debug_get_stack_level_function(i);
 | 
				
			||||||
 | 
									if (target_function != current_function) {
 | 
				
			||||||
 | 
										script_debugger->set_depth(0);
 | 
				
			||||||
 | 
										script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								print_line("Error: Reached last frame.");
 | 
				
			||||||
 | 
								target_function = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line.begins_with("br") || line.begins_with("break")) {
 | 
				
			||||||
 | 
								if (line.get_slice_count(" ") <= 1) {
 | 
				
			||||||
 | 
									const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
 | 
				
			||||||
 | 
									if (breakpoints.size() == 0) {
 | 
				
			||||||
 | 
										print_line("No Breakpoints.");
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									print_line("Breakpoint(s): " + itos(breakpoints.size()));
 | 
				
			||||||
 | 
									for (const KeyValue<int, HashSet<StringName>> &E : breakpoints) {
 | 
				
			||||||
 | 
										print_line("\t" + String(*E.value.begin()) + ":" + itos(E.key));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									Pair<String, int> breakpoint = to_breakpoint(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									String source = breakpoint.first;
 | 
				
			||||||
 | 
									int linenr = breakpoint.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (source.is_empty()) {
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									script_debugger->insert_breakpoint(linenr, source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									print_line("Added breakpoint at " + source + ":" + itos(linenr));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "q" || line == "quit" ||
 | 
				
			||||||
 | 
									(line.is_empty() && feof(stdin))) {
 | 
				
			||||||
 | 
								// Do not stop again on quit
 | 
				
			||||||
 | 
								script_debugger->clear_breakpoints();
 | 
				
			||||||
 | 
								script_debugger->set_depth(-1);
 | 
				
			||||||
 | 
								script_debugger->set_lines_left(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								MainLoop *main_loop = OS::get_singleton()->get_main_loop();
 | 
				
			||||||
 | 
								if (main_loop->get_class() == "SceneTree") {
 | 
				
			||||||
 | 
									main_loop->call("quit");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} else if (line.begins_with("delete")) {
 | 
				
			||||||
 | 
								if (line.get_slice_count(" ") <= 1) {
 | 
				
			||||||
 | 
									script_debugger->clear_breakpoints();
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									Pair<String, int> breakpoint = to_breakpoint(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									String source = breakpoint.first;
 | 
				
			||||||
 | 
									int linenr = breakpoint.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (source.is_empty()) {
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									script_debugger->remove_breakpoint(linenr, source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									print_line("Removed breakpoint at " + source + ":" + itos(linenr));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (line == "h" || line == "help") {
 | 
				
			||||||
 | 
								print_line("Built-In Debugger command list:\n");
 | 
				
			||||||
 | 
								print_line("\tc,continue\t\t Continue execution.");
 | 
				
			||||||
 | 
								print_line("\tbt,backtrace\t\t Show stack trace (frames).");
 | 
				
			||||||
 | 
								print_line("\tfr,frame <frame>:\t Change current frame.");
 | 
				
			||||||
 | 
								print_line("\tlv,locals\t\t Show local variables for current frame.");
 | 
				
			||||||
 | 
								print_line("\tmv,members\t\t Show member variables for \"this\" in frame.");
 | 
				
			||||||
 | 
								print_line("\tgv,globals\t\t Show global variables.");
 | 
				
			||||||
 | 
								print_line("\tp,print <expr>\t\t Execute and print variable in expression.");
 | 
				
			||||||
 | 
								print_line("\ts,step\t\t\t Step to next line.");
 | 
				
			||||||
 | 
								print_line("\tn,next\t\t\t Next line.");
 | 
				
			||||||
 | 
								print_line("\tfin,finish\t\t Step out of current frame.");
 | 
				
			||||||
 | 
								print_line("\tbr,break [source:line]\t List all breakpoints or place a breakpoint.");
 | 
				
			||||||
 | 
								print_line("\tdelete [source:line]:\t Delete one/all breakpoints.");
 | 
				
			||||||
 | 
								print_line("\tset [key=value]:\t List all options, or set one.");
 | 
				
			||||||
 | 
								print_line("\tq,quit\t\t\t Quit application.");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								print_line("Error: Invalid command, enter \"help\" for assistance.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LocalDebugger::print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix) {
 | 
				
			||||||
 | 
						String value;
 | 
				
			||||||
 | 
						Vector<String> value_lines;
 | 
				
			||||||
 | 
						const List<Variant>::Element *V = values.front();
 | 
				
			||||||
 | 
						for (const String &E : names) {
 | 
				
			||||||
 | 
							value = String(V->get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (variable_prefix.is_empty()) {
 | 
				
			||||||
 | 
								print_line(E + ": " + String(V->get()));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								print_line(E + ":");
 | 
				
			||||||
 | 
								value_lines = value.split("\n");
 | 
				
			||||||
 | 
								for (int i = 0; i < value_lines.size(); ++i) {
 | 
				
			||||||
 | 
									print_line(variable_prefix + value_lines[i]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							V = V->next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
 | 
				
			||||||
 | 
						String breakpoint_part = p_line.get_slicec(' ', 1);
 | 
				
			||||||
 | 
						Pair<String, int> breakpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int last_colon = breakpoint_part.rfind(":");
 | 
				
			||||||
 | 
						if (last_colon < 0) {
 | 
				
			||||||
 | 
							print_line("Error: Invalid breakpoint format. Expected [source:line]");
 | 
				
			||||||
 | 
							return breakpoint;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						breakpoint.first = script_debugger->breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges());
 | 
				
			||||||
 | 
						breakpoint.second = breakpoint_part.substr(last_colon).strip_edges().to_int();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return breakpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LocalDebugger::send_message(const String &p_message, const Array &p_args) {
 | 
				
			||||||
 | 
						// This needs to be cleaned up entirely.
 | 
				
			||||||
 | 
						// print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LocalDebugger::LocalDebugger() {
 | 
				
			||||||
 | 
						options["variable_prefix"] = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bind scripts profiler.
 | 
				
			||||||
 | 
						scripts_profiler = memnew(ScriptsProfiler);
 | 
				
			||||||
 | 
						Profiler scr_prof(
 | 
				
			||||||
 | 
								scripts_profiler,
 | 
				
			||||||
 | 
								[](void *p_user, bool p_enable, const Array &p_opts) {
 | 
				
			||||||
 | 
									static_cast<ScriptsProfiler *>(p_user)->toggle(p_enable, p_opts);
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nullptr,
 | 
				
			||||||
 | 
								[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
 | 
				
			||||||
 | 
									static_cast<ScriptsProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
						register_profiler("scripts", scr_prof);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LocalDebugger::~LocalDebugger() {
 | 
				
			||||||
 | 
						unregister_profiler("scripts");
 | 
				
			||||||
 | 
						if (scripts_profiler) {
 | 
				
			||||||
 | 
							memdelete(scripts_profiler);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								engine/core/debugger/local_debugger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								engine/core/debugger/local_debugger.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  local_debugger.h                                                      */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef LOCAL_DEBUGGER_H
 | 
				
			||||||
 | 
					#define LOCAL_DEBUGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					#include "core/templates/list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LocalDebugger : public EngineDebugger {
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						struct ScriptsProfiler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ScriptsProfiler *scripts_profiler = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String target_function;
 | 
				
			||||||
 | 
						HashMap<String, String> options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Pair<String, int> to_breakpoint(const String &p_line);
 | 
				
			||||||
 | 
						void print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void debug(bool p_can_continue, bool p_is_error_breakpoint);
 | 
				
			||||||
 | 
						void send_message(const String &p_message, const Array &p_args);
 | 
				
			||||||
 | 
						void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LocalDebugger();
 | 
				
			||||||
 | 
						~LocalDebugger();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // LOCAL_DEBUGGER_H
 | 
				
			||||||
							
								
								
									
										700
									
								
								engine/core/debugger/remote_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										700
									
								
								engine/core/debugger/remote_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,700 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  remote_debugger.cpp                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "remote_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/debugger/debugger_marshalls.h"
 | 
				
			||||||
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
 | 
					#include "core/debugger/engine_profiler.h"
 | 
				
			||||||
 | 
					#include "core/debugger/script_debugger.h"
 | 
				
			||||||
 | 
					#include "core/input/input.h"
 | 
				
			||||||
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "servers/display_server.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
 | 
				
			||||||
 | 
						Object *performance = nullptr;
 | 
				
			||||||
 | 
						int last_perf_time = 0;
 | 
				
			||||||
 | 
						uint64_t last_monitor_modification_time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void toggle(bool p_enable, const Array &p_opts) {}
 | 
				
			||||||
 | 
						void add(const Array &p_data) {}
 | 
				
			||||||
 | 
						void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
 | 
				
			||||||
 | 
							if (!performance) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t pt = OS::get_singleton()->get_ticks_msec();
 | 
				
			||||||
 | 
							if (pt - last_perf_time < 1000) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							last_perf_time = pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Array custom_monitor_names = performance->call("get_custom_monitor_names");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t monitor_modification_time = performance->call("get_monitor_modification_time");
 | 
				
			||||||
 | 
							if (monitor_modification_time > last_monitor_modification_time) {
 | 
				
			||||||
 | 
								last_monitor_modification_time = monitor_modification_time;
 | 
				
			||||||
 | 
								EngineDebugger::get_singleton()->send_message("performance:profile_names", custom_monitor_names);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int max = performance->get("MONITOR_MAX");
 | 
				
			||||||
 | 
							Array arr;
 | 
				
			||||||
 | 
							arr.resize(max + custom_monitor_names.size());
 | 
				
			||||||
 | 
							for (int i = 0; i < max; i++) {
 | 
				
			||||||
 | 
								arr[i] = performance->call("get_monitor", i);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < custom_monitor_names.size(); i++) {
 | 
				
			||||||
 | 
								Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]);
 | 
				
			||||||
 | 
								if (!monitor_value.is_num()) {
 | 
				
			||||||
 | 
									ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number");
 | 
				
			||||||
 | 
									arr[i + max] = Variant();
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									arr[i + max] = monitor_value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						explicit PerformanceProfiler(Object *p_performance) {
 | 
				
			||||||
 | 
							performance = p_performance;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebugger::_put_msg(const String &p_message, const Array &p_data) {
 | 
				
			||||||
 | 
						Array msg;
 | 
				
			||||||
 | 
						msg.push_back(p_message);
 | 
				
			||||||
 | 
						msg.push_back(Thread::get_caller_id());
 | 
				
			||||||
 | 
						msg.push_back(p_data);
 | 
				
			||||||
 | 
						Error err = peer->put_message(msg);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							n_messages_dropped++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						if (p_type == ERR_HANDLER_SCRIPT) {
 | 
				
			||||||
 | 
							return; //ignore script errors, those go through debugger
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
 | 
				
			||||||
 | 
						if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive errors during flush.
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<ScriptLanguage::StackInfo> si;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
							si = ScriptServer::get_language(i)->debug_get_current_stack_info();
 | 
				
			||||||
 | 
							if (si.size()) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// send_error will lock internally.
 | 
				
			||||||
 | 
						rd->script_debugger->send_error(String::utf8(p_func), String::utf8(p_file), p_line, String::utf8(p_err), String::utf8(p_descr), p_editor_notify, p_type, si);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich) {
 | 
				
			||||||
 | 
						RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush.
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String s = p_string;
 | 
				
			||||||
 | 
						int allowed_chars = MIN(MAX(rd->max_chars_per_second - rd->char_count, 0), s.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (allowed_chars == 0 && s.length() > 0) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (allowed_chars < s.length()) {
 | 
				
			||||||
 | 
							s = s.substr(0, allowed_chars);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MutexLock lock(rd->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rd->char_count += allowed_chars;
 | 
				
			||||||
 | 
						bool overflowed = rd->char_count >= rd->max_chars_per_second;
 | 
				
			||||||
 | 
						if (rd->is_peer_connected()) {
 | 
				
			||||||
 | 
							if (overflowed) {
 | 
				
			||||||
 | 
								s += "[...]";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OutputString output_string;
 | 
				
			||||||
 | 
							output_string.message = s;
 | 
				
			||||||
 | 
							if (p_error) {
 | 
				
			||||||
 | 
								output_string.type = MESSAGE_TYPE_ERROR;
 | 
				
			||||||
 | 
							} else if (p_rich) {
 | 
				
			||||||
 | 
								output_string.type = MESSAGE_TYPE_LOG_RICH;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								output_string.type = MESSAGE_TYPE_LOG;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rd->output_strings.push_back(output_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (overflowed) {
 | 
				
			||||||
 | 
								output_string.message = "[output overflow, print less text!]";
 | 
				
			||||||
 | 
								output_string.type = MESSAGE_TYPE_ERROR;
 | 
				
			||||||
 | 
								rd->output_strings.push_back(output_string);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebugger::ErrorMessage RemoteDebugger::_create_overflow_error(const String &p_what, const String &p_descr) {
 | 
				
			||||||
 | 
						ErrorMessage oe;
 | 
				
			||||||
 | 
						oe.error = p_what;
 | 
				
			||||||
 | 
						oe.error_descr = p_descr;
 | 
				
			||||||
 | 
						oe.warning = false;
 | 
				
			||||||
 | 
						uint64_t time = OS::get_singleton()->get_ticks_msec();
 | 
				
			||||||
 | 
						oe.hr = time / 3600000;
 | 
				
			||||||
 | 
						oe.min = (time / 60000) % 60;
 | 
				
			||||||
 | 
						oe.sec = (time / 1000) % 60;
 | 
				
			||||||
 | 
						oe.msec = time % 1000;
 | 
				
			||||||
 | 
						return oe;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::flush_output() {
 | 
				
			||||||
 | 
						MutexLock lock(mutex);
 | 
				
			||||||
 | 
						flush_thread = Thread::get_caller_id();
 | 
				
			||||||
 | 
						flushing = true;
 | 
				
			||||||
 | 
						if (!is_peer_connected()) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (n_messages_dropped > 0) {
 | 
				
			||||||
 | 
							ErrorMessage err_msg = _create_overflow_error("TOO_MANY_MESSAGES", "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped. Profiling might misbheave, try raising 'network/limits/debugger/max_queued_messages' in project setting.");
 | 
				
			||||||
 | 
							if (_put_msg("error", err_msg.serialize()) == OK) {
 | 
				
			||||||
 | 
								n_messages_dropped = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (output_strings.size()) {
 | 
				
			||||||
 | 
							// Join output strings so we generate less messages.
 | 
				
			||||||
 | 
							Vector<String> joined_log_strings;
 | 
				
			||||||
 | 
							Vector<String> strings;
 | 
				
			||||||
 | 
							Vector<int> types;
 | 
				
			||||||
 | 
							for (const OutputString &output_string : output_strings) {
 | 
				
			||||||
 | 
								if (output_string.type == MESSAGE_TYPE_ERROR) {
 | 
				
			||||||
 | 
									if (!joined_log_strings.is_empty()) {
 | 
				
			||||||
 | 
										strings.push_back(String("\n").join(joined_log_strings));
 | 
				
			||||||
 | 
										types.push_back(MESSAGE_TYPE_LOG);
 | 
				
			||||||
 | 
										joined_log_strings.clear();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									strings.push_back(output_string.message);
 | 
				
			||||||
 | 
									types.push_back(MESSAGE_TYPE_ERROR);
 | 
				
			||||||
 | 
								} else if (output_string.type == MESSAGE_TYPE_LOG_RICH) {
 | 
				
			||||||
 | 
									if (!joined_log_strings.is_empty()) {
 | 
				
			||||||
 | 
										strings.push_back(String("\n").join(joined_log_strings));
 | 
				
			||||||
 | 
										types.push_back(MESSAGE_TYPE_LOG_RICH);
 | 
				
			||||||
 | 
										joined_log_strings.clear();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									strings.push_back(output_string.message);
 | 
				
			||||||
 | 
									types.push_back(MESSAGE_TYPE_LOG_RICH);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									joined_log_strings.push_back(output_string.message);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!joined_log_strings.is_empty()) {
 | 
				
			||||||
 | 
								strings.push_back(String("\n").join(joined_log_strings));
 | 
				
			||||||
 | 
								types.push_back(MESSAGE_TYPE_LOG);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Array arr;
 | 
				
			||||||
 | 
							arr.push_back(strings);
 | 
				
			||||||
 | 
							arr.push_back(types);
 | 
				
			||||||
 | 
							_put_msg("output", arr);
 | 
				
			||||||
 | 
							output_strings.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (errors.size()) {
 | 
				
			||||||
 | 
							ErrorMessage oe = errors.front()->get();
 | 
				
			||||||
 | 
							_put_msg("error", oe.serialize());
 | 
				
			||||||
 | 
							errors.pop_front();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Update limits
 | 
				
			||||||
 | 
						uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ticks - last_reset > 1000) {
 | 
				
			||||||
 | 
							last_reset = ticks;
 | 
				
			||||||
 | 
							char_count = 0;
 | 
				
			||||||
 | 
							err_count = 0;
 | 
				
			||||||
 | 
							n_errors_dropped = 0;
 | 
				
			||||||
 | 
							warn_count = 0;
 | 
				
			||||||
 | 
							n_warnings_dropped = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						flushing = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::send_message(const String &p_message, const Array &p_args) {
 | 
				
			||||||
 | 
						MutexLock lock(mutex);
 | 
				
			||||||
 | 
						if (is_peer_connected()) {
 | 
				
			||||||
 | 
							_put_msg(p_message, p_args);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						ErrorMessage oe;
 | 
				
			||||||
 | 
						oe.error = p_err;
 | 
				
			||||||
 | 
						oe.error_descr = p_descr;
 | 
				
			||||||
 | 
						oe.source_file = p_file;
 | 
				
			||||||
 | 
						oe.source_line = p_line;
 | 
				
			||||||
 | 
						oe.source_func = p_func;
 | 
				
			||||||
 | 
						oe.warning = p_type == ERR_HANDLER_WARNING;
 | 
				
			||||||
 | 
						uint64_t time = OS::get_singleton()->get_ticks_msec();
 | 
				
			||||||
 | 
						oe.hr = time / 3600000;
 | 
				
			||||||
 | 
						oe.min = (time / 60000) % 60;
 | 
				
			||||||
 | 
						oe.sec = (time / 1000) % 60;
 | 
				
			||||||
 | 
						oe.msec = time % 1000;
 | 
				
			||||||
 | 
						oe.callstack.append_array(script_debugger->get_error_stack_info());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flushing && Thread::get_caller_id() == flush_thread) { // Can't handle recursive errors during flush.
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MutexLock lock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (oe.warning) {
 | 
				
			||||||
 | 
							warn_count++;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err_count++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_peer_connected()) {
 | 
				
			||||||
 | 
							if (oe.warning) {
 | 
				
			||||||
 | 
								if (warn_count > max_warnings_per_second) {
 | 
				
			||||||
 | 
									n_warnings_dropped++;
 | 
				
			||||||
 | 
									if (n_warnings_dropped == 1) {
 | 
				
			||||||
 | 
										// Only print one message about dropping per second
 | 
				
			||||||
 | 
										ErrorMessage overflow = _create_overflow_error("TOO_MANY_WARNINGS", "Too many warnings! Ignoring warnings for up to 1 second.");
 | 
				
			||||||
 | 
										errors.push_back(overflow);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									errors.push_back(oe);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (err_count > max_errors_per_second) {
 | 
				
			||||||
 | 
									n_errors_dropped++;
 | 
				
			||||||
 | 
									if (n_errors_dropped == 1) {
 | 
				
			||||||
 | 
										// Only print one message about dropping per second
 | 
				
			||||||
 | 
										ErrorMessage overflow = _create_overflow_error("TOO_MANY_ERRORS", "Too many errors! Ignoring errors for up to 1 second.");
 | 
				
			||||||
 | 
										errors.push_back(overflow);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									errors.push_back(oe);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type) {
 | 
				
			||||||
 | 
						DebuggerMarshalls::ScriptStackVariable stvar;
 | 
				
			||||||
 | 
						List<String>::Element *E = p_names.front();
 | 
				
			||||||
 | 
						List<Variant>::Element *F = p_vals.front();
 | 
				
			||||||
 | 
						while (E) {
 | 
				
			||||||
 | 
							stvar.name = E->get();
 | 
				
			||||||
 | 
							stvar.value = F->get();
 | 
				
			||||||
 | 
							stvar.type = p_type;
 | 
				
			||||||
 | 
							send_message("stack_frame_var", stvar.serialize());
 | 
				
			||||||
 | 
							E = E->next();
 | 
				
			||||||
 | 
							F = F->next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
 | 
						const int idx = p_msg.find(":");
 | 
				
			||||||
 | 
						r_captured = false;
 | 
				
			||||||
 | 
						if (idx < 0) { // No prefix, unknown message.
 | 
				
			||||||
 | 
							return OK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const String cap = p_msg.substr(0, idx);
 | 
				
			||||||
 | 
						if (!has_capture(cap)) {
 | 
				
			||||||
 | 
							return ERR_UNAVAILABLE; // Unknown message...
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const String msg = p_msg.substr(idx + 1);
 | 
				
			||||||
 | 
						return capture_parse(cap, msg, p_data, r_captured);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::_poll_messages() {
 | 
				
			||||||
 | 
						MutexLock mutex_lock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						peer->poll();
 | 
				
			||||||
 | 
						while (peer->has_message()) {
 | 
				
			||||||
 | 
							Array cmd = peer->get_message();
 | 
				
			||||||
 | 
							ERR_CONTINUE(cmd.size() != 3);
 | 
				
			||||||
 | 
							ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
 | 
				
			||||||
 | 
							ERR_CONTINUE(cmd[1].get_type() != Variant::INT);
 | 
				
			||||||
 | 
							ERR_CONTINUE(cmd[2].get_type() != Variant::ARRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Thread::ID thread = cmd[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!messages.has(thread)) {
 | 
				
			||||||
 | 
								continue; // This thread is not around to receive the messages
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Message msg;
 | 
				
			||||||
 | 
							msg.message = cmd[0];
 | 
				
			||||||
 | 
							msg.data = cmd[2];
 | 
				
			||||||
 | 
							messages[thread].push_back(msg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RemoteDebugger::_has_messages() {
 | 
				
			||||||
 | 
						MutexLock mutex_lock(mutex);
 | 
				
			||||||
 | 
						return messages.has(Thread::get_caller_id()) && !messages[Thread::get_caller_id()].is_empty();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array RemoteDebugger::_get_message() {
 | 
				
			||||||
 | 
						MutexLock mutex_lock(mutex);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!messages.has(Thread::get_caller_id()), Array());
 | 
				
			||||||
 | 
						List<Message> &message_list = messages[Thread::get_caller_id()];
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(message_list.is_empty(), Array());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Array msg;
 | 
				
			||||||
 | 
						msg.resize(2);
 | 
				
			||||||
 | 
						msg[0] = message_list.front()->get().message;
 | 
				
			||||||
 | 
						msg[1] = message_list.front()->get().data;
 | 
				
			||||||
 | 
						message_list.pop_front();
 | 
				
			||||||
 | 
						return msg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
 | 
						//this function is called when there is a debugger break (bug on script)
 | 
				
			||||||
 | 
						//or when execution is paused from editor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							MutexLock lock(mutex);
 | 
				
			||||||
 | 
							// Tests that require mutex.
 | 
				
			||||||
 | 
							if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!peer->can_block()) {
 | 
				
			||||||
 | 
								return; // Peer does not support blocking IO. We could at least send the error though.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ScriptLanguage *script_lang = script_debugger->get_break_language();
 | 
				
			||||||
 | 
						const String error_str = script_lang ? script_lang->debug_get_error() : "";
 | 
				
			||||||
 | 
						Array msg;
 | 
				
			||||||
 | 
						msg.push_back(p_can_continue);
 | 
				
			||||||
 | 
						msg.push_back(error_str);
 | 
				
			||||||
 | 
						ERR_FAIL_NULL(script_lang);
 | 
				
			||||||
 | 
						msg.push_back(script_lang->debug_get_stack_level_count() > 0);
 | 
				
			||||||
 | 
						msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id()));
 | 
				
			||||||
 | 
						if (allow_focus_steal_fn) {
 | 
				
			||||||
 | 
							allow_focus_steal_fn();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						send_message("debug_enter", msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (Thread::get_caller_id() == Thread::get_main_id()) {
 | 
				
			||||||
 | 
							mouse_mode = Input::get_singleton()->get_mouse_mode();
 | 
				
			||||||
 | 
							if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
 | 
				
			||||||
 | 
								Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							MutexLock mutex_lock(mutex);
 | 
				
			||||||
 | 
							messages.insert(Thread::get_caller_id(), List<Message>());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (is_peer_connected()) {
 | 
				
			||||||
 | 
							flush_output();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_poll_messages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (_has_messages()) {
 | 
				
			||||||
 | 
								Array cmd = _get_message();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ERR_CONTINUE(cmd.size() != 2);
 | 
				
			||||||
 | 
								ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
 | 
				
			||||||
 | 
								ERR_CONTINUE(cmd[1].get_type() != Variant::ARRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								String command = cmd[0];
 | 
				
			||||||
 | 
								Array data = cmd[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (command == "step") {
 | 
				
			||||||
 | 
									script_debugger->set_depth(-1);
 | 
				
			||||||
 | 
									script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "next") {
 | 
				
			||||||
 | 
									script_debugger->set_depth(0);
 | 
				
			||||||
 | 
									script_debugger->set_lines_left(1);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "continue") {
 | 
				
			||||||
 | 
									script_debugger->set_depth(-1);
 | 
				
			||||||
 | 
									script_debugger->set_lines_left(-1);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "break") {
 | 
				
			||||||
 | 
									ERR_PRINT("Got break when already broke!");
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "get_stack_dump") {
 | 
				
			||||||
 | 
									DebuggerMarshalls::ScriptStackDump dump;
 | 
				
			||||||
 | 
									int slc = script_lang->debug_get_stack_level_count();
 | 
				
			||||||
 | 
									for (int i = 0; i < slc; i++) {
 | 
				
			||||||
 | 
										ScriptLanguage::StackInfo frame;
 | 
				
			||||||
 | 
										frame.file = script_lang->debug_get_stack_level_source(i);
 | 
				
			||||||
 | 
										frame.line = script_lang->debug_get_stack_level_line(i);
 | 
				
			||||||
 | 
										frame.func = script_lang->debug_get_stack_level_function(i);
 | 
				
			||||||
 | 
										dump.frames.push_back(frame);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									send_message("stack_dump", dump.serialize());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "get_stack_frame_vars") {
 | 
				
			||||||
 | 
									ERR_FAIL_COND(data.size() != 1);
 | 
				
			||||||
 | 
									ERR_FAIL_NULL(script_lang);
 | 
				
			||||||
 | 
									int lv = data[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									List<String> members;
 | 
				
			||||||
 | 
									List<Variant> member_vals;
 | 
				
			||||||
 | 
									if (ScriptInstance *inst = script_lang->debug_get_stack_level_instance(lv)) {
 | 
				
			||||||
 | 
										members.push_back("self");
 | 
				
			||||||
 | 
										member_vals.push_back(inst->get_owner());
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									script_lang->debug_get_stack_level_members(lv, &members, &member_vals);
 | 
				
			||||||
 | 
									ERR_FAIL_COND(members.size() != member_vals.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									List<String> locals;
 | 
				
			||||||
 | 
									List<Variant> local_vals;
 | 
				
			||||||
 | 
									script_lang->debug_get_stack_level_locals(lv, &locals, &local_vals);
 | 
				
			||||||
 | 
									ERR_FAIL_COND(locals.size() != local_vals.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									List<String> globals;
 | 
				
			||||||
 | 
									List<Variant> globals_vals;
 | 
				
			||||||
 | 
									script_lang->debug_get_globals(&globals, &globals_vals);
 | 
				
			||||||
 | 
									ERR_FAIL_COND(globals.size() != globals_vals.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Array var_size;
 | 
				
			||||||
 | 
									var_size.push_back(local_vals.size() + member_vals.size() + globals_vals.size());
 | 
				
			||||||
 | 
									send_message("stack_frame_vars", var_size);
 | 
				
			||||||
 | 
									_send_stack_vars(locals, local_vals, 0);
 | 
				
			||||||
 | 
									_send_stack_vars(members, member_vals, 1);
 | 
				
			||||||
 | 
									_send_stack_vars(globals, globals_vals, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "reload_scripts") {
 | 
				
			||||||
 | 
									script_paths_to_reload = data;
 | 
				
			||||||
 | 
								} else if (command == "reload_all_scripts") {
 | 
				
			||||||
 | 
									reload_all_scripts = true;
 | 
				
			||||||
 | 
								} else if (command == "breakpoint") {
 | 
				
			||||||
 | 
									ERR_FAIL_COND(data.size() < 3);
 | 
				
			||||||
 | 
									bool set = data[2];
 | 
				
			||||||
 | 
									if (set) {
 | 
				
			||||||
 | 
										script_debugger->insert_breakpoint(data[1], data[0]);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										script_debugger->remove_breakpoint(data[1], data[0]);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if (command == "set_skip_breakpoints") {
 | 
				
			||||||
 | 
									ERR_FAIL_COND(data.is_empty());
 | 
				
			||||||
 | 
									script_debugger->set_skip_breakpoints(data[0]);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									bool captured = false;
 | 
				
			||||||
 | 
									ERR_CONTINUE(_try_capture(command, data, captured) != OK);
 | 
				
			||||||
 | 
									if (!captured) {
 | 
				
			||||||
 | 
										WARN_PRINT("Unknown message received from debugger: " + command);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								OS::get_singleton()->delay_usec(10000);
 | 
				
			||||||
 | 
								if (Thread::get_caller_id() == Thread::get_main_id()) {
 | 
				
			||||||
 | 
									// If this is a busy loop on the main thread, events still need to be processed.
 | 
				
			||||||
 | 
									DisplayServer::get_singleton()->force_process_and_drop_events();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						send_message("debug_exit", Array());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (Thread::get_caller_id() == Thread::get_main_id()) {
 | 
				
			||||||
 | 
							if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
 | 
				
			||||||
 | 
								Input::get_singleton()->set_mouse_mode(mouse_mode);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							MutexLock mutex_lock(mutex);
 | 
				
			||||||
 | 
							messages.erase(Thread::get_caller_id());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebugger::poll_events(bool p_is_idle) {
 | 
				
			||||||
 | 
						if (peer.is_null()) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flush_output();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_poll_messages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (_has_messages()) {
 | 
				
			||||||
 | 
							Array arr = _get_message();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ERR_CONTINUE(arr.size() != 2);
 | 
				
			||||||
 | 
							ERR_CONTINUE(arr[0].get_type() != Variant::STRING);
 | 
				
			||||||
 | 
							ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const String cmd = arr[0];
 | 
				
			||||||
 | 
							const int idx = cmd.find(":");
 | 
				
			||||||
 | 
							bool parsed = false;
 | 
				
			||||||
 | 
							if (idx < 0) { // Not prefix, use scripts capture.
 | 
				
			||||||
 | 
								capture_parse("core", cmd, arr[1], parsed);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const String cap = cmd.substr(0, idx);
 | 
				
			||||||
 | 
							if (!has_capture(cap)) {
 | 
				
			||||||
 | 
								continue; // Unknown message...
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const String msg = cmd.substr(idx + 1);
 | 
				
			||||||
 | 
							capture_parse(cap, msg, arr[1], parsed);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reload scripts during idle poll only.
 | 
				
			||||||
 | 
						if (p_is_idle) {
 | 
				
			||||||
 | 
							if (reload_all_scripts) {
 | 
				
			||||||
 | 
								for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
									ScriptServer::get_language(i)->reload_all_scripts();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								reload_all_scripts = false;
 | 
				
			||||||
 | 
							} else if (!script_paths_to_reload.is_empty()) {
 | 
				
			||||||
 | 
								Array scripts_to_reload;
 | 
				
			||||||
 | 
								for (int i = 0; i < script_paths_to_reload.size(); ++i) {
 | 
				
			||||||
 | 
									String path = script_paths_to_reload[i];
 | 
				
			||||||
 | 
									Error err = OK;
 | 
				
			||||||
 | 
									Ref<Script> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
 | 
				
			||||||
 | 
									ERR_CONTINUE_MSG(err != OK, vformat("Could not reload script '%s': %s", path, error_names[err]));
 | 
				
			||||||
 | 
									ERR_CONTINUE_MSG(script.is_null(), vformat("Could not reload script '%s': Not a script!", path, error_names[err]));
 | 
				
			||||||
 | 
									scripts_to_reload.push_back(script);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
									ScriptServer::get_language(i)->reload_scripts(scripts_to_reload, true);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							script_paths_to_reload.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
 | 
						r_captured = true;
 | 
				
			||||||
 | 
						if (p_cmd == "reload_scripts") {
 | 
				
			||||||
 | 
							script_paths_to_reload = p_data;
 | 
				
			||||||
 | 
						} else if (p_cmd == "reload_all_scripts") {
 | 
				
			||||||
 | 
							reload_all_scripts = true;
 | 
				
			||||||
 | 
						} else if (p_cmd == "breakpoint") {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(p_data.size() < 3, ERR_INVALID_DATA);
 | 
				
			||||||
 | 
							bool set = p_data[2];
 | 
				
			||||||
 | 
							if (set) {
 | 
				
			||||||
 | 
								script_debugger->insert_breakpoint(p_data[1], p_data[0]);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								script_debugger->remove_breakpoint(p_data[1], p_data[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else if (p_cmd == "set_skip_breakpoints") {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
 | 
				
			||||||
 | 
							script_debugger->set_skip_breakpoints(p_data[0]);
 | 
				
			||||||
 | 
						} else if (p_cmd == "break") {
 | 
				
			||||||
 | 
							script_debugger->debug(script_debugger->get_break_language());
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							r_captured = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
 | 
						r_captured = false;
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(p_data[0].get_type() != Variant::BOOL, ERR_INVALID_DATA);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!has_profiler(p_cmd), ERR_UNAVAILABLE);
 | 
				
			||||||
 | 
						Array opts;
 | 
				
			||||||
 | 
						if (p_data.size() > 1) { // Optional profiler parameters.
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(p_data[1].get_type() != Variant::ARRAY, ERR_INVALID_DATA);
 | 
				
			||||||
 | 
							opts = p_data[1];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						r_captured = true;
 | 
				
			||||||
 | 
						profiler_enable(p_cmd, p_data[0], opts);
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
 | 
				
			||||||
 | 
						peer = p_peer;
 | 
				
			||||||
 | 
						max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second");
 | 
				
			||||||
 | 
						max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second");
 | 
				
			||||||
 | 
						max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Performance Profiler
 | 
				
			||||||
 | 
						Object *perf = Engine::get_singleton()->get_singleton_object("Performance");
 | 
				
			||||||
 | 
						if (perf) {
 | 
				
			||||||
 | 
							performance_profiler.instantiate(perf);
 | 
				
			||||||
 | 
							performance_profiler->bind("performance");
 | 
				
			||||||
 | 
							profiler_enable("performance", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Core and profiler captures.
 | 
				
			||||||
 | 
						Capture core_cap(this,
 | 
				
			||||||
 | 
								[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
 | 
									return static_cast<RemoteDebugger *>(p_user)->_core_capture(p_cmd, p_data, r_captured);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
						register_message_capture("core", core_cap);
 | 
				
			||||||
 | 
						Capture profiler_cap(this,
 | 
				
			||||||
 | 
								[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
 | 
				
			||||||
 | 
									return static_cast<RemoteDebugger *>(p_user)->_profiler_capture(p_cmd, p_data, r_captured);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
						register_message_capture("profiler", profiler_cap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Error handlers
 | 
				
			||||||
 | 
						phl.printfunc = _print_handler;
 | 
				
			||||||
 | 
						phl.userdata = this;
 | 
				
			||||||
 | 
						add_print_handler(&phl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						eh.errfunc = _err_handler;
 | 
				
			||||||
 | 
						eh.userdata = this;
 | 
				
			||||||
 | 
						add_error_handler(&eh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						messages.insert(Thread::get_main_id(), List<Message>());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebugger::~RemoteDebugger() {
 | 
				
			||||||
 | 
						remove_print_handler(&phl);
 | 
				
			||||||
 | 
						remove_error_handler(&eh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										126
									
								
								engine/core/debugger/remote_debugger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								engine/core/debugger/remote_debugger.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  remote_debugger.h                                                     */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef REMOTE_DEBUGGER_H
 | 
				
			||||||
 | 
					#define REMOTE_DEBUGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/debugger_marshalls.h"
 | 
				
			||||||
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
 | 
					#include "core/debugger/remote_debugger_peer.h"
 | 
				
			||||||
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					#include "core/variant/array.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoteDebugger : public EngineDebugger {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum MessageType {
 | 
				
			||||||
 | 
							MESSAGE_TYPE_LOG,
 | 
				
			||||||
 | 
							MESSAGE_TYPE_ERROR,
 | 
				
			||||||
 | 
							MESSAGE_TYPE_LOG_RICH,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						typedef DebuggerMarshalls::OutputError ErrorMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class PerformanceProfiler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<PerformanceProfiler> performance_profiler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<RemoteDebuggerPeer> peer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct OutputString {
 | 
				
			||||||
 | 
							String message;
 | 
				
			||||||
 | 
							MessageType type;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						List<OutputString> output_strings;
 | 
				
			||||||
 | 
						List<ErrorMessage> errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int n_messages_dropped = 0;
 | 
				
			||||||
 | 
						int max_errors_per_second = 0;
 | 
				
			||||||
 | 
						int max_chars_per_second = 0;
 | 
				
			||||||
 | 
						int max_warnings_per_second = 0;
 | 
				
			||||||
 | 
						int n_errors_dropped = 0;
 | 
				
			||||||
 | 
						int n_warnings_dropped = 0;
 | 
				
			||||||
 | 
						int char_count = 0;
 | 
				
			||||||
 | 
						int err_count = 0;
 | 
				
			||||||
 | 
						int warn_count = 0;
 | 
				
			||||||
 | 
						int last_reset = 0;
 | 
				
			||||||
 | 
						bool reload_all_scripts = false;
 | 
				
			||||||
 | 
						Array script_paths_to_reload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make handlers and send_message thread safe.
 | 
				
			||||||
 | 
						Mutex mutex;
 | 
				
			||||||
 | 
						bool flushing = false;
 | 
				
			||||||
 | 
						Thread::ID flush_thread = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Message {
 | 
				
			||||||
 | 
							String message;
 | 
				
			||||||
 | 
							Array data;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<Thread::ID, List<Message>> messages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _poll_messages();
 | 
				
			||||||
 | 
						bool _has_messages();
 | 
				
			||||||
 | 
						Array _get_message();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PrintHandlerList phl;
 | 
				
			||||||
 | 
						static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich);
 | 
				
			||||||
 | 
						ErrorHandlerList eh;
 | 
				
			||||||
 | 
						static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ErrorMessage _create_overflow_error(const String &p_what, const String &p_descr);
 | 
				
			||||||
 | 
						Error _put_msg(const String &p_message, const Array &p_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_peer_connected() { return peer->is_peer_connected(); }
 | 
				
			||||||
 | 
						void flush_output();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
 | 
				
			||||||
 | 
						Error _core_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename T>
 | 
				
			||||||
 | 
						void _bind_profiler(const String &p_name, T *p_prof);
 | 
				
			||||||
 | 
						Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						// Overrides
 | 
				
			||||||
 | 
						void poll_events(bool p_is_idle);
 | 
				
			||||||
 | 
						void send_message(const String &p_message, const Array &p_args);
 | 
				
			||||||
 | 
						void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
 | 
				
			||||||
 | 
						void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
 | 
				
			||||||
 | 
						~RemoteDebugger();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // REMOTE_DEBUGGER_H
 | 
				
			||||||
							
								
								
									
										244
									
								
								engine/core/debugger/remote_debugger_peer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								engine/core/debugger/remote_debugger_peer.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,244 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  remote_debugger_peer.cpp                                              */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "remote_debugger_peer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/io/marshalls.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RemoteDebuggerPeerTCP::is_peer_connected() {
 | 
				
			||||||
 | 
						return connected;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RemoteDebuggerPeerTCP::has_message() {
 | 
				
			||||||
 | 
						return in_queue.size() > 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array RemoteDebuggerPeerTCP::get_message() {
 | 
				
			||||||
 | 
						MutexLock lock(mutex);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!has_message(), Array());
 | 
				
			||||||
 | 
						Array out = in_queue.front()->get();
 | 
				
			||||||
 | 
						in_queue.pop_front();
 | 
				
			||||||
 | 
						return out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebuggerPeerTCP::put_message(const Array &p_arr) {
 | 
				
			||||||
 | 
						MutexLock lock(mutex);
 | 
				
			||||||
 | 
						if (out_queue.size() >= max_queued_messages) {
 | 
				
			||||||
 | 
							return ERR_OUT_OF_MEMORY;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out_queue.push_back(p_arr);
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int RemoteDebuggerPeerTCP::get_max_message_size() const {
 | 
				
			||||||
 | 
						return 8 << 20; // 8 MiB
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::close() {
 | 
				
			||||||
 | 
						running = false;
 | 
				
			||||||
 | 
						if (thread.is_started()) {
 | 
				
			||||||
 | 
							thread.wait_to_finish();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tcp_client->disconnect_from_host();
 | 
				
			||||||
 | 
						out_buf.clear();
 | 
				
			||||||
 | 
						in_buf.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
 | 
				
			||||||
 | 
						// This means remote debugger takes 16 MiB just because it exists...
 | 
				
			||||||
 | 
						in_buf.resize((8 << 20) + 4); // 8 MiB should be way more than enough (need 4 extra bytes for encoding packet size).
 | 
				
			||||||
 | 
						out_buf.resize(8 << 20); // 8 MiB should be way more than enough
 | 
				
			||||||
 | 
						tcp_client = p_tcp;
 | 
				
			||||||
 | 
						if (tcp_client.is_valid()) { // Attaching to an already connected stream.
 | 
				
			||||||
 | 
							connected = true;
 | 
				
			||||||
 | 
							running = true;
 | 
				
			||||||
 | 
							thread.start(_thread_func, this);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							tcp_client.instantiate();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebuggerPeerTCP::~RemoteDebuggerPeerTCP() {
 | 
				
			||||||
 | 
						close();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::_write_out() {
 | 
				
			||||||
 | 
						while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) {
 | 
				
			||||||
 | 
							uint8_t *buf = out_buf.ptrw();
 | 
				
			||||||
 | 
							if (out_left <= 0) {
 | 
				
			||||||
 | 
								if (out_queue.size() == 0) {
 | 
				
			||||||
 | 
									break; // Nothing left to send
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								mutex.lock();
 | 
				
			||||||
 | 
								Variant var = out_queue.front()->get();
 | 
				
			||||||
 | 
								out_queue.pop_front();
 | 
				
			||||||
 | 
								mutex.unlock();
 | 
				
			||||||
 | 
								int size = 0;
 | 
				
			||||||
 | 
								Error err = encode_variant(var, nullptr, size);
 | 
				
			||||||
 | 
								ERR_CONTINUE(err != OK || size > out_buf.size() - 4); // 4 bytes separator.
 | 
				
			||||||
 | 
								encode_uint32(size, buf);
 | 
				
			||||||
 | 
								encode_variant(var, buf + 4, size);
 | 
				
			||||||
 | 
								out_left = size + 4;
 | 
				
			||||||
 | 
								out_pos = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							int sent = 0;
 | 
				
			||||||
 | 
							tcp_client->put_partial_data(buf + out_pos, out_left, sent);
 | 
				
			||||||
 | 
							out_left -= sent;
 | 
				
			||||||
 | 
							out_pos += sent;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::_read_in() {
 | 
				
			||||||
 | 
						while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_IN) == OK) {
 | 
				
			||||||
 | 
							uint8_t *buf = in_buf.ptrw();
 | 
				
			||||||
 | 
							if (in_left <= 0) {
 | 
				
			||||||
 | 
								if (in_queue.size() > max_queued_messages) {
 | 
				
			||||||
 | 
									break; // Too many messages already in queue.
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (tcp_client->get_available_bytes() < 4) {
 | 
				
			||||||
 | 
									break; // Need 4 more bytes.
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								uint32_t size = 0;
 | 
				
			||||||
 | 
								int read = 0;
 | 
				
			||||||
 | 
								Error err = tcp_client->get_partial_data((uint8_t *)&size, 4, read);
 | 
				
			||||||
 | 
								ERR_CONTINUE(read != 4 || err != OK || size > (uint32_t)in_buf.size());
 | 
				
			||||||
 | 
								in_left = size;
 | 
				
			||||||
 | 
								in_pos = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							int read = 0;
 | 
				
			||||||
 | 
							tcp_client->get_partial_data(buf + in_pos, in_left, read);
 | 
				
			||||||
 | 
							in_left -= read;
 | 
				
			||||||
 | 
							in_pos += read;
 | 
				
			||||||
 | 
							if (in_left == 0) {
 | 
				
			||||||
 | 
								Variant var;
 | 
				
			||||||
 | 
								Error err = decode_variant(var, buf, in_pos, &read);
 | 
				
			||||||
 | 
								ERR_CONTINUE(read != in_pos || err != OK);
 | 
				
			||||||
 | 
								ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
 | 
				
			||||||
 | 
								mutex.lock();
 | 
				
			||||||
 | 
								in_queue.push_back(var);
 | 
				
			||||||
 | 
								mutex.unlock();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
 | 
				
			||||||
 | 
						IPAddress ip;
 | 
				
			||||||
 | 
						if (p_host.is_valid_ip_address()) {
 | 
				
			||||||
 | 
							ip = p_host;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ip = IP::get_singleton()->resolve_hostname(p_host);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int port = p_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const int tries = 6;
 | 
				
			||||||
 | 
						const int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_client->connect_to_host(ip, port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < tries; i++) {
 | 
				
			||||||
 | 
							tcp_client->poll();
 | 
				
			||||||
 | 
							if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
 | 
				
			||||||
 | 
								print_verbose("Remote Debugger: Connected!");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								const int ms = waits[i];
 | 
				
			||||||
 | 
								OS::get_singleton()->delay_usec(ms * 1000);
 | 
				
			||||||
 | 
								print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
 | 
				
			||||||
 | 
							ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + ".");
 | 
				
			||||||
 | 
							return FAILED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						connected = true;
 | 
				
			||||||
 | 
						running = true;
 | 
				
			||||||
 | 
						thread.start(_thread_func, this);
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
 | 
				
			||||||
 | 
						// Update in time for 144hz monitors
 | 
				
			||||||
 | 
						const uint64_t min_tick = 6900;
 | 
				
			||||||
 | 
						RemoteDebuggerPeerTCP *peer = static_cast<RemoteDebuggerPeerTCP *>(p_ud);
 | 
				
			||||||
 | 
						while (peer->running && peer->is_peer_connected()) {
 | 
				
			||||||
 | 
							uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
 | 
				
			||||||
 | 
							peer->_poll();
 | 
				
			||||||
 | 
							if (!peer->is_peer_connected()) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ticks_usec = OS::get_singleton()->get_ticks_usec() - ticks_usec;
 | 
				
			||||||
 | 
							if (ticks_usec < min_tick) {
 | 
				
			||||||
 | 
								OS::get_singleton()->delay_usec(min_tick - ticks_usec);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::poll() {
 | 
				
			||||||
 | 
						// Nothing to do, polling is done in thread.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoteDebuggerPeerTCP::_poll() {
 | 
				
			||||||
 | 
						tcp_client->poll();
 | 
				
			||||||
 | 
						if (connected) {
 | 
				
			||||||
 | 
							_write_out();
 | 
				
			||||||
 | 
							_read_in();
 | 
				
			||||||
 | 
							connected = tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String debug_host = p_uri.replace("tcp://", "");
 | 
				
			||||||
 | 
						uint16_t debug_port = 6007;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (debug_host.contains(":")) {
 | 
				
			||||||
 | 
							int sep_pos = debug_host.rfind(":");
 | 
				
			||||||
 | 
							debug_port = debug_host.substr(sep_pos + 1).to_int();
 | 
				
			||||||
 | 
							debug_host = debug_host.substr(0, sep_pos);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP);
 | 
				
			||||||
 | 
						Error err = peer->connect_to_host(debug_host, debug_port);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							memdelete(peer);
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return peer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RemoteDebuggerPeer::RemoteDebuggerPeer() {
 | 
				
			||||||
 | 
						max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								engine/core/debugger/remote_debugger_peer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								engine/core/debugger/remote_debugger_peer.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  remote_debugger_peer.h                                                */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef REMOTE_DEBUGGER_PEER_H
 | 
				
			||||||
 | 
					#define REMOTE_DEBUGGER_PEER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/stream_peer_tcp.h"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					#include "core/os/mutex.h"
 | 
				
			||||||
 | 
					#include "core/os/thread.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoteDebuggerPeer : public RefCounted {
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						int max_queued_messages = 4096;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual bool is_peer_connected() = 0;
 | 
				
			||||||
 | 
						virtual int get_max_message_size() const = 0;
 | 
				
			||||||
 | 
						virtual bool has_message() = 0;
 | 
				
			||||||
 | 
						virtual Error put_message(const Array &p_arr) = 0;
 | 
				
			||||||
 | 
						virtual Array get_message() = 0;
 | 
				
			||||||
 | 
						virtual void close() = 0;
 | 
				
			||||||
 | 
						virtual void poll() = 0;
 | 
				
			||||||
 | 
						virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteDebuggerPeer();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						Ref<StreamPeerTCP> tcp_client;
 | 
				
			||||||
 | 
						Mutex mutex;
 | 
				
			||||||
 | 
						Thread thread;
 | 
				
			||||||
 | 
						List<Array> in_queue;
 | 
				
			||||||
 | 
						List<Array> out_queue;
 | 
				
			||||||
 | 
						int out_left = 0;
 | 
				
			||||||
 | 
						int out_pos = 0;
 | 
				
			||||||
 | 
						Vector<uint8_t> out_buf;
 | 
				
			||||||
 | 
						int in_left = 0;
 | 
				
			||||||
 | 
						int in_pos = 0;
 | 
				
			||||||
 | 
						Vector<uint8_t> in_buf;
 | 
				
			||||||
 | 
						bool connected = false;
 | 
				
			||||||
 | 
						bool running = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _thread_func(void *p_ud);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _poll();
 | 
				
			||||||
 | 
						void _write_out();
 | 
				
			||||||
 | 
						void _read_in();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static RemoteDebuggerPeer *create(const String &p_uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error connect_to_host(const String &p_host, uint16_t p_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_peer_connected() override;
 | 
				
			||||||
 | 
						int get_max_message_size() const override;
 | 
				
			||||||
 | 
						bool has_message() override;
 | 
				
			||||||
 | 
						Error put_message(const Array &p_arr) override;
 | 
				
			||||||
 | 
						Array get_message() override;
 | 
				
			||||||
 | 
						void poll() override;
 | 
				
			||||||
 | 
						void close() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
 | 
				
			||||||
 | 
						~RemoteDebuggerPeerTCP();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // REMOTE_DEBUGGER_PEER_H
 | 
				
			||||||
							
								
								
									
										102
									
								
								engine/core/debugger/script_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								engine/core/debugger/script_debugger.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  script_debugger.cpp                                                   */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "script_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/debugger/engine_debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					thread_local int ScriptDebugger::lines_left = -1;
 | 
				
			||||||
 | 
					thread_local int ScriptDebugger::depth = -1;
 | 
				
			||||||
 | 
					thread_local ScriptLanguage *ScriptDebugger::break_lang = nullptr;
 | 
				
			||||||
 | 
					thread_local Vector<ScriptDebugger::StackInfo> ScriptDebugger::error_stack_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::set_lines_left(int p_left) {
 | 
				
			||||||
 | 
						lines_left = p_left;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::set_depth(int p_depth) {
 | 
				
			||||||
 | 
						depth = p_depth;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
 | 
				
			||||||
 | 
						if (!breakpoints.has(p_line)) {
 | 
				
			||||||
 | 
							breakpoints[p_line] = HashSet<StringName>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						breakpoints[p_line].insert(p_source);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
 | 
				
			||||||
 | 
						if (!breakpoints.has(p_line)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						breakpoints[p_line].erase(p_source);
 | 
				
			||||||
 | 
						if (breakpoints[p_line].size() == 0) {
 | 
				
			||||||
 | 
							breakpoints.erase(p_line);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
 | 
				
			||||||
 | 
						return p_source;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::clear_breakpoints() {
 | 
				
			||||||
 | 
						breakpoints.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::set_skip_breakpoints(bool p_skip_breakpoints) {
 | 
				
			||||||
 | 
						skip_breakpoints = p_skip_breakpoints;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ScriptDebugger::is_skipping_breakpoints() {
 | 
				
			||||||
 | 
						return skip_breakpoints;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
 | 
				
			||||||
 | 
						ScriptLanguage *prev = break_lang;
 | 
				
			||||||
 | 
						break_lang = p_lang;
 | 
				
			||||||
 | 
						EngineDebugger::get_singleton()->debug(p_can_continue, p_is_error_breakpoint);
 | 
				
			||||||
 | 
						break_lang = prev;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ScriptDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info) {
 | 
				
			||||||
 | 
						// Store stack info, this is ugly, but allows us to separate EngineDebugger and ScriptDebugger. There might be a better way.
 | 
				
			||||||
 | 
						error_stack_info.append_array(p_stack_info);
 | 
				
			||||||
 | 
						EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type);
 | 
				
			||||||
 | 
						error_stack_info.clear(); // Clear because this is thread local
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vector<ScriptLanguage::StackInfo> ScriptDebugger::get_error_stack_info() const {
 | 
				
			||||||
 | 
						return error_stack_info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ScriptLanguage *ScriptDebugger::get_break_language() const {
 | 
				
			||||||
 | 
						return break_lang;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										87
									
								
								engine/core/debugger/script_debugger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								engine/core/debugger/script_debugger.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  script_debugger.h                                                     */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SCRIPT_DEBUGGER_H
 | 
				
			||||||
 | 
					#define SCRIPT_DEBUGGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
 | 
					#include "core/templates/rb_map.h"
 | 
				
			||||||
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ScriptDebugger {
 | 
				
			||||||
 | 
						typedef ScriptLanguage::StackInfo StackInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool skip_breakpoints = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<int, HashSet<StringName>> breakpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static thread_local int lines_left;
 | 
				
			||||||
 | 
						static thread_local int depth;
 | 
				
			||||||
 | 
						static thread_local ScriptLanguage *break_lang;
 | 
				
			||||||
 | 
						static thread_local Vector<StackInfo> error_stack_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_lines_left(int p_left);
 | 
				
			||||||
 | 
						_ALWAYS_INLINE_ int get_lines_left() const {
 | 
				
			||||||
 | 
							return lines_left;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_depth(int p_depth);
 | 
				
			||||||
 | 
						_ALWAYS_INLINE_ int get_depth() const {
 | 
				
			||||||
 | 
							return depth;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String breakpoint_find_source(const String &p_source) const;
 | 
				
			||||||
 | 
						void set_break_language(ScriptLanguage *p_lang) { break_lang = p_lang; }
 | 
				
			||||||
 | 
						ScriptLanguage *get_break_language() { return break_lang; }
 | 
				
			||||||
 | 
						void set_skip_breakpoints(bool p_skip_breakpoints);
 | 
				
			||||||
 | 
						bool is_skipping_breakpoints();
 | 
				
			||||||
 | 
						void insert_breakpoint(int p_line, const StringName &p_source);
 | 
				
			||||||
 | 
						void remove_breakpoint(int p_line, const StringName &p_source);
 | 
				
			||||||
 | 
						_ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const {
 | 
				
			||||||
 | 
							if (likely(!breakpoints.has(p_line))) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return breakpoints[p_line].has(p_source);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void clear_breakpoints();
 | 
				
			||||||
 | 
						const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
 | 
				
			||||||
 | 
						ScriptLanguage *get_break_language() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info);
 | 
				
			||||||
 | 
						Vector<StackInfo> get_error_stack_info() const;
 | 
				
			||||||
 | 
						ScriptDebugger() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SCRIPT_DEBUGGER_H
 | 
				
			||||||
							
								
								
									
										177
									
								
								engine/core/doc_data.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								engine/core/doc_data.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,177 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  doc_data.cpp                                                          */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "doc_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DocData::get_default_value_string(const Variant &p_value) {
 | 
				
			||||||
 | 
						if (p_value.get_type() == Variant::ARRAY) {
 | 
				
			||||||
 | 
							return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return p_value.get_construct_string().replace("\n", " ");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
 | 
				
			||||||
 | 
						if (p_retinfo.type == Variant::INT && p_retinfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
 | 
				
			||||||
 | 
							p_method.return_type = p_retinfo.hint_string;
 | 
				
			||||||
 | 
							if (p_method.return_type.is_empty()) {
 | 
				
			||||||
 | 
								p_method.return_type = "void*";
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								p_method.return_type += "*";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
 | 
				
			||||||
 | 
							p_method.return_enum = p_retinfo.class_name;
 | 
				
			||||||
 | 
							if (p_method.return_enum.begins_with("_")) { //proxy class
 | 
				
			||||||
 | 
								p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
 | 
				
			||||||
 | 
							p_method.return_type = "int";
 | 
				
			||||||
 | 
						} else if (p_retinfo.class_name != StringName()) {
 | 
				
			||||||
 | 
							p_method.return_type = p_retinfo.class_name;
 | 
				
			||||||
 | 
						} else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
				
			||||||
 | 
							p_method.return_type = p_retinfo.hint_string + "[]";
 | 
				
			||||||
 | 
						} else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
 | 
				
			||||||
 | 
							p_method.return_type = p_retinfo.hint_string;
 | 
				
			||||||
 | 
						} else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
 | 
				
			||||||
 | 
							p_method.return_type = "Variant";
 | 
				
			||||||
 | 
						} else if (p_retinfo.type == Variant::NIL) {
 | 
				
			||||||
 | 
							p_method.return_type = "void";
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							p_method.return_type = Variant::get_type_name(p_retinfo.type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) {
 | 
				
			||||||
 | 
						p_argument.name = p_arginfo.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_arginfo.type == Variant::INT && p_arginfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
 | 
				
			||||||
 | 
							p_argument.type = p_arginfo.hint_string;
 | 
				
			||||||
 | 
							if (p_argument.type.is_empty()) {
 | 
				
			||||||
 | 
								p_argument.type = "void*";
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								p_argument.type += "*";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
 | 
				
			||||||
 | 
							p_argument.enumeration = p_arginfo.class_name;
 | 
				
			||||||
 | 
							if (p_argument.enumeration.begins_with("_")) { //proxy class
 | 
				
			||||||
 | 
								p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
 | 
				
			||||||
 | 
							p_argument.type = "int";
 | 
				
			||||||
 | 
						} else if (p_arginfo.class_name != StringName()) {
 | 
				
			||||||
 | 
							p_argument.type = p_arginfo.class_name;
 | 
				
			||||||
 | 
						} else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
 | 
				
			||||||
 | 
							p_argument.type = p_arginfo.hint_string + "[]";
 | 
				
			||||||
 | 
						} else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
 | 
				
			||||||
 | 
							p_argument.type = p_arginfo.hint_string;
 | 
				
			||||||
 | 
						} else if (p_arginfo.type == Variant::NIL) {
 | 
				
			||||||
 | 
							// Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary
 | 
				
			||||||
 | 
							p_argument.type = "Variant";
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							p_argument.type = Variant::get_type_name(p_arginfo.type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DocData::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) {
 | 
				
			||||||
 | 
						p_method.name = p_methodinfo.name;
 | 
				
			||||||
 | 
						p_method.description = p_desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_methodinfo.flags & METHOD_FLAG_VIRTUAL) {
 | 
				
			||||||
 | 
							p_method.qualifiers = "virtual";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_methodinfo.flags & METHOD_FLAG_CONST) {
 | 
				
			||||||
 | 
							if (!p_method.qualifiers.is_empty()) {
 | 
				
			||||||
 | 
								p_method.qualifiers += " ";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_method.qualifiers += "const";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_methodinfo.flags & METHOD_FLAG_VARARG) {
 | 
				
			||||||
 | 
							if (!p_method.qualifiers.is_empty()) {
 | 
				
			||||||
 | 
								p_method.qualifiers += " ";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_method.qualifiers += "vararg";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_methodinfo.flags & METHOD_FLAG_STATIC) {
 | 
				
			||||||
 | 
							if (!p_method.qualifiers.is_empty()) {
 | 
				
			||||||
 | 
								p_method.qualifiers += " ";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_method.qualifiers += "static";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return_doc_from_retinfo(p_method, p_methodinfo.return_val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						for (List<PropertyInfo>::ConstIterator itr = p_methodinfo.arguments.begin(); itr != p_methodinfo.arguments.end(); ++itr, ++i) {
 | 
				
			||||||
 | 
							DocData::ArgumentDoc argument;
 | 
				
			||||||
 | 
							argument_doc_from_arginfo(argument, *itr);
 | 
				
			||||||
 | 
							int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
 | 
				
			||||||
 | 
							if (default_arg_index >= 0) {
 | 
				
			||||||
 | 
								Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
 | 
				
			||||||
 | 
								argument.default_value = get_default_value_string(default_arg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p_method.arguments.push_back(argument);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										968
									
								
								engine/core/doc_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										968
									
								
								engine/core/doc_data.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,968 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  doc_data.h                                                            */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DOC_DATA_H
 | 
				
			||||||
 | 
					#define DOC_DATA_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/xml_parser.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ScriptMemberInfo {
 | 
				
			||||||
 | 
						PropertyInfo propinfo;
 | 
				
			||||||
 | 
						String doc_string;
 | 
				
			||||||
 | 
						StringName setter;
 | 
				
			||||||
 | 
						StringName getter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_default_value = false;
 | 
				
			||||||
 | 
						Variant default_value;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DocData {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						struct ArgumentDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String type;
 | 
				
			||||||
 | 
							String enumeration;
 | 
				
			||||||
 | 
							bool is_bitfield = false;
 | 
				
			||||||
 | 
							String default_value;
 | 
				
			||||||
 | 
							bool operator<(const ArgumentDoc &p_arg) const {
 | 
				
			||||||
 | 
								if (name == p_arg.name) {
 | 
				
			||||||
 | 
									return type < p_arg.type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return name < p_arg.name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static ArgumentDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								ArgumentDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("type")) {
 | 
				
			||||||
 | 
									doc.type = p_dict["type"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("enumeration")) {
 | 
				
			||||||
 | 
									doc.enumeration = p_dict["enumeration"];
 | 
				
			||||||
 | 
									if (p_dict.has("is_bitfield")) {
 | 
				
			||||||
 | 
										doc.is_bitfield = p_dict["is_bitfield"];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("default_value")) {
 | 
				
			||||||
 | 
									doc.default_value = p_dict["default_value"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const ArgumentDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.type.is_empty()) {
 | 
				
			||||||
 | 
									dict["type"] = p_doc.type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.enumeration.is_empty()) {
 | 
				
			||||||
 | 
									dict["enumeration"] = p_doc.enumeration;
 | 
				
			||||||
 | 
									dict["is_bitfield"] = p_doc.is_bitfield;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.default_value.is_empty()) {
 | 
				
			||||||
 | 
									dict["default_value"] = p_doc.default_value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct MethodDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String return_type;
 | 
				
			||||||
 | 
							String return_enum;
 | 
				
			||||||
 | 
							bool return_is_bitfield = false;
 | 
				
			||||||
 | 
							String qualifiers;
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
 | 
							Vector<ArgumentDoc> arguments;
 | 
				
			||||||
 | 
							Vector<int> errors_returned;
 | 
				
			||||||
 | 
							String keywords;
 | 
				
			||||||
 | 
							bool operator<(const MethodDoc &p_method) const {
 | 
				
			||||||
 | 
								if (name == p_method.name) {
 | 
				
			||||||
 | 
									// Must be an operator or a constructor since there is no other overloading
 | 
				
			||||||
 | 
									if (name.left(8) == "operator") {
 | 
				
			||||||
 | 
										if (arguments.size() == p_method.arguments.size()) {
 | 
				
			||||||
 | 
											if (arguments.size() == 0) {
 | 
				
			||||||
 | 
												return false;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											return arguments[0].type < p_method.arguments[0].type;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return arguments.size() < p_method.arguments.size();
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										// Must be a constructor
 | 
				
			||||||
 | 
										// We want this arbitrary order for a class "Foo":
 | 
				
			||||||
 | 
										// - 1. Default constructor: Foo()
 | 
				
			||||||
 | 
										// - 2. Copy constructor: Foo(Foo)
 | 
				
			||||||
 | 
										// - 3+. Other constructors Foo(Bar, ...) based on first argument's name
 | 
				
			||||||
 | 
										if (arguments.size() == 0 || p_method.arguments.size() == 0) { // 1.
 | 
				
			||||||
 | 
											return arguments.size() < p_method.arguments.size();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2.
 | 
				
			||||||
 | 
											return (arguments[0].type == return_type) || (p_method.arguments[0].type != p_method.return_type);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return arguments[0] < p_method.arguments[0];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return name.naturalcasecmp_to(p_method.name) < 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static MethodDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								MethodDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("return_type")) {
 | 
				
			||||||
 | 
									doc.return_type = p_dict["return_type"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("return_enum")) {
 | 
				
			||||||
 | 
									doc.return_enum = p_dict["return_enum"];
 | 
				
			||||||
 | 
									if (p_dict.has("return_is_bitfield")) {
 | 
				
			||||||
 | 
										doc.return_is_bitfield = p_dict["return_is_bitfield"];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("qualifiers")) {
 | 
				
			||||||
 | 
									doc.qualifiers = p_dict["qualifiers"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
								if (p_dict.has("is_deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = p_dict["is_deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = p_dict["is_experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = true;
 | 
				
			||||||
 | 
									doc.deprecated_message = p_dict["deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = true;
 | 
				
			||||||
 | 
									doc.experimental_message = p_dict["experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array arguments;
 | 
				
			||||||
 | 
								if (p_dict.has("arguments")) {
 | 
				
			||||||
 | 
									arguments = p_dict["arguments"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < arguments.size(); i++) {
 | 
				
			||||||
 | 
									doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array errors_returned;
 | 
				
			||||||
 | 
								if (p_dict.has("errors_returned")) {
 | 
				
			||||||
 | 
									errors_returned = p_dict["errors_returned"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < errors_returned.size(); i++) {
 | 
				
			||||||
 | 
									doc.errors_returned.push_back(errors_returned[i]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("keywords")) {
 | 
				
			||||||
 | 
									doc.keywords = p_dict["keywords"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const MethodDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.return_type.is_empty()) {
 | 
				
			||||||
 | 
									dict["return_type"] = p_doc.return_type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.return_enum.is_empty()) {
 | 
				
			||||||
 | 
									dict["return_enum"] = p_doc.return_enum;
 | 
				
			||||||
 | 
									dict["return_is_bitfield"] = p_doc.return_is_bitfield;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.qualifiers.is_empty()) {
 | 
				
			||||||
 | 
									dict["qualifiers"] = p_doc.qualifiers;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_deprecated) {
 | 
				
			||||||
 | 
									dict["deprecated"] = p_doc.deprecated_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_experimental) {
 | 
				
			||||||
 | 
									dict["experimental"] = p_doc.experimental_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.keywords.is_empty()) {
 | 
				
			||||||
 | 
									dict["keywords"] = p_doc.keywords;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.arguments.is_empty()) {
 | 
				
			||||||
 | 
									Array arguments;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.arguments.size(); i++) {
 | 
				
			||||||
 | 
										arguments.push_back(ArgumentDoc::to_dict(p_doc.arguments[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["arguments"] = arguments;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.errors_returned.is_empty()) {
 | 
				
			||||||
 | 
									Array errors_returned;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.errors_returned.size(); i++) {
 | 
				
			||||||
 | 
										errors_returned.push_back(p_doc.errors_returned[i]);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["errors_returned"] = errors_returned;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ConstantDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String value;
 | 
				
			||||||
 | 
							bool is_value_valid = false;
 | 
				
			||||||
 | 
							String enumeration;
 | 
				
			||||||
 | 
							bool is_bitfield = false;
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
 | 
							String keywords;
 | 
				
			||||||
 | 
							bool operator<(const ConstantDoc &p_const) const {
 | 
				
			||||||
 | 
								return name < p_const.name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static ConstantDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								ConstantDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("value")) {
 | 
				
			||||||
 | 
									doc.value = p_dict["value"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_value_valid")) {
 | 
				
			||||||
 | 
									doc.is_value_valid = p_dict["is_value_valid"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("enumeration")) {
 | 
				
			||||||
 | 
									doc.enumeration = p_dict["enumeration"];
 | 
				
			||||||
 | 
									if (p_dict.has("is_bitfield")) {
 | 
				
			||||||
 | 
										doc.is_bitfield = p_dict["is_bitfield"];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
								if (p_dict.has("is_deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = p_dict["is_deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = p_dict["is_experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = true;
 | 
				
			||||||
 | 
									doc.deprecated_message = p_dict["deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = true;
 | 
				
			||||||
 | 
									doc.experimental_message = p_dict["experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("keywords")) {
 | 
				
			||||||
 | 
									doc.keywords = p_dict["keywords"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const ConstantDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.value.is_empty()) {
 | 
				
			||||||
 | 
									dict["value"] = p_doc.value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dict["is_value_valid"] = p_doc.is_value_valid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.enumeration.is_empty()) {
 | 
				
			||||||
 | 
									dict["enumeration"] = p_doc.enumeration;
 | 
				
			||||||
 | 
									dict["is_bitfield"] = p_doc.is_bitfield;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_deprecated) {
 | 
				
			||||||
 | 
									dict["deprecated"] = p_doc.deprecated_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_experimental) {
 | 
				
			||||||
 | 
									dict["experimental"] = p_doc.experimental_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.keywords.is_empty()) {
 | 
				
			||||||
 | 
									dict["keywords"] = p_doc.keywords;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct PropertyDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String type;
 | 
				
			||||||
 | 
							String enumeration;
 | 
				
			||||||
 | 
							bool is_bitfield = false;
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							String setter, getter;
 | 
				
			||||||
 | 
							String default_value;
 | 
				
			||||||
 | 
							bool overridden = false;
 | 
				
			||||||
 | 
							String overrides;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
 | 
							String keywords;
 | 
				
			||||||
 | 
							bool operator<(const PropertyDoc &p_prop) const {
 | 
				
			||||||
 | 
								return name.naturalcasecmp_to(p_prop.name) < 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static PropertyDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								PropertyDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("type")) {
 | 
				
			||||||
 | 
									doc.type = p_dict["type"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("enumeration")) {
 | 
				
			||||||
 | 
									doc.enumeration = p_dict["enumeration"];
 | 
				
			||||||
 | 
									if (p_dict.has("is_bitfield")) {
 | 
				
			||||||
 | 
										doc.is_bitfield = p_dict["is_bitfield"];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("setter")) {
 | 
				
			||||||
 | 
									doc.setter = p_dict["setter"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("getter")) {
 | 
				
			||||||
 | 
									doc.getter = p_dict["getter"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("default_value")) {
 | 
				
			||||||
 | 
									doc.default_value = p_dict["default_value"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("overridden")) {
 | 
				
			||||||
 | 
									doc.overridden = p_dict["overridden"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("overrides")) {
 | 
				
			||||||
 | 
									doc.overrides = p_dict["overrides"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
								if (p_dict.has("is_deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = p_dict["is_deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = p_dict["is_experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = true;
 | 
				
			||||||
 | 
									doc.deprecated_message = p_dict["deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = true;
 | 
				
			||||||
 | 
									doc.experimental_message = p_dict["experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("keywords")) {
 | 
				
			||||||
 | 
									doc.keywords = p_dict["keywords"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const PropertyDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.type.is_empty()) {
 | 
				
			||||||
 | 
									dict["type"] = p_doc.type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.enumeration.is_empty()) {
 | 
				
			||||||
 | 
									dict["enumeration"] = p_doc.enumeration;
 | 
				
			||||||
 | 
									dict["is_bitfield"] = p_doc.is_bitfield;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.setter.is_empty()) {
 | 
				
			||||||
 | 
									dict["setter"] = p_doc.setter;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.getter.is_empty()) {
 | 
				
			||||||
 | 
									dict["getter"] = p_doc.getter;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.default_value.is_empty()) {
 | 
				
			||||||
 | 
									dict["default_value"] = p_doc.default_value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dict["overridden"] = p_doc.overridden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.overrides.is_empty()) {
 | 
				
			||||||
 | 
									dict["overrides"] = p_doc.overrides;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_deprecated) {
 | 
				
			||||||
 | 
									dict["deprecated"] = p_doc.deprecated_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_experimental) {
 | 
				
			||||||
 | 
									dict["experimental"] = p_doc.experimental_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.keywords.is_empty()) {
 | 
				
			||||||
 | 
									dict["keywords"] = p_doc.keywords;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ThemeItemDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String type;
 | 
				
			||||||
 | 
							String data_type;
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							String default_value;
 | 
				
			||||||
 | 
							String keywords;
 | 
				
			||||||
 | 
							bool operator<(const ThemeItemDoc &p_theme_item) const {
 | 
				
			||||||
 | 
								// First sort by the data type, then by name.
 | 
				
			||||||
 | 
								if (data_type == p_theme_item.data_type) {
 | 
				
			||||||
 | 
									return name.naturalcasecmp_to(p_theme_item.name) < 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return data_type < p_theme_item.data_type;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static ThemeItemDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								ThemeItemDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("type")) {
 | 
				
			||||||
 | 
									doc.type = p_dict["type"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("data_type")) {
 | 
				
			||||||
 | 
									doc.data_type = p_dict["data_type"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("default_value")) {
 | 
				
			||||||
 | 
									doc.default_value = p_dict["default_value"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("keywords")) {
 | 
				
			||||||
 | 
									doc.keywords = p_dict["keywords"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const ThemeItemDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.type.is_empty()) {
 | 
				
			||||||
 | 
									dict["type"] = p_doc.type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.data_type.is_empty()) {
 | 
				
			||||||
 | 
									dict["data_type"] = p_doc.data_type;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.default_value.is_empty()) {
 | 
				
			||||||
 | 
									dict["default_value"] = p_doc.default_value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.keywords.is_empty()) {
 | 
				
			||||||
 | 
									dict["keywords"] = p_doc.keywords;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct TutorialDoc {
 | 
				
			||||||
 | 
							String link;
 | 
				
			||||||
 | 
							String title;
 | 
				
			||||||
 | 
							static TutorialDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								TutorialDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("link")) {
 | 
				
			||||||
 | 
									doc.link = p_dict["link"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("title")) {
 | 
				
			||||||
 | 
									doc.title = p_dict["title"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const TutorialDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.link.is_empty()) {
 | 
				
			||||||
 | 
									dict["link"] = p_doc.link;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.title.is_empty()) {
 | 
				
			||||||
 | 
									dict["title"] = p_doc.title;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct EnumDoc {
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
 | 
							static EnumDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								EnumDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
								if (p_dict.has("is_deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = p_dict["is_deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = p_dict["is_experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = true;
 | 
				
			||||||
 | 
									doc.deprecated_message = p_dict["deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = true;
 | 
				
			||||||
 | 
									doc.experimental_message = p_dict["experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const EnumDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_deprecated) {
 | 
				
			||||||
 | 
									dict["deprecated"] = p_doc.deprecated_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_experimental) {
 | 
				
			||||||
 | 
									dict["experimental"] = p_doc.experimental_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ClassDoc {
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							String inherits;
 | 
				
			||||||
 | 
							String brief_description;
 | 
				
			||||||
 | 
							String description;
 | 
				
			||||||
 | 
							String keywords;
 | 
				
			||||||
 | 
							Vector<TutorialDoc> tutorials;
 | 
				
			||||||
 | 
							Vector<MethodDoc> constructors;
 | 
				
			||||||
 | 
							Vector<MethodDoc> methods;
 | 
				
			||||||
 | 
							Vector<MethodDoc> operators;
 | 
				
			||||||
 | 
							Vector<MethodDoc> signals;
 | 
				
			||||||
 | 
							Vector<ConstantDoc> constants;
 | 
				
			||||||
 | 
							HashMap<String, EnumDoc> enums;
 | 
				
			||||||
 | 
							Vector<PropertyDoc> properties;
 | 
				
			||||||
 | 
							Vector<MethodDoc> annotations;
 | 
				
			||||||
 | 
							Vector<ThemeItemDoc> theme_properties;
 | 
				
			||||||
 | 
							bool is_deprecated = false;
 | 
				
			||||||
 | 
							String deprecated_message;
 | 
				
			||||||
 | 
							bool is_experimental = false;
 | 
				
			||||||
 | 
							String experimental_message;
 | 
				
			||||||
 | 
							bool is_script_doc = false;
 | 
				
			||||||
 | 
							String script_path;
 | 
				
			||||||
 | 
							bool operator<(const ClassDoc &p_class) const {
 | 
				
			||||||
 | 
								return name < p_class.name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static ClassDoc from_dict(const Dictionary &p_dict) {
 | 
				
			||||||
 | 
								ClassDoc doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("name")) {
 | 
				
			||||||
 | 
									doc.name = p_dict["name"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("inherits")) {
 | 
				
			||||||
 | 
									doc.inherits = p_dict["inherits"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("brief_description")) {
 | 
				
			||||||
 | 
									doc.brief_description = p_dict["brief_description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("description")) {
 | 
				
			||||||
 | 
									doc.description = p_dict["description"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("keywords")) {
 | 
				
			||||||
 | 
									doc.keywords = p_dict["keywords"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array tutorials;
 | 
				
			||||||
 | 
								if (p_dict.has("tutorials")) {
 | 
				
			||||||
 | 
									tutorials = p_dict["tutorials"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < tutorials.size(); i++) {
 | 
				
			||||||
 | 
									doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array constructors;
 | 
				
			||||||
 | 
								if (p_dict.has("constructors")) {
 | 
				
			||||||
 | 
									constructors = p_dict["constructors"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < constructors.size(); i++) {
 | 
				
			||||||
 | 
									doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array methods;
 | 
				
			||||||
 | 
								if (p_dict.has("methods")) {
 | 
				
			||||||
 | 
									methods = p_dict["methods"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < methods.size(); i++) {
 | 
				
			||||||
 | 
									doc.methods.push_back(MethodDoc::from_dict(methods[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array operators;
 | 
				
			||||||
 | 
								if (p_dict.has("operators")) {
 | 
				
			||||||
 | 
									operators = p_dict["operators"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < operators.size(); i++) {
 | 
				
			||||||
 | 
									doc.operators.push_back(MethodDoc::from_dict(operators[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array signals;
 | 
				
			||||||
 | 
								if (p_dict.has("signals")) {
 | 
				
			||||||
 | 
									signals = p_dict["signals"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < signals.size(); i++) {
 | 
				
			||||||
 | 
									doc.signals.push_back(MethodDoc::from_dict(signals[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array constants;
 | 
				
			||||||
 | 
								if (p_dict.has("constants")) {
 | 
				
			||||||
 | 
									constants = p_dict["constants"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < constants.size(); i++) {
 | 
				
			||||||
 | 
									doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Dictionary enums;
 | 
				
			||||||
 | 
								if (p_dict.has("enums")) {
 | 
				
			||||||
 | 
									enums = p_dict["enums"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < enums.size(); i++) {
 | 
				
			||||||
 | 
									doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array properties;
 | 
				
			||||||
 | 
								if (p_dict.has("properties")) {
 | 
				
			||||||
 | 
									properties = p_dict["properties"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < properties.size(); i++) {
 | 
				
			||||||
 | 
									doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array annotations;
 | 
				
			||||||
 | 
								if (p_dict.has("annotations")) {
 | 
				
			||||||
 | 
									annotations = p_dict["annotations"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < annotations.size(); i++) {
 | 
				
			||||||
 | 
									doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Array theme_properties;
 | 
				
			||||||
 | 
								if (p_dict.has("theme_properties")) {
 | 
				
			||||||
 | 
									theme_properties = p_dict["theme_properties"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < theme_properties.size(); i++) {
 | 
				
			||||||
 | 
									doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
								if (p_dict.has("is_deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = p_dict["is_deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = p_dict["is_experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("deprecated")) {
 | 
				
			||||||
 | 
									doc.is_deprecated = true;
 | 
				
			||||||
 | 
									doc.deprecated_message = p_dict["deprecated"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("experimental")) {
 | 
				
			||||||
 | 
									doc.is_experimental = true;
 | 
				
			||||||
 | 
									doc.experimental_message = p_dict["experimental"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("is_script_doc")) {
 | 
				
			||||||
 | 
									doc.is_script_doc = p_dict["is_script_doc"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dict.has("script_path")) {
 | 
				
			||||||
 | 
									doc.script_path = p_dict["script_path"];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return doc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							static Dictionary to_dict(const ClassDoc &p_doc) {
 | 
				
			||||||
 | 
								Dictionary dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.name.is_empty()) {
 | 
				
			||||||
 | 
									dict["name"] = p_doc.name;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.inherits.is_empty()) {
 | 
				
			||||||
 | 
									dict["inherits"] = p_doc.inherits;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.brief_description.is_empty()) {
 | 
				
			||||||
 | 
									dict["brief_description"] = p_doc.brief_description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.description.is_empty()) {
 | 
				
			||||||
 | 
									dict["description"] = p_doc.description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.tutorials.is_empty()) {
 | 
				
			||||||
 | 
									Array tutorials;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.tutorials.size(); i++) {
 | 
				
			||||||
 | 
										tutorials.push_back(TutorialDoc::to_dict(p_doc.tutorials[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["tutorials"] = tutorials;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.constructors.is_empty()) {
 | 
				
			||||||
 | 
									Array constructors;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.constructors.size(); i++) {
 | 
				
			||||||
 | 
										constructors.push_back(MethodDoc::to_dict(p_doc.constructors[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["constructors"] = constructors;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.methods.is_empty()) {
 | 
				
			||||||
 | 
									Array methods;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.methods.size(); i++) {
 | 
				
			||||||
 | 
										methods.push_back(MethodDoc::to_dict(p_doc.methods[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["methods"] = methods;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.operators.is_empty()) {
 | 
				
			||||||
 | 
									Array operators;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.operators.size(); i++) {
 | 
				
			||||||
 | 
										operators.push_back(MethodDoc::to_dict(p_doc.operators[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["operators"] = operators;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.signals.is_empty()) {
 | 
				
			||||||
 | 
									Array signals;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.signals.size(); i++) {
 | 
				
			||||||
 | 
										signals.push_back(MethodDoc::to_dict(p_doc.signals[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["signals"] = signals;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.constants.is_empty()) {
 | 
				
			||||||
 | 
									Array constants;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.constants.size(); i++) {
 | 
				
			||||||
 | 
										constants.push_back(ConstantDoc::to_dict(p_doc.constants[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["constants"] = constants;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.enums.is_empty()) {
 | 
				
			||||||
 | 
									Dictionary enums;
 | 
				
			||||||
 | 
									for (const KeyValue<String, EnumDoc> &E : p_doc.enums) {
 | 
				
			||||||
 | 
										enums[E.key] = EnumDoc::to_dict(E.value);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["enums"] = enums;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.properties.is_empty()) {
 | 
				
			||||||
 | 
									Array properties;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.properties.size(); i++) {
 | 
				
			||||||
 | 
										properties.push_back(PropertyDoc::to_dict(p_doc.properties[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["properties"] = properties;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.annotations.is_empty()) {
 | 
				
			||||||
 | 
									Array annotations;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.annotations.size(); i++) {
 | 
				
			||||||
 | 
										annotations.push_back(MethodDoc::to_dict(p_doc.annotations[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["annotations"] = annotations;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.theme_properties.is_empty()) {
 | 
				
			||||||
 | 
									Array theme_properties;
 | 
				
			||||||
 | 
									for (int i = 0; i < p_doc.theme_properties.size(); i++) {
 | 
				
			||||||
 | 
										theme_properties.push_back(ThemeItemDoc::to_dict(p_doc.theme_properties[i]));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dict["theme_properties"] = theme_properties;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_deprecated) {
 | 
				
			||||||
 | 
									dict["deprecated"] = p_doc.deprecated_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_doc.is_experimental) {
 | 
				
			||||||
 | 
									dict["experimental"] = p_doc.experimental_message;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dict["is_script_doc"] = p_doc.is_script_doc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.script_path.is_empty()) {
 | 
				
			||||||
 | 
									dict["script_path"] = p_doc.script_path;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!p_doc.keywords.is_empty()) {
 | 
				
			||||||
 | 
									dict["keywords"] = p_doc.keywords;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return dict;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static String get_default_value_string(const Variant &p_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
 | 
				
			||||||
 | 
						static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo);
 | 
				
			||||||
 | 
						static void 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 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
 | 
				
			||||||
							
								
								
									
										7
									
								
								engine/core/error/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								engine/core/error/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_error = env.Clone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_error.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
							
								
								
									
										85
									
								
								engine/core/error/error_list.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								engine/core/error/error_list.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  error_list.cpp                                                        */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "error_list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *error_names[] = {
 | 
				
			||||||
 | 
						"OK", // OK
 | 
				
			||||||
 | 
						"Failed", // FAILED
 | 
				
			||||||
 | 
						"Unavailable", // ERR_UNAVAILABLE
 | 
				
			||||||
 | 
						"Unconfigured", // ERR_UNCONFIGURED
 | 
				
			||||||
 | 
						"Unauthorized", // ERR_UNAUTHORIZED
 | 
				
			||||||
 | 
						"Parameter out of range", // ERR_PARAMETER_RANGE_ERROR
 | 
				
			||||||
 | 
						"Out of memory", // ERR_OUT_OF_MEMORY
 | 
				
			||||||
 | 
						"File not found", // ERR_FILE_NOT_FOUND
 | 
				
			||||||
 | 
						"File: Bad drive", // ERR_FILE_BAD_DRIVE
 | 
				
			||||||
 | 
						"File: Bad path", // ERR_FILE_BAD_PATH
 | 
				
			||||||
 | 
						"File: Permission denied", // ERR_FILE_NO_PERMISSION
 | 
				
			||||||
 | 
						"File already in use", // ERR_FILE_ALREADY_IN_USE
 | 
				
			||||||
 | 
						"Can't open file", // ERR_FILE_CANT_OPEN
 | 
				
			||||||
 | 
						"Can't write file", // ERR_FILE_CANT_WRITE
 | 
				
			||||||
 | 
						"Can't read file", // ERR_FILE_CANT_READ
 | 
				
			||||||
 | 
						"File unrecognized", // ERR_FILE_UNRECOGNIZED
 | 
				
			||||||
 | 
						"File corrupt", // ERR_FILE_CORRUPT
 | 
				
			||||||
 | 
						"Missing dependencies for file", // ERR_FILE_MISSING_DEPENDENCIES
 | 
				
			||||||
 | 
						"End of file", // ERR_FILE_EOF
 | 
				
			||||||
 | 
						"Can't open", // ERR_CANT_OPEN
 | 
				
			||||||
 | 
						"Can't create", // ERR_CANT_CREATE
 | 
				
			||||||
 | 
						"Query failed", // ERR_QUERY_FAILED
 | 
				
			||||||
 | 
						"Already in use", // ERR_ALREADY_IN_USE
 | 
				
			||||||
 | 
						"Locked", // ERR_LOCKED
 | 
				
			||||||
 | 
						"Timeout", // ERR_TIMEOUT
 | 
				
			||||||
 | 
						"Can't connect", // ERR_CANT_CONNECT
 | 
				
			||||||
 | 
						"Can't resolve", // ERR_CANT_RESOLVE
 | 
				
			||||||
 | 
						"Connection error", // ERR_CONNECTION_ERROR
 | 
				
			||||||
 | 
						"Can't acquire resource", // ERR_CANT_ACQUIRE_RESOURCE
 | 
				
			||||||
 | 
						"Can't fork", // ERR_CANT_FORK
 | 
				
			||||||
 | 
						"Invalid data", // ERR_INVALID_DATA
 | 
				
			||||||
 | 
						"Invalid parameter", // ERR_INVALID_PARAMETER
 | 
				
			||||||
 | 
						"Already exists", // ERR_ALREADY_EXISTS
 | 
				
			||||||
 | 
						"Does not exist", // ERR_DOES_NOT_EXIST
 | 
				
			||||||
 | 
						"Can't read database", // ERR_DATABASE_CANT_READ
 | 
				
			||||||
 | 
						"Can't write database", // ERR_DATABASE_CANT_WRITE
 | 
				
			||||||
 | 
						"Compilation failed", // ERR_COMPILATION_FAILED
 | 
				
			||||||
 | 
						"Method not found", // ERR_METHOD_NOT_FOUND
 | 
				
			||||||
 | 
						"Link failed", // ERR_LINK_FAILED
 | 
				
			||||||
 | 
						"Script failed", // ERR_SCRIPT_FAILED
 | 
				
			||||||
 | 
						"Cyclic link detected", // ERR_CYCLIC_LINK
 | 
				
			||||||
 | 
						"Invalid declaration", // ERR_INVALID_DECLARATION
 | 
				
			||||||
 | 
						"Duplicate symbol", // ERR_DUPLICATE_SYMBOL
 | 
				
			||||||
 | 
						"Parse error", // ERR_PARSE_ERROR
 | 
				
			||||||
 | 
						"Busy", // ERR_BUSY
 | 
				
			||||||
 | 
						"Skip", // ERR_SKIP
 | 
				
			||||||
 | 
						"Help", // ERR_HELP
 | 
				
			||||||
 | 
						"Bug", // ERR_BUG
 | 
				
			||||||
 | 
						"Printer on fire", // ERR_PRINTER_ON_FIRE
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(error_names) / sizeof(*error_names) == ERR_MAX);
 | 
				
			||||||
							
								
								
									
										101
									
								
								engine/core/error/error_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								engine/core/error/error_list.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  error_list.h                                                          */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ERROR_LIST_H
 | 
				
			||||||
 | 
					#define ERROR_LIST_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Error List. Please never compare an error against FAILED
 | 
				
			||||||
 | 
					 * Either do result != OK , or !result. This way, Error fail
 | 
				
			||||||
 | 
					 * values can be more detailed in the future.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a generic error list, mainly for organizing a language of returning errors.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Errors:
 | 
				
			||||||
 | 
					 * - Are added to the Error enum in core/error/error_list.h
 | 
				
			||||||
 | 
					 * - Have a description added to error_names in core/error/error_list.cpp
 | 
				
			||||||
 | 
					 * - Are bound with BIND_CORE_ENUM_CONSTANT() in core/core_constants.cpp
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum Error {
 | 
				
			||||||
 | 
						OK, // (0)
 | 
				
			||||||
 | 
						FAILED, ///< Generic fail error
 | 
				
			||||||
 | 
						ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
 | 
				
			||||||
 | 
						ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
 | 
				
			||||||
 | 
						ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
 | 
				
			||||||
 | 
						ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
 | 
				
			||||||
 | 
						ERR_OUT_OF_MEMORY, ///< Out of memory
 | 
				
			||||||
 | 
						ERR_FILE_NOT_FOUND,
 | 
				
			||||||
 | 
						ERR_FILE_BAD_DRIVE,
 | 
				
			||||||
 | 
						ERR_FILE_BAD_PATH,
 | 
				
			||||||
 | 
						ERR_FILE_NO_PERMISSION, // (10)
 | 
				
			||||||
 | 
						ERR_FILE_ALREADY_IN_USE,
 | 
				
			||||||
 | 
						ERR_FILE_CANT_OPEN,
 | 
				
			||||||
 | 
						ERR_FILE_CANT_WRITE,
 | 
				
			||||||
 | 
						ERR_FILE_CANT_READ,
 | 
				
			||||||
 | 
						ERR_FILE_UNRECOGNIZED, // (15)
 | 
				
			||||||
 | 
						ERR_FILE_CORRUPT,
 | 
				
			||||||
 | 
						ERR_FILE_MISSING_DEPENDENCIES,
 | 
				
			||||||
 | 
						ERR_FILE_EOF,
 | 
				
			||||||
 | 
						ERR_CANT_OPEN, ///< Can't open a resource/socket/file
 | 
				
			||||||
 | 
						ERR_CANT_CREATE, // (20)
 | 
				
			||||||
 | 
						ERR_QUERY_FAILED,
 | 
				
			||||||
 | 
						ERR_ALREADY_IN_USE,
 | 
				
			||||||
 | 
						ERR_LOCKED, ///< resource is locked
 | 
				
			||||||
 | 
						ERR_TIMEOUT,
 | 
				
			||||||
 | 
						ERR_CANT_CONNECT, // (25)
 | 
				
			||||||
 | 
						ERR_CANT_RESOLVE,
 | 
				
			||||||
 | 
						ERR_CONNECTION_ERROR,
 | 
				
			||||||
 | 
						ERR_CANT_ACQUIRE_RESOURCE,
 | 
				
			||||||
 | 
						ERR_CANT_FORK,
 | 
				
			||||||
 | 
						ERR_INVALID_DATA, ///< Data passed is invalid (30)
 | 
				
			||||||
 | 
						ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
 | 
				
			||||||
 | 
						ERR_ALREADY_EXISTS, ///< When adding, item already exists
 | 
				
			||||||
 | 
						ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
 | 
				
			||||||
 | 
						ERR_DATABASE_CANT_READ, ///< database is full
 | 
				
			||||||
 | 
						ERR_DATABASE_CANT_WRITE, ///< database is full (35)
 | 
				
			||||||
 | 
						ERR_COMPILATION_FAILED,
 | 
				
			||||||
 | 
						ERR_METHOD_NOT_FOUND,
 | 
				
			||||||
 | 
						ERR_LINK_FAILED,
 | 
				
			||||||
 | 
						ERR_SCRIPT_FAILED,
 | 
				
			||||||
 | 
						ERR_CYCLIC_LINK, // (40)
 | 
				
			||||||
 | 
						ERR_INVALID_DECLARATION,
 | 
				
			||||||
 | 
						ERR_DUPLICATE_SYMBOL,
 | 
				
			||||||
 | 
						ERR_PARSE_ERROR,
 | 
				
			||||||
 | 
						ERR_BUSY,
 | 
				
			||||||
 | 
						ERR_SKIP, // (45)
 | 
				
			||||||
 | 
						ERR_HELP, ///< user requested help!!
 | 
				
			||||||
 | 
						ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
 | 
				
			||||||
 | 
						ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
 | 
				
			||||||
 | 
						ERR_MAX, // Not being returned, value represents the number of errors
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const char *error_names[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ERROR_LIST_H
 | 
				
			||||||
							
								
								
									
										130
									
								
								engine/core/error/error_macros.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								engine/core/error/error_macros.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,130 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  error_macros.cpp                                                      */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "error_macros.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/logger.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ErrorHandlerList *error_handler_list = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void add_error_handler(ErrorHandlerList *p_handler) {
 | 
				
			||||||
 | 
						// If p_handler is already in error_handler_list
 | 
				
			||||||
 | 
						// we'd better remove it first then we can add it.
 | 
				
			||||||
 | 
						// This prevent cyclic redundancy.
 | 
				
			||||||
 | 
						remove_error_handler(p_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_global_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p_handler->next = error_handler_list;
 | 
				
			||||||
 | 
						error_handler_list = p_handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_global_unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void remove_error_handler(const ErrorHandlerList *p_handler) {
 | 
				
			||||||
 | 
						_global_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ErrorHandlerList *prev = nullptr;
 | 
				
			||||||
 | 
						ErrorHandlerList *l = error_handler_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (l) {
 | 
				
			||||||
 | 
							if (l == p_handler) {
 | 
				
			||||||
 | 
								if (prev) {
 | 
				
			||||||
 | 
									prev->next = l->next;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									error_handler_list = l->next;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							prev = l;
 | 
				
			||||||
 | 
							l = l->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_global_unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Errors without messages.
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, p_error, "", p_editor_notify, p_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), "", p_editor_notify, p_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Main error printing function.
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						if (OS::get_singleton()) {
 | 
				
			||||||
 | 
							OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Fallback if errors happen before OS init or after it's destroyed.
 | 
				
			||||||
 | 
							const char *err_details = (p_message && *p_message) ? p_message : p_error;
 | 
				
			||||||
 | 
							fprintf(stderr, "ERROR: %s\n   at: %s (%s:%i)\n", err_details, p_function, p_file, p_line);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_global_lock();
 | 
				
			||||||
 | 
						ErrorHandlerList *l = error_handler_list;
 | 
				
			||||||
 | 
						while (l) {
 | 
				
			||||||
 | 
							l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type);
 | 
				
			||||||
 | 
							l = l->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_global_unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Errors with message. (All combinations of p_error and p_message as String or char*.)
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, p_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) {
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, p_type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Index errors. (All combinations of p_message as String or char*.)
 | 
				
			||||||
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) {
 | 
				
			||||||
 | 
						String fstr(p_fatal ? "FATAL: " : "");
 | 
				
			||||||
 | 
						String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
 | 
				
			||||||
 | 
						_err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) {
 | 
				
			||||||
 | 
						_err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _err_flush_stdout() {
 | 
				
			||||||
 | 
						fflush(stdout);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										835
									
								
								engine/core/error/error_macros.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										835
									
								
								engine/core/error/error_macros.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,835 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  error_macros.h                                                        */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ERROR_MACROS_H
 | 
				
			||||||
 | 
					#define ERROR_MACROS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/typedefs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ErrorHandlerType {
 | 
				
			||||||
 | 
						ERR_HANDLER_ERROR,
 | 
				
			||||||
 | 
						ERR_HANDLER_WARNING,
 | 
				
			||||||
 | 
						ERR_HANDLER_SCRIPT,
 | 
				
			||||||
 | 
						ERR_HANDLER_SHADER,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pointer to the error handler printing function. Reassign to any function to have errors printed.
 | 
				
			||||||
 | 
					// Parameters: userdata, function, file, line, error, explanation, type.
 | 
				
			||||||
 | 
					typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ErrorHandlerList {
 | 
				
			||||||
 | 
						ErrorHandlerFunc errfunc = nullptr;
 | 
				
			||||||
 | 
						void *userdata = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ErrorHandlerList *next = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ErrorHandlerList() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void add_error_handler(ErrorHandlerList *p_handler);
 | 
				
			||||||
 | 
					void remove_error_handler(const ErrorHandlerList *p_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Functions used by the error macros.
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
 | 
				
			||||||
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
 | 
				
			||||||
 | 
					void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
 | 
				
			||||||
 | 
					void _err_flush_stdout();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __GNUC__
 | 
				
			||||||
 | 
					//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
 | 
				
			||||||
 | 
					#define FUNCTION_STR __FUNCTION__
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define FUNCTION_STR __FUNCTION__
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _MSC_VER
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Don't use GENERATE_TRAP() directly, should only be used be the macros below.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define GENERATE_TRAP() __debugbreak()
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Don't use GENERATE_TRAP() directly, should only be used be the macros below.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define GENERATE_TRAP() __builtin_trap()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Error macros.
 | 
				
			||||||
 | 
					 * WARNING: These macros work in the opposite way to assert().
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unlike exceptions and asserts, these macros try to maintain consistency and stability.
 | 
				
			||||||
 | 
					 * In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
 | 
				
			||||||
 | 
					 * running application to fail or crash.
 | 
				
			||||||
 | 
					 * Always try to return processable data, so the engine can keep running well.
 | 
				
			||||||
 | 
					 * Use the _MSG versions to print a meaningful message to help with debugging.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
 | 
				
			||||||
 | 
					 * those macros, making them look like proper statements.
 | 
				
			||||||
 | 
					 * The if wrappers are used to ensure that the macro replacement does not trigger unexpected
 | 
				
			||||||
 | 
					 * issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Index out of bounds error macros.
 | 
				
			||||||
 | 
					// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Integer index out of bounds error macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_INDEX_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX(m_index, m_size)                                                                         \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                     \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
 | 
				
			||||||
 | 
							return;                                                                                                 \
 | 
				
			||||||
 | 
						} else                                                                                                      \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg)                                                                     \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                            \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
 | 
				
			||||||
 | 
							return;                                                                                                        \
 | 
				
			||||||
 | 
						} else                                                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg)                                                                         \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                                  \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
 | 
				
			||||||
 | 
							return;                                                                                                              \
 | 
				
			||||||
 | 
						} else                                                                                                                   \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval)                                                             \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                     \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                        \
 | 
				
			||||||
 | 
						} else                                                                                                      \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg)                                                         \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                            \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                               \
 | 
				
			||||||
 | 
						} else                                                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg)                                                             \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                                  \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                     \
 | 
				
			||||||
 | 
						} else                                                                                                                   \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
 | 
				
			||||||
 | 
					 * there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_BAD_INDEX(m_index, m_size)                                                                                         \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                                      \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                                     \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                                                       \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg)                                                                                 \
 | 
				
			||||||
 | 
						if (unlikely((m_index) < 0 || (m_index) >= (m_size))) {                                                                         \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                                        \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                                            \
 | 
				
			||||||
 | 
						} else                                                                                                                          \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unsigned integer index out of bounds error macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size)                                                                \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                      \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
 | 
				
			||||||
 | 
							return;                                                                                                 \
 | 
				
			||||||
 | 
						} else                                                                                                      \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg)                                                            \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                             \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
 | 
				
			||||||
 | 
							return;                                                                                                        \
 | 
				
			||||||
 | 
						} else                                                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg)                                                                \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                                   \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
 | 
				
			||||||
 | 
							return;                                                                                                              \
 | 
				
			||||||
 | 
						} else                                                                                                                   \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval)                                                    \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                      \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                        \
 | 
				
			||||||
 | 
						} else                                                                                                      \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg)                                                \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                             \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                               \
 | 
				
			||||||
 | 
						} else                                                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg)                                                    \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                                   \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                     \
 | 
				
			||||||
 | 
						} else                                                                                                                   \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
 | 
				
			||||||
 | 
					 * there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size)                                                                                \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                                       \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                                     \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                                                       \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures an unsigned integer index `m_index` is less than `m_size`.
 | 
				
			||||||
 | 
					 * If not, prints `m_msg` and the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg)                                                                        \
 | 
				
			||||||
 | 
						if (unlikely((m_index) >= (m_size))) {                                                                                          \
 | 
				
			||||||
 | 
							_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                                        \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                                            \
 | 
				
			||||||
 | 
						} else                                                                                                                          \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Null reference error macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_NULL_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures a pointer `m_param` is not null.
 | 
				
			||||||
 | 
					 * If it is null, the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL(m_param)                                                                          \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                 \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
 | 
				
			||||||
 | 
							return;                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                              \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures a pointer `m_param` is not null.
 | 
				
			||||||
 | 
					 * If it is null, prints `m_msg` and the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL_MSG(m_param, m_msg)                                                                      \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                        \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
 | 
				
			||||||
 | 
							return;                                                                                                \
 | 
				
			||||||
 | 
						} else                                                                                                     \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL_EDMSG(m_param, m_msg)                                                                          \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                              \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
 | 
				
			||||||
 | 
							return;                                                                                                      \
 | 
				
			||||||
 | 
						} else                                                                                                           \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_NULL_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures a pointer `m_param` is not null.
 | 
				
			||||||
 | 
					 * If it is null, the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL_V(m_param, m_retval)                                                              \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                 \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                \
 | 
				
			||||||
 | 
						} else                                                                                              \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures a pointer `m_param` is not null.
 | 
				
			||||||
 | 
					 * If it is null, prints `m_msg` and the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg)                                                          \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                        \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                       \
 | 
				
			||||||
 | 
						} else                                                                                                     \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg)                                                              \
 | 
				
			||||||
 | 
						if (unlikely(m_param == nullptr)) {                                                                              \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                             \
 | 
				
			||||||
 | 
						} else                                                                                                           \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 * If checking for null use ERR_FAIL_NULL_MSG instead.
 | 
				
			||||||
 | 
					 * If checking index bounds use ERR_FAIL_INDEX_MSG instead.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND(m_cond)                                                                          \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                            \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
 | 
				
			||||||
 | 
							return;                                                                                        \
 | 
				
			||||||
 | 
						} else                                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, prints `m_msg` and the current function returns.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If checking for null use ERR_FAIL_NULL_MSG instead.
 | 
				
			||||||
 | 
					 * If checking index bounds use ERR_FAIL_INDEX_MSG instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND_MSG(m_cond, m_msg)                                                                      \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                   \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
 | 
				
			||||||
 | 
							return;                                                                                               \
 | 
				
			||||||
 | 
						} else                                                                                                    \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND_EDMSG(m_cond, m_msg)                                                                          \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                         \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
 | 
				
			||||||
 | 
							return;                                                                                                     \
 | 
				
			||||||
 | 
						} else                                                                                                          \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 * If checking for null use ERR_FAIL_NULL_V_MSG instead.
 | 
				
			||||||
 | 
					 * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND_V(m_cond, m_retval)                                                                                         \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                                       \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                          \
 | 
				
			||||||
 | 
						} else                                                                                                                        \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If checking for null use ERR_FAIL_NULL_V_MSG instead.
 | 
				
			||||||
 | 
					 * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg)                                                                                     \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                                              \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                                 \
 | 
				
			||||||
 | 
						} else                                                                                                                               \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg)                                                                                         \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                                                    \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                                       \
 | 
				
			||||||
 | 
						} else                                                                                                                                     \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_CONTINUE_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, the current loop continues.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_CONTINUE(m_cond)                                                                                       \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                        \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
 | 
				
			||||||
 | 
							continue;                                                                                                  \
 | 
				
			||||||
 | 
						} else                                                                                                         \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, prints `m_msg` and the current loop continues.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_CONTINUE_MSG(m_cond, m_msg)                                                                                   \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                               \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
 | 
				
			||||||
 | 
							continue;                                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                                                \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_CONTINUE_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_CONTINUE_EDMSG(m_cond, m_msg)                                                                                       \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                                     \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
 | 
				
			||||||
 | 
							continue;                                                                                                               \
 | 
				
			||||||
 | 
						} else                                                                                                                      \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_BREAK_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, the current loop breaks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_BREAK(m_cond)                                                                                        \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                      \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
 | 
				
			||||||
 | 
							break;                                                                                                   \
 | 
				
			||||||
 | 
						} else                                                                                                       \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, prints `m_msg` and the current loop breaks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_BREAK_MSG(m_cond, m_msg)                                                                                    \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                             \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
 | 
				
			||||||
 | 
							break;                                                                                                          \
 | 
				
			||||||
 | 
						} else                                                                                                              \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_BREAK_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_BREAK_EDMSG(m_cond, m_msg)                                                                                        \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                                   \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
 | 
				
			||||||
 | 
							break;                                                                                                                \
 | 
				
			||||||
 | 
						} else                                                                                                                    \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
 | 
				
			||||||
 | 
					 * there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_COND(m_cond)                                                                                    \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                   \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                  \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                      \
 | 
				
			||||||
 | 
						} else                                                                                                    \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ensures `m_cond` is false.
 | 
				
			||||||
 | 
					 * If `m_cond` is true, prints `m_msg` and the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_COND_MSG(m_cond, m_msg)                                                                                \
 | 
				
			||||||
 | 
						if (unlikely(m_cond)) {                                                                                          \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                         \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                             \
 | 
				
			||||||
 | 
						} else                                                                                                           \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Generic error macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if more complex error detection or recovery is required, and
 | 
				
			||||||
 | 
					 * there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL()                                                                     \
 | 
				
			||||||
 | 
						if (true) {                                                                        \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
 | 
				
			||||||
 | 
							return;                                                                        \
 | 
				
			||||||
 | 
						} else                                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if more complex error detection or recovery is required.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Prints `m_msg`, and the current function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_MSG(m_msg)                                                                   \
 | 
				
			||||||
 | 
						if (true) {                                                                               \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
 | 
				
			||||||
 | 
							return;                                                                               \
 | 
				
			||||||
 | 
						} else                                                                                    \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_EDMSG(m_msg)                                                                       \
 | 
				
			||||||
 | 
						if (true) {                                                                                     \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
 | 
				
			||||||
 | 
							return;                                                                                     \
 | 
				
			||||||
 | 
						} else                                                                                          \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if more complex error detection or recovery is required, and
 | 
				
			||||||
 | 
					 * there is no sensible error message.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_V(m_retval)                                                                                      \
 | 
				
			||||||
 | 
						if (true) {                                                                                                   \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                          \
 | 
				
			||||||
 | 
						} else                                                                                                        \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_V_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro if more complex error detection or recovery is required.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Prints `m_msg`, and the current function returns `m_retval`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_V_MSG(m_retval, m_msg)                                                                                  \
 | 
				
			||||||
 | 
						if (true) {                                                                                                          \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                 \
 | 
				
			||||||
 | 
						} else                                                                                                               \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_FAIL_V_MSG` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_FAIL_V_EDMSG(m_retval, m_msg)                                                                                      \
 | 
				
			||||||
 | 
						if (true) {                                                                                                                \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
 | 
				
			||||||
 | 
							return m_retval;                                                                                                       \
 | 
				
			||||||
 | 
						} else                                                                                                                     \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
 | 
				
			||||||
 | 
					 * Only use this macro at the start of a function that has not been implemented yet, or
 | 
				
			||||||
 | 
					 * if more complex error detection or recovery is required.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Prints `m_msg`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_PRINT(m_msg) \
 | 
				
			||||||
 | 
						_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_PRINT` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_PRINT_ED(m_msg) \
 | 
				
			||||||
 | 
						_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Prints `m_msg` once during the application lifetime.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_PRINT_ONCE(m_msg)                                          \
 | 
				
			||||||
 | 
						if (true) {                                                        \
 | 
				
			||||||
 | 
							static bool first_print = true;                                \
 | 
				
			||||||
 | 
							if (first_print) {                                             \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
 | 
				
			||||||
 | 
								first_print = false;                                       \
 | 
				
			||||||
 | 
							}                                                              \
 | 
				
			||||||
 | 
						} else                                                             \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `ERR_PRINT_ONCE` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ERR_PRINT_ONCE_ED(m_msg)                                             \
 | 
				
			||||||
 | 
						if (true) {                                                              \
 | 
				
			||||||
 | 
							static bool first_print = true;                                      \
 | 
				
			||||||
 | 
							if (first_print) {                                                   \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
 | 
				
			||||||
 | 
								first_print = false;                                             \
 | 
				
			||||||
 | 
							}                                                                    \
 | 
				
			||||||
 | 
						} else                                                                   \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Print warning message macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Prints `m_msg`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_PRINT(m_msg) \
 | 
				
			||||||
 | 
						_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `WARN_PRINT` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_PRINT_ED(m_msg) \
 | 
				
			||||||
 | 
						_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Prints `m_msg` once during the application lifetime.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_PRINT_ONCE(m_msg)                                                                     \
 | 
				
			||||||
 | 
						if (true) {                                                                                    \
 | 
				
			||||||
 | 
							static bool first_print = true;                                                            \
 | 
				
			||||||
 | 
							if (first_print) {                                                                         \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \
 | 
				
			||||||
 | 
								first_print = false;                                                                   \
 | 
				
			||||||
 | 
							}                                                                                          \
 | 
				
			||||||
 | 
						} else                                                                                         \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Same as `WARN_PRINT_ONCE` but also notifies the editor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_PRINT_ONCE_ED(m_msg)                                                                 \
 | 
				
			||||||
 | 
						if (true) {                                                                                   \
 | 
				
			||||||
 | 
							static bool first_print = true;                                                           \
 | 
				
			||||||
 | 
							if (first_print) {                                                                        \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \
 | 
				
			||||||
 | 
								first_print = false;                                                                  \
 | 
				
			||||||
 | 
							}                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                        \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Warns about `m_msg` only when verbose mode is enabled.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_VERBOSE(m_msg)               \
 | 
				
			||||||
 | 
						{                                     \
 | 
				
			||||||
 | 
							if (is_print_verbose_enabled()) { \
 | 
				
			||||||
 | 
								WARN_PRINT(m_msg);            \
 | 
				
			||||||
 | 
							}                                 \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Print deprecated warning message macros.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Warns that the current function is deprecated.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_DEPRECATED                                                                                                                                           \
 | 
				
			||||||
 | 
						if (true) {                                                                                                                                                   \
 | 
				
			||||||
 | 
							static std::atomic<bool> warning_shown;                                                                                                                   \
 | 
				
			||||||
 | 
							if (!warning_shown.load()) {                                                                                                                              \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \
 | 
				
			||||||
 | 
								warning_shown.store(true);                                                                                                                            \
 | 
				
			||||||
 | 
							}                                                                                                                                                         \
 | 
				
			||||||
 | 
						} else                                                                                                                                                        \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Warns that the current function is deprecated and prints `m_msg`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define WARN_DEPRECATED_MSG(m_msg)                                                                                                                                       \
 | 
				
			||||||
 | 
						if (true) {                                                                                                                                                          \
 | 
				
			||||||
 | 
							static std::atomic<bool> warning_shown;                                                                                                                          \
 | 
				
			||||||
 | 
							if (!warning_shown.load()) {                                                                                                                                     \
 | 
				
			||||||
 | 
								_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \
 | 
				
			||||||
 | 
								warning_shown.store(true);                                                                                                                                   \
 | 
				
			||||||
 | 
							}                                                                                                                                                                \
 | 
				
			||||||
 | 
						} else                                                                                                                                                               \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Do not use.
 | 
				
			||||||
 | 
					 * If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_NOW()                                                                           \
 | 
				
			||||||
 | 
						if (true) {                                                                               \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                  \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                      \
 | 
				
			||||||
 | 
						} else                                                                                    \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Only use if the application should never reach this point.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Prints `m_msg`, and then the application crashes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define CRASH_NOW_MSG(m_msg)                                                                         \
 | 
				
			||||||
 | 
						if (true) {                                                                                      \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                         \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                             \
 | 
				
			||||||
 | 
						} else                                                                                           \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Note: IN MOST CASES YOU SHOULD NOT USE THIS MACRO.
 | 
				
			||||||
 | 
					 * Do not use unless you understand the trade-offs.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DEV macros will be compiled out in releases, they are wrapped in DEV_ENABLED.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Prefer WARNINGS / ERR_FAIL macros (which fail without crashing) - ERR_FAIL should be used in most cases.
 | 
				
			||||||
 | 
					 * Then CRASH_NOW_MSG macros (on rare occasions where error cannot be recovered).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DEV_ASSERT should generally only be used when both of the following conditions are met:
 | 
				
			||||||
 | 
					 * 1) Bottleneck code where a check in release would be too expensive.
 | 
				
			||||||
 | 
					 * 2) Situations where the check would fail obviously and straight away during the maintenance of the code
 | 
				
			||||||
 | 
					 *    (i.e. strict conditions that should be true no matter what)
 | 
				
			||||||
 | 
					 *    and that can't fail for other contributors once the code is finished and merged.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifdef DEV_ENABLED
 | 
				
			||||||
 | 
					#define DEV_ASSERT(m_cond)                                                                                              \
 | 
				
			||||||
 | 
						if (unlikely(!(m_cond))) {                                                                                          \
 | 
				
			||||||
 | 
							_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed  \"" _STR(m_cond) "\" is false."); \
 | 
				
			||||||
 | 
							_err_flush_stdout();                                                                                            \
 | 
				
			||||||
 | 
							GENERATE_TRAP();                                                                                                \
 | 
				
			||||||
 | 
						} else                                                                                                              \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DEV_ASSERT(m_cond)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEV_ENABLED
 | 
				
			||||||
 | 
					#define DEV_CHECK_ONCE(m_cond)                                                   \
 | 
				
			||||||
 | 
						if (unlikely(!(m_cond))) {                                                   \
 | 
				
			||||||
 | 
							ERR_PRINT_ONCE("DEV_CHECK_ONCE failed  \"" _STR(m_cond) "\" is false."); \
 | 
				
			||||||
 | 
						} else                                                                       \
 | 
				
			||||||
 | 
							((void)0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DEV_CHECK_ONCE(m_cond)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ERROR_MACROS_H
 | 
				
			||||||
							
								
								
									
										17
									
								
								engine/core/extension/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								engine/core/extension/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import make_interface_dumper
 | 
				
			||||||
 | 
					import make_wrappers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
 | 
				
			||||||
 | 
					env.CommandNoCache(
 | 
				
			||||||
 | 
					    "gdextension_interface_dump.gen.h",
 | 
				
			||||||
 | 
					    ["gdextension_interface.h", "make_interface_dumper.py"],
 | 
				
			||||||
 | 
					    env.Run(make_interface_dumper.run),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_extension = env.Clone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env_extension.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
							
								
								
									
										1654
									
								
								engine/core/extension/extension_api_dump.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1654
									
								
								engine/core/extension/extension_api_dump.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										46
									
								
								engine/core/extension/extension_api_dump.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								engine/core/extension/extension_api_dump.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  extension_api_dump.h                                                  */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef EXTENSION_API_DUMP_H
 | 
				
			||||||
 | 
					#define EXTENSION_API_DUMP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/extension/gdextension.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionAPIDump {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Dictionary generate_extension_api(bool p_include_docs = false);
 | 
				
			||||||
 | 
						static void generate_extension_json_file(const String &p_path, bool p_include_docs = false);
 | 
				
			||||||
 | 
						static Error validate_extension_json_file(const String &p_path);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // EXTENSION_API_DUMP_H
 | 
				
			||||||
							
								
								
									
										49
									
								
								engine/core/extension/gdextension.compat.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								engine/core/extension/gdextension.compat.inc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension.compat.inc                                                */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) {
 | 
				
			||||||
 | 
						return ERR_UNAVAILABLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtension::_close_library_bind_compat_88418() {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtension::_initialize_library_bind_compat_88418(InitializationLevel p_level) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtension::_bind_compatibility_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88418);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("close_library"), &GDExtension::_close_library_bind_compat_88418);
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										1315
									
								
								engine/core/extension/gdextension.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1315
									
								
								engine/core/extension/gdextension.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										234
									
								
								engine/core/extension/gdextension.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								engine/core/extension/gdextension.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,234 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/extension/gdextension_interface.h"
 | 
				
			||||||
 | 
					#include "core/io/config_file.h"
 | 
				
			||||||
 | 
					#include "core/io/resource_loader.h"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					#include "core/os/shared_object.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionMethodBind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtension : public Resource {
 | 
				
			||||||
 | 
						GDCLASS(GDExtension, Resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class GDExtensionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *library = nullptr; // pointer if valid,
 | 
				
			||||||
 | 
						String library_path;
 | 
				
			||||||
 | 
						bool reloadable = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Extension {
 | 
				
			||||||
 | 
							ObjectGDExtension gdextension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
							bool is_reloading = false;
 | 
				
			||||||
 | 
							HashMap<StringName, GDExtensionMethodBind *> methods;
 | 
				
			||||||
 | 
							HashSet<ObjectID> instances;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct InstanceState {
 | 
				
			||||||
 | 
								List<Pair<String, Variant>> properties;
 | 
				
			||||||
 | 
								bool is_placeholder = false;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							HashMap<ObjectID, InstanceState> instance_state;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<StringName, Extension> extension_classes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ClassCreationDeprecatedInfo {
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
							GDExtensionClassNotification notification_func = nullptr;
 | 
				
			||||||
 | 
							GDExtensionClassFreePropertyList free_property_list_func = nullptr;
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs);
 | 
				
			||||||
 | 
						static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
 | 
				
			||||||
 | 
					#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_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);
 | 
				
			||||||
 | 
						static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
 | 
				
			||||||
 | 
						static void _register_extension_class_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info);
 | 
				
			||||||
 | 
						static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
 | 
				
			||||||
 | 
						static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
 | 
				
			||||||
 | 
						static void _register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
 | 
				
			||||||
 | 
						static void _register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_group_name, GDExtensionConstStringNamePtr p_prefix);
 | 
				
			||||||
 | 
						static void _register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_subgroup_name, GDExtensionConstStringNamePtr p_prefix);
 | 
				
			||||||
 | 
						static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
 | 
				
			||||||
 | 
						static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
 | 
				
			||||||
 | 
						static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDExtensionInitialization initialization;
 | 
				
			||||||
 | 
						int32_t level_initialized = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						uint64_t resource_last_modified_time = 0;
 | 
				
			||||||
 | 
						uint64_t library_last_modified_time = 0;
 | 
				
			||||||
 | 
						bool is_reloading = false;
 | 
				
			||||||
 | 
						Vector<GDExtensionMethodBind *> invalid_methods;
 | 
				
			||||||
 | 
						Vector<ObjectID> instance_bindings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _track_instance(void *p_user_data, void *p_instance);
 | 
				
			||||||
 | 
						static void _untrack_instance(void *p_user_data, void *p_instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _clear_extension(Extension *p_extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Only called by GDExtensionManager during the reload process.
 | 
				
			||||||
 | 
						void prepare_reload();
 | 
				
			||||||
 | 
						void finish_reload();
 | 
				
			||||||
 | 
						void clear_instance_bindings();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						HashMap<String, String> class_icon_paths;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool editor_can_reload_from_file() override { return false; } // Reloading is handled in a special way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static String get_extension_list_config_file();
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						void close_library();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum InitializationLevel {
 | 
				
			||||||
 | 
							INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
 | 
				
			||||||
 | 
							INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
 | 
				
			||||||
 | 
							INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
 | 
				
			||||||
 | 
							INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						Error _open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol);
 | 
				
			||||||
 | 
						void _close_library_bind_compat_88418();
 | 
				
			||||||
 | 
						void _initialize_library_bind_compat_88418(InitializationLevel p_level);
 | 
				
			||||||
 | 
						static void _bind_compatibility_methods();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						bool is_library_open() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						bool is_reloadable() const { return reloadable; }
 | 
				
			||||||
 | 
						void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 untrack_instance_binding(Object *p_object);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InitializationLevel get_minimum_library_initialization_level() const;
 | 
				
			||||||
 | 
						void initialize_library(InitializationLevel p_level);
 | 
				
			||||||
 | 
						void deinitialize_library(InitializationLevel p_level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
 | 
				
			||||||
 | 
						static GDExtensionInterfaceFunctionPtr get_interface_function(const StringName &p_function_name);
 | 
				
			||||||
 | 
						static void initialize_gdextensions();
 | 
				
			||||||
 | 
						static void finalize_gdextensions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDExtension();
 | 
				
			||||||
 | 
						~GDExtension();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(GDExtension::InitializationLevel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionResourceLoader : public ResourceFormatLoader {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
 | 
				
			||||||
 | 
						virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 | 
				
			||||||
 | 
						virtual bool handles_type(const String &p_type) const override;
 | 
				
			||||||
 | 
						virtual String get_resource_type(const String &p_path) const override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
					class GDExtensionEditorPlugins {
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						static Vector<StringName> extension_classes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						friend class EditorNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Since this in core, we can't directly reference EditorNode, so it will
 | 
				
			||||||
 | 
						// set these function pointers in its constructor.
 | 
				
			||||||
 | 
						typedef void (*EditorPluginRegisterFunc)(const StringName &p_class_name);
 | 
				
			||||||
 | 
						static EditorPluginRegisterFunc editor_node_add_plugin;
 | 
				
			||||||
 | 
						static EditorPluginRegisterFunc editor_node_remove_plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static void add_extension_class(const StringName &p_class_name);
 | 
				
			||||||
 | 
						static void remove_extension_class(const StringName &p_class_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static const Vector<StringName> &get_extension_classes() {
 | 
				
			||||||
 | 
							return extension_classes;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionEditorHelp {
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						friend class EditorHelp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Similarly to EditorNode above, we need to be able to ask EditorHelp to parse
 | 
				
			||||||
 | 
						// new documentation data. Note though that, differently from EditorHelp, this
 | 
				
			||||||
 | 
						// is initialized even _before_ it gets instantiated, as we need to rely on
 | 
				
			||||||
 | 
						// this method while initializing the engine.
 | 
				
			||||||
 | 
						typedef void (*EditorHelpLoadXmlBufferFunc)(const uint8_t *p_buffer, int p_size);
 | 
				
			||||||
 | 
						static EditorHelpLoadXmlBufferFunc editor_help_load_xml_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef void (*EditorHelpRemoveClassFunc)(const String &p_class);
 | 
				
			||||||
 | 
						static EditorHelpRemoveClassFunc editor_help_remove_class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
 | 
				
			||||||
 | 
						static void remove_class(const String &p_class);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_H
 | 
				
			||||||
							
								
								
									
										971
									
								
								engine/core/extension/gdextension_compat_hashes.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										971
									
								
								engine/core/extension/gdextension_compat_hashes.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,971 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_compat_hashes.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_compat_hashes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HashMap<StringName, LocalVector<GDExtensionCompatHashes::Mapping>> GDExtensionCompatHashes::mappings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionCompatHashes::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);
 | 
				
			||||||
 | 
						if (!methods) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const Mapping &mapping : *methods) {
 | 
				
			||||||
 | 
							if (mapping.method == p_method && mapping.legacy_hash == p_legacy_hash) {
 | 
				
			||||||
 | 
								*r_current_hash = mapping.current_hash;
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionCompatHashes::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);
 | 
				
			||||||
 | 
						if (!methods) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
						for (const Mapping &mapping : *methods) {
 | 
				
			||||||
 | 
							if (mapping.method == p_method) {
 | 
				
			||||||
 | 
								if (p_check_valid) {
 | 
				
			||||||
 | 
									MethodBind *mb = ClassDB::get_method_with_compatibility(p_class, p_method, mapping.current_hash);
 | 
				
			||||||
 | 
									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));
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								r_hashes.push_back(mapping.legacy_hash);
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionCompatHashes::initialize() {
 | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						mappings.insert("AESContext", {
 | 
				
			||||||
 | 
							{ "start", 3167574919, 3122411423 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AStar2D", {
 | 
				
			||||||
 | 
							{ "add_point", 3370185124, 4074201818 },
 | 
				
			||||||
 | 
							{ "set_point_disabled", 4023243586, 972357352 },
 | 
				
			||||||
 | 
							{ "connect_points", 3785370599, 3710494224 },
 | 
				
			||||||
 | 
							{ "disconnect_points", 3785370599, 3710494224 },
 | 
				
			||||||
 | 
							{ "are_points_connected", 4063588998, 2288175859 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AStar3D", {
 | 
				
			||||||
 | 
							{ "add_point", 2920922839, 1038703438 },
 | 
				
			||||||
 | 
							{ "set_point_disabled", 4023243586, 972357352 },
 | 
				
			||||||
 | 
							{ "connect_points", 3785370599, 3710494224 },
 | 
				
			||||||
 | 
							{ "disconnect_points", 3785370599, 3710494224 },
 | 
				
			||||||
 | 
							{ "are_points_connected", 4063588998, 2288175859 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AStarGrid2D", {
 | 
				
			||||||
 | 
							{ "set_point_solid", 2825551965, 1765703753 },
 | 
				
			||||||
 | 
							{ "fill_solid_region", 1152863744, 2261970063 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AcceptDialog", {
 | 
				
			||||||
 | 
							{ "add_button", 4158837846, 3328440682 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Animation", {
 | 
				
			||||||
 | 
							{ "add_track", 2393815928, 3843682357 },
 | 
				
			||||||
 | 
							{ "track_insert_key", 1985425300, 808952278 },
 | 
				
			||||||
 | 
							{ "track_find_key", 3898229885, 3245197284 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "bezier_track_insert_key", 1057544502, 3767441357 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "bezier_track_insert_key", 1057544502, 3656773645 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							{ "bezier_track_set_key_in_handle", 1028302688, 1719223284 },
 | 
				
			||||||
 | 
							{ "bezier_track_set_key_out_handle", 1028302688, 1719223284 },
 | 
				
			||||||
 | 
							{ "audio_track_insert_key", 3489962123, 4021027286 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNode", {
 | 
				
			||||||
 | 
							{ "blend_animation", 11797022, 1630801826 },
 | 
				
			||||||
 | 
							{ "blend_node", 263389446, 1746075988 },
 | 
				
			||||||
 | 
							{ "blend_input", 2709059328, 1361527350 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNodeBlendSpace1D", {
 | 
				
			||||||
 | 
							{ "add_blend_point", 4069484420, 285050433 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNodeBlendSpace2D", {
 | 
				
			||||||
 | 
							{ "add_blend_point", 1533588937, 402261981 },
 | 
				
			||||||
 | 
							{ "add_triangle", 642454959, 753017335 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNodeBlendTree", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_node", 2055804584, 1407702499 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "add_node", 2055804584, 1980270704 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNodeStateMachine", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_node", 2055804584, 1407702499 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "add_node", 2055804584, 1980270704 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AnimationNodeStateMachinePlayback", {
 | 
				
			||||||
 | 
							{ "travel", 3683006648, 3823612587 },
 | 
				
			||||||
 | 
							{ "start", 3683006648, 3823612587 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ArrayMesh", {
 | 
				
			||||||
 | 
							{ "add_surface_from_arrays", 172284304, 1796411378 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AudioEffectSpectrumAnalyzerInstance", {
 | 
				
			||||||
 | 
							{ "get_magnitude_for_frequency_range", 2693213071, 797993915 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AudioServer", {
 | 
				
			||||||
 | 
							{ "add_bus_effect", 4147765248, 4068819785 },
 | 
				
			||||||
 | 
							{ "get_bus_effect_instance", 2887144608, 1829771234 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AudioStreamPlaybackPolyphonic", {
 | 
				
			||||||
 | 
							{ "play_stream", 3792189967, 604492179 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("AudioStreamRandomizer", {
 | 
				
			||||||
 | 
							{ "add_stream", 3197802065, 1892018854 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("BitMap", {
 | 
				
			||||||
 | 
							{ "create_from_image_alpha", 505265891, 106271684 },
 | 
				
			||||||
 | 
							{ "opaque_to_polygons", 876132484, 48478126 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("CanvasItem", {
 | 
				
			||||||
 | 
							{ "draw_line", 2516941890, 1562330099 },
 | 
				
			||||||
 | 
							{ "draw_dashed_line", 2175215884, 684651049 },
 | 
				
			||||||
 | 
							{ "draw_polyline", 4175878946, 3797364428 },
 | 
				
			||||||
 | 
							{ "draw_polyline_colors", 2239164197, 2311979562 },
 | 
				
			||||||
 | 
							{ "draw_arc", 3486841771, 4140652635 },
 | 
				
			||||||
 | 
							{ "draw_multiline", 4230657331, 2239075205 },
 | 
				
			||||||
 | 
							{ "draw_multiline_colors", 235933050, 4072951537 },
 | 
				
			||||||
 | 
							{ "draw_rect", 84391229, 2417231121 },
 | 
				
			||||||
 | 
							{ "draw_texture", 1695860435, 520200117 },
 | 
				
			||||||
 | 
							{ "draw_texture_rect", 3204081724, 3832805018 },
 | 
				
			||||||
 | 
							{ "draw_texture_rect_region", 3196597532, 3883821411 },
 | 
				
			||||||
 | 
							{ "draw_msdf_texture_rect_region", 2672026175, 4219163252 },
 | 
				
			||||||
 | 
							{ "draw_lcd_texture_rect_region", 169610548, 3212350954 },
 | 
				
			||||||
 | 
							{ "draw_primitive", 2248678295, 3288481815 },
 | 
				
			||||||
 | 
							{ "draw_polygon", 2683625537, 974537912 },
 | 
				
			||||||
 | 
							{ "draw_colored_polygon", 1659099617, 15245644 },
 | 
				
			||||||
 | 
							{ "draw_string", 2552080639, 728290553 },
 | 
				
			||||||
 | 
							{ "draw_multiline_string", 4002645436, 1927038192 },
 | 
				
			||||||
 | 
							{ "draw_string_outline", 850005221, 340562381 },
 | 
				
			||||||
 | 
							{ "draw_multiline_string_outline", 3717870722, 1912318525 },
 | 
				
			||||||
 | 
							{ "draw_char", 2329089032, 3339793283 },
 | 
				
			||||||
 | 
							{ "draw_char_outline", 419453826, 3302344391 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "draw_mesh", 1634855856, 4036154158 },
 | 
				
			||||||
 | 
							{ "draw_set_transform", 3283884939, 156553079 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "draw_mesh", 1634855856, 153818295 },
 | 
				
			||||||
 | 
							{ "draw_set_transform", 3283884939, 288975085 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							{ "draw_animation_slice", 2295343543, 3112831842 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("CodeEdit", {
 | 
				
			||||||
 | 
							{ "is_in_string", 3294126239, 688195400 },
 | 
				
			||||||
 | 
							{ "is_in_comment", 3294126239, 688195400 },
 | 
				
			||||||
 | 
							{ "add_code_completion_option", 1629240608, 947964390 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Control", {
 | 
				
			||||||
 | 
							{ "set_offsets_preset", 3651818904, 3724524307 },
 | 
				
			||||||
 | 
							{ "set_anchors_and_offsets_preset", 3651818904, 3724524307 },
 | 
				
			||||||
 | 
							{ "set_anchor", 2589937826, 2302782885 },
 | 
				
			||||||
 | 
							{ "get_theme_icon", 2336455395, 3163973443 },
 | 
				
			||||||
 | 
							{ "get_theme_stylebox", 2759935355, 604739069 },
 | 
				
			||||||
 | 
							{ "get_theme_font", 387378635, 2826986490 },
 | 
				
			||||||
 | 
							{ "get_theme_font_size", 229578101, 1327056374 },
 | 
				
			||||||
 | 
							{ "get_theme_color", 2377051548, 2798751242 },
 | 
				
			||||||
 | 
							{ "get_theme_constant", 229578101, 1327056374 },
 | 
				
			||||||
 | 
							{ "has_theme_icon", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_stylebox", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_font", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_font_size", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_color", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_constant", 1187511791, 866386512 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Crypto", {
 | 
				
			||||||
 | 
							{ "generate_self_signed_certificate", 947314696, 492266173 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Curve", {
 | 
				
			||||||
 | 
							{ "add_point", 2766148617, 434072736 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Curve2D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_point", 529706502, 3343370600 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "add_point", 2437345566, 4175465202 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Curve3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_point", 3544159631, 917388502 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "add_point", 3836314258, 2931053748 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("DirAccess", {
 | 
				
			||||||
 | 
							{ "list_dir_begin", 2018049411, 2610976713 },
 | 
				
			||||||
 | 
							{ "copy", 198434953, 1063198817 },
 | 
				
			||||||
 | 
							{ "copy_absolute", 198434953, 1063198817 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("DisplayServer", {
 | 
				
			||||||
 | 
							{ "global_menu_add_submenu_item", 3806306913, 2828985934 },
 | 
				
			||||||
 | 
							{ "global_menu_add_item", 3415468211, 3401266716 },
 | 
				
			||||||
 | 
							{ "global_menu_add_check_item", 3415468211, 3401266716 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_item", 1700867534, 4245856523 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_check_item", 1700867534, 4245856523 },
 | 
				
			||||||
 | 
							{ "global_menu_add_radio_check_item", 3415468211, 3401266716 },
 | 
				
			||||||
 | 
							{ "global_menu_add_icon_radio_check_item", 1700867534, 4245856523 },
 | 
				
			||||||
 | 
							{ "global_menu_add_multistate_item", 635750054, 3431222859 },
 | 
				
			||||||
 | 
							{ "global_menu_add_separator", 1041533178, 3214812433 },
 | 
				
			||||||
 | 
							{ "tts_speak", 3741216677, 903992738 },
 | 
				
			||||||
 | 
							{ "is_touchscreen_available", 4162880507, 3323674545 },
 | 
				
			||||||
 | 
							{ "screen_set_orientation", 2629526904, 2211511631 },
 | 
				
			||||||
 | 
							{ "window_get_native_handle", 2709193271, 1096425680 },
 | 
				
			||||||
 | 
							{ "window_set_title", 3043792800, 441246282 },
 | 
				
			||||||
 | 
							{ "window_set_mouse_passthrough", 3958815166, 1993637420 },
 | 
				
			||||||
 | 
							{ "window_set_current_screen", 3023605688, 2230941749 },
 | 
				
			||||||
 | 
							{ "window_set_position", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_size", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_rect_changed_callback", 3653650673, 1091192925 },
 | 
				
			||||||
 | 
							{ "window_set_window_event_callback", 3653650673, 1091192925 },
 | 
				
			||||||
 | 
							{ "window_set_input_event_callback", 3653650673, 1091192925 },
 | 
				
			||||||
 | 
							{ "window_set_input_text_callback", 3653650673, 1091192925 },
 | 
				
			||||||
 | 
							{ "window_set_drop_files_callback", 3653650673, 1091192925 },
 | 
				
			||||||
 | 
							{ "window_set_max_size", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_min_size", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_mode", 2942569511, 1319965401 },
 | 
				
			||||||
 | 
							{ "window_set_flag", 3971592565, 254894155 },
 | 
				
			||||||
 | 
							{ "window_get_flag", 2662949986, 802816991 },
 | 
				
			||||||
 | 
							{ "window_set_window_buttons_offset", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_ime_active", 450484987, 1661950165 },
 | 
				
			||||||
 | 
							{ "window_set_ime_position", 3614040015, 2019273902 },
 | 
				
			||||||
 | 
							{ "window_set_vsync_mode", 1708924624, 2179333492 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "cursor_set_custom_image", 1358907026, 4163678968 },
 | 
				
			||||||
 | 
							{ "virtual_keyboard_show", 384539973, 1323934605 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "cursor_set_custom_image", 1358907026, 1816663697 },
 | 
				
			||||||
 | 
							{ "virtual_keyboard_show", 860410478, 3042891259 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ENetConnection", {
 | 
				
			||||||
 | 
							{ "create_host_bound", 866250949, 1515002313 },
 | 
				
			||||||
 | 
							{ "connect_to_host", 385984708, 2171300490 },
 | 
				
			||||||
 | 
							{ "dtls_client_setup", 3097527179, 1966198364 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ENetMultiplayerPeer", {
 | 
				
			||||||
 | 
							{ "create_server", 1616151701, 2917761309 },
 | 
				
			||||||
 | 
							{ "create_client", 920217784, 2327163476 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorCommandPalette", {
 | 
				
			||||||
 | 
							{ "add_command", 3664614892, 864043298 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorDebuggerSession", {
 | 
				
			||||||
 | 
							{ "send_message", 3780025912, 85656714 },
 | 
				
			||||||
 | 
							{ "toggle_profiler", 35674246, 1198443697 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorFileDialog", {
 | 
				
			||||||
 | 
							{ "add_filter", 233059325, 3388804757 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorImportPlugin", {
 | 
				
			||||||
 | 
							{ "append_import_external_resource", 3645925746, 320493106 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorInterface", {
 | 
				
			||||||
 | 
							{ "popup_dialog", 2478844058, 2015770942 },
 | 
				
			||||||
 | 
							{ "popup_dialog_centered", 1723337679, 346557367 },
 | 
				
			||||||
 | 
							{ "popup_dialog_centered_ratio", 1310934579, 2093669136 },
 | 
				
			||||||
 | 
							{ "popup_dialog_centered_clamped", 3433759678, 3763385571 },
 | 
				
			||||||
 | 
							{ "inspect_object", 2564140749, 127962172 },
 | 
				
			||||||
 | 
							{ "edit_script", 3664508569, 219829402 },
 | 
				
			||||||
 | 
							{ "save_scene_as", 1168363258, 3647332257 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorNode3DGizmo", {
 | 
				
			||||||
 | 
							{ "add_lines", 302451090, 2910971437 },
 | 
				
			||||||
 | 
						#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_mesh", 3332776472, 2161761131 },
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							{ "add_mesh", 1868867708, 1579955111 },
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
							{ "add_unscaled_billboard", 3719733075, 520007164 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorNode3DGizmoPlugin", {
 | 
				
			||||||
 | 
							{ "create_icon_material", 2976007329, 3804976916 },
 | 
				
			||||||
 | 
							{ "get_material", 3501703615, 974464017 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorScenePostImportPlugin", {
 | 
				
			||||||
 | 
							{ "add_import_option_advanced", 3774155785, 3674075649 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EditorUndoRedoManager", {
 | 
				
			||||||
 | 
							{ "create_action", 3577985681, 2107025470 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("EngineDebugger", {
 | 
				
			||||||
 | 
							{ "profiler_enable", 438160728, 3192561009 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Expression", {
 | 
				
			||||||
 | 
							{ "parse", 3658149758, 3069722906 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("FileAccess", {
 | 
				
			||||||
 | 
							{ "open_compressed", 2874458257, 3686439335 },
 | 
				
			||||||
 | 
							{ "store_csv_line", 2217842308, 2173791505 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("FileDialog", {
 | 
				
			||||||
 | 
							{ "add_filter", 233059325, 3388804757 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Font", {
 | 
				
			||||||
 | 
							{ "get_string_size", 3678918099, 1868866121 },
 | 
				
			||||||
 | 
							{ "get_multiline_string_size", 2427690650, 519636710 },
 | 
				
			||||||
 | 
							{ "draw_string", 2565402639, 1983721962 },
 | 
				
			||||||
 | 
							{ "draw_multiline_string", 348869189, 1171506176 },
 | 
				
			||||||
 | 
							{ "draw_string_outline", 657875837, 623754045 },
 | 
				
			||||||
 | 
							{ "draw_multiline_string_outline", 1649790182, 3206388178 },
 | 
				
			||||||
 | 
							{ "draw_char", 1462476057, 3815617597 },
 | 
				
			||||||
 | 
							{ "draw_char_outline", 4161008124, 209525354 },
 | 
				
			||||||
 | 
						#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "find_variation", 625117670, 2196349508 },
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							{ "find_variation", 1222433716, 3344325384 },
 | 
				
			||||||
 | 
							// Pre-existing compatibility hash.
 | 
				
			||||||
 | 
							{ "find_variation", 1149405976, 1851767612 },
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("GLTFDocument", {
 | 
				
			||||||
 | 
							{ "append_from_file", 1862991421, 866380864 },
 | 
				
			||||||
 | 
							{ "append_from_buffer", 2818062664, 1616081266 },
 | 
				
			||||||
 | 
							{ "append_from_scene", 374125375, 1622574258 },
 | 
				
			||||||
 | 
							{ "generate_scene", 2770277081, 596118388 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Geometry2D", {
 | 
				
			||||||
 | 
							{ "offset_polygon", 3837618924, 1275354010 },
 | 
				
			||||||
 | 
							{ "offset_polyline", 328033063, 2328231778 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Geometry3D", {
 | 
				
			||||||
 | 
							{ "build_cylinder_planes", 3142160516, 449920067 },
 | 
				
			||||||
 | 
							{ "build_capsule_planes", 410870045, 2113592876 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("GraphNode", {
 | 
				
			||||||
 | 
							{ "set_slot", 902131739, 2873310869 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("GridMap", {
 | 
				
			||||||
 | 
							{ "set_cell_item", 4177201334, 3449088946 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("HTTPClient", {
 | 
				
			||||||
 | 
							{ "connect_to_host", 1970282951, 504540374 },
 | 
				
			||||||
 | 
							{ "request", 3249905507, 3778990155 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("HTTPRequest", {
 | 
				
			||||||
 | 
							{ "request", 2720304520, 3215244323 },
 | 
				
			||||||
 | 
							{ "request_raw", 4282724657, 2714829993 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("IP", {
 | 
				
			||||||
 | 
							{ "resolve_hostname", 396864159, 4283295457 },
 | 
				
			||||||
 | 
							{ "resolve_hostname_addresses", 3462780090, 773767525 },
 | 
				
			||||||
 | 
							{ "resolve_hostname_queue_item", 3936392508, 1749894742 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Image", {
 | 
				
			||||||
 | 
							{ "resize", 2461393748, 994498151 },
 | 
				
			||||||
 | 
							{ "save_jpg", 578836491, 2800019068 },
 | 
				
			||||||
 | 
							{ "save_webp", 3594949219, 2781156876 },
 | 
				
			||||||
 | 
							{ "compress", 4094210332, 2975424957 },
 | 
				
			||||||
 | 
							{ "compress_from_channels", 279105990, 4212890953 },
 | 
				
			||||||
 | 
							{ "load_svg_from_buffer", 1822513750, 311853421 },
 | 
				
			||||||
 | 
							{ "load_svg_from_string", 1461766635, 3254053600 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ImmediateMesh", {
 | 
				
			||||||
 | 
							{ "surface_begin", 3716480242, 2794442543 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ImporterMesh", {
 | 
				
			||||||
 | 
							{ "add_surface", 4122361985, 1740448849 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Input", {
 | 
				
			||||||
 | 
							{ "get_vector", 1517139831, 2479607902 },
 | 
				
			||||||
 | 
							{ "start_joy_vibration", 1890603622, 2576575033 },
 | 
				
			||||||
 | 
							{ "action_press", 573731101, 1713091165 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "set_custom_mouse_cursor", 3489634142, 1277868338 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "set_custom_mouse_cursor", 3489634142, 703945977 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("InputEvent", {
 | 
				
			||||||
 | 
							{ "is_match", 3392494811, 1754951977 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "xformed_by", 2747409789, 3242949850 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "xformed_by", 2747409789, 1282766827 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("InputMap", {
 | 
				
			||||||
 | 
							{ "add_action", 573731101, 4100757082 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ItemList", {
 | 
				
			||||||
 | 
							{ "add_item", 4086250691, 359861678 },
 | 
				
			||||||
 | 
							{ "add_icon_item", 3332687421, 4256579627 },
 | 
				
			||||||
 | 
							{ "get_item_rect", 1501513492, 159227807 },
 | 
				
			||||||
 | 
							{ "select", 4023243586, 972357352 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("JSON", {
 | 
				
			||||||
 | 
							{ "stringify", 2656701787, 462733549 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("JavaScriptBridge", {
 | 
				
			||||||
 | 
							{ "download_buffer", 4123979296, 3352272093 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Line2D", {
 | 
				
			||||||
 | 
							{ "add_point", 468506575, 2654014372 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("MultiplayerAPI", {
 | 
				
			||||||
 | 
							{ "rpc", 1833408346, 2077486355 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("NavigationMeshGenerator", {
 | 
				
			||||||
 | 
							{ "parse_source_geometry_data", 3703028813, 685862123 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 3669016597, 2469318639 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("NavigationServer2D", {
 | 
				
			||||||
 | 
							{ "map_get_path", 56240621, 3146466012 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("NavigationServer3D", {
 | 
				
			||||||
 | 
							{ "map_get_path", 2121045993, 1187418690 },
 | 
				
			||||||
 | 
							{ "parse_source_geometry_data", 3703028813, 685862123 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data", 3669016597, 2469318639 },
 | 
				
			||||||
 | 
							{ "bake_from_source_geometry_data_async", 3669016597, 2469318639 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Node", {
 | 
				
			||||||
 | 
							{ "add_child", 3070154285, 3863233950 },
 | 
				
			||||||
 | 
							{ "reparent", 2570952461, 3685795103 },
 | 
				
			||||||
 | 
							{ "find_child", 4253159453, 2008217037 },
 | 
				
			||||||
 | 
							{ "find_children", 1585018254, 2560337219 },
 | 
				
			||||||
 | 
							{ "propagate_call", 1667910434, 1871007965 },
 | 
				
			||||||
 | 
							{ "set_multiplayer_authority", 4023243586, 972357352 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Node3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "look_at", 136915519, 819337406 },
 | 
				
			||||||
 | 
							{ "look_at_from_position", 4067663783, 1809580162 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "look_at", 3123400617, 2882425029 },
 | 
				
			||||||
 | 
							{ "look_at_from_position", 4067663783, 2086826090 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Noise", {
 | 
				
			||||||
 | 
							{ "get_image", 2569233413, 3180683109 },
 | 
				
			||||||
 | 
							{ "get_seamless_image", 2210827790, 2770743602 },
 | 
				
			||||||
 | 
							{ "get_image_3d", 2358868431, 3977814329 },
 | 
				
			||||||
 | 
							{ "get_seamless_image_3d", 3328694319, 451006340 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("OS", {
 | 
				
			||||||
 | 
							{ "alert", 233059325, 1783970740 },
 | 
				
			||||||
 | 
							{ "get_system_font_path", 2262142305, 626580860 },
 | 
				
			||||||
 | 
							{ "get_system_font_path_for_text", 3824042574, 197317981 },
 | 
				
			||||||
 | 
							{ "execute", 2881709059, 1488299882 },
 | 
				
			||||||
 | 
							{ "shell_show_in_file_manager", 885841341, 3565188097 },
 | 
				
			||||||
 | 
							{ "set_restart_on_exit", 611198603, 3331453935 },
 | 
				
			||||||
 | 
							{ "get_system_dir", 1965199849, 3073895123 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Object", {
 | 
				
			||||||
 | 
							{ "add_user_signal", 3780025912, 85656714 },
 | 
				
			||||||
 | 
							{ "connect", 1469446357, 1518946055 },
 | 
				
			||||||
 | 
							{ "tr", 2475554935, 1195764410 },
 | 
				
			||||||
 | 
							{ "tr_n", 4021311862, 162698058 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("OptionButton", {
 | 
				
			||||||
 | 
							{ "add_item", 3043792800, 2697778442 },
 | 
				
			||||||
 | 
							{ "add_icon_item", 3944051090, 3781678508 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PCKPacker", {
 | 
				
			||||||
 | 
							{ "pck_start", 3232891339, 508410629 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PacketPeerDTLS", {
 | 
				
			||||||
 | 
							{ "connect_to_peer", 1801538152, 2880188099 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PacketPeerUDP", {
 | 
				
			||||||
 | 
							{ "bind", 4290438434, 4051239242 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Performance", {
 | 
				
			||||||
 | 
							{ "add_custom_monitor", 2865980031, 4099036814 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicalBone3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsBody2D", {
 | 
				
			||||||
 | 
							{ "move_and_collide", 1529961754, 3681923724 },
 | 
				
			||||||
 | 
							{ "test_move", 1369208982, 3324464701 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsBody3D", {
 | 
				
			||||||
 | 
							{ "move_and_collide", 2825704414, 3208792678 },
 | 
				
			||||||
 | 
							{ "test_move", 680299713, 2481691619 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsDirectBodyState2D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "apply_impulse", 496058220, 1271588277 },
 | 
				
			||||||
 | 
							{ "apply_force", 496058220, 1271588277 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 496058220, 1271588277 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "apply_impulse", 496058220, 4288681949 },
 | 
				
			||||||
 | 
							{ "apply_force", 496058220, 4288681949 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 496058220, 4288681949 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsDirectBodyState3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
							{ "apply_force", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
							{ "apply_force", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsDirectSpaceState2D", {
 | 
				
			||||||
 | 
							{ "intersect_point", 3278207904, 2118456068 },
 | 
				
			||||||
 | 
							{ "intersect_shape", 3803848594, 2488867228 },
 | 
				
			||||||
 | 
							{ "collide_shape", 3803848594, 2488867228 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsDirectSpaceState3D", {
 | 
				
			||||||
 | 
							{ "intersect_point", 45993382, 975173756 },
 | 
				
			||||||
 | 
							{ "intersect_shape", 550215980, 3762137681 },
 | 
				
			||||||
 | 
							{ "collide_shape", 550215980, 3762137681 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsRayQueryParameters2D", {
 | 
				
			||||||
 | 
							{ "create", 1118143851, 3196569324 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsRayQueryParameters3D", {
 | 
				
			||||||
 | 
							{ "create", 680321959, 3110599579 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsServer2D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "area_add_shape", 754862190, 3597527023 },
 | 
				
			||||||
 | 
							{ "body_add_shape", 754862190, 3597527023 },
 | 
				
			||||||
 | 
							{ "body_apply_impulse", 34330743, 1124035137 },
 | 
				
			||||||
 | 
							{ "body_apply_force", 34330743, 1124035137 },
 | 
				
			||||||
 | 
							{ "body_add_constant_force", 34330743, 1124035137 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "area_add_shape", 754862190, 339056240 },
 | 
				
			||||||
 | 
							{ "body_add_shape", 754862190, 339056240 },
 | 
				
			||||||
 | 
							{ "body_apply_impulse", 34330743, 205485391 },
 | 
				
			||||||
 | 
							{ "body_apply_force", 34330743, 205485391 },
 | 
				
			||||||
 | 
							{ "body_add_constant_force", 34330743, 205485391 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							{ "joint_make_pin", 2288600450, 1612646186 },
 | 
				
			||||||
 | 
							{ "joint_make_groove", 3573265764, 481430435 },
 | 
				
			||||||
 | 
							{ "joint_make_damped_spring", 206603952, 1994657646 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PhysicsServer3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "area_add_shape", 4040559639, 183938777 },
 | 
				
			||||||
 | 
							{ "body_add_shape", 4040559639, 183938777 },
 | 
				
			||||||
 | 
							{ "body_apply_impulse", 110375048, 2238283471 },
 | 
				
			||||||
 | 
							{ "body_apply_force", 110375048, 2238283471 },
 | 
				
			||||||
 | 
							{ "body_add_constant_force", 110375048, 2238283471 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "area_add_shape", 4040559639, 3711419014 },
 | 
				
			||||||
 | 
							{ "body_add_shape", 4040559639, 3711419014 },
 | 
				
			||||||
 | 
							{ "body_apply_impulse", 110375048, 390416203 },
 | 
				
			||||||
 | 
							{ "body_apply_force", 110375048, 390416203 },
 | 
				
			||||||
 | 
							{ "body_add_constant_force", 110375048, 390416203 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PopupMenu", {
 | 
				
			||||||
 | 
							{ "add_item", 3224536192, 3674230041 },
 | 
				
			||||||
 | 
							{ "add_icon_item", 1200674553, 1086190128 },
 | 
				
			||||||
 | 
							{ "add_check_item", 3224536192, 3674230041 },
 | 
				
			||||||
 | 
							{ "add_icon_check_item", 1200674553, 1086190128 },
 | 
				
			||||||
 | 
							{ "add_radio_check_item", 3224536192, 3674230041 },
 | 
				
			||||||
 | 
							{ "add_icon_radio_check_item", 1200674553, 1086190128 },
 | 
				
			||||||
 | 
							{ "add_multistate_item", 1585218420, 150780458 },
 | 
				
			||||||
 | 
							{ "add_shortcut", 2482211467, 3451850107 },
 | 
				
			||||||
 | 
							{ "add_icon_shortcut", 3060251822, 2997871092 },
 | 
				
			||||||
 | 
							{ "add_check_shortcut", 2168272394, 1642193386 },
 | 
				
			||||||
 | 
							{ "add_icon_check_shortcut", 68101841, 3856247530 },
 | 
				
			||||||
 | 
							{ "add_radio_check_shortcut", 2168272394, 1642193386 },
 | 
				
			||||||
 | 
							{ "add_icon_radio_check_shortcut", 68101841, 3856247530 },
 | 
				
			||||||
 | 
							{ "add_submenu_item", 3728518296, 2979222410 },
 | 
				
			||||||
 | 
							// Pre-existing compatibility hashes.
 | 
				
			||||||
 | 
							{ "add_icon_shortcut", 68101841, 3856247530 },
 | 
				
			||||||
 | 
							{ "add_shortcut", 2168272394, 1642193386 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("PortableCompressedTexture2D", {
 | 
				
			||||||
 | 
							{ "create_from_image", 97251393, 3679243433 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ProjectSettings", {
 | 
				
			||||||
 | 
							{ "load_resource_pack", 3001721055, 708980503 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RegEx", {
 | 
				
			||||||
 | 
							{ "search", 4087180739, 3365977994 },
 | 
				
			||||||
 | 
							{ "search_all", 3354100289, 849021363 },
 | 
				
			||||||
 | 
							{ "sub", 758293621, 54019702 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RenderingDevice", {
 | 
				
			||||||
 | 
							{ "texture_create", 3011278298, 3709173589 },
 | 
				
			||||||
 | 
							{ "texture_create_shared_from_slice", 864132525, 1808971279 },
 | 
				
			||||||
 | 
							{ "texture_update", 2736912341, 2096463824 },
 | 
				
			||||||
 | 
							{ "texture_copy", 3741367532, 2339493201 },
 | 
				
			||||||
 | 
							{ "texture_clear", 3423681478, 3396867530 },
 | 
				
			||||||
 | 
							{ "texture_resolve_multisample", 2126834943, 594679454 },
 | 
				
			||||||
 | 
							{ "framebuffer_format_create", 2635475316, 697032759 },
 | 
				
			||||||
 | 
							{ "framebuffer_format_create_multipass", 1992489524, 2647479094 },
 | 
				
			||||||
 | 
							{ "framebuffer_format_get_texture_samples", 1036806638, 4223391010 },
 | 
				
			||||||
 | 
							{ "framebuffer_create", 1884747791, 3284231055 },
 | 
				
			||||||
 | 
							{ "framebuffer_create_multipass", 452534725, 1750306695 },
 | 
				
			||||||
 | 
							{ "framebuffer_create_empty", 382373098, 3058360618 },
 | 
				
			||||||
 | 
							{ "vertex_buffer_create", 3491282828, 3410049843 },
 | 
				
			||||||
 | 
							{ "vertex_array_create", 3137892244, 3799816279 },
 | 
				
			||||||
 | 
							{ "index_buffer_create", 975915977, 3935920523 },
 | 
				
			||||||
 | 
							{ "shader_compile_spirv_from_source", 3459523685, 1178973306 },
 | 
				
			||||||
 | 
							{ "shader_compile_binary_from_spirv", 1395027180, 134910450 },
 | 
				
			||||||
 | 
							{ "shader_create_from_spirv", 3297482566, 342949005 },
 | 
				
			||||||
 | 
							{ "shader_create_from_bytecode", 2078349841, 1687031350 },
 | 
				
			||||||
 | 
							{ "uniform_buffer_create", 1453158401, 34556762 },
 | 
				
			||||||
 | 
							{ "storage_buffer_create", 1173156076, 2316365934 },
 | 
				
			||||||
 | 
							{ "texture_buffer_create", 2344087557, 1470338698 },
 | 
				
			||||||
 | 
							{ "buffer_update", 652628289, 3793150683 },
 | 
				
			||||||
 | 
							{ "buffer_clear", 1645170096, 2797041220 },
 | 
				
			||||||
 | 
							{ "buffer_get_data", 125363422, 3101830688 },
 | 
				
			||||||
 | 
							{ "render_pipeline_create", 2911419500, 2385451958 },
 | 
				
			||||||
 | 
							{ "compute_pipeline_create", 403593840, 1448838280 },
 | 
				
			||||||
 | 
							{ "draw_list_draw", 3710874499, 4230067973 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "draw_list_begin", 4252992020, 848735039 },
 | 
				
			||||||
 | 
							{ "draw_list_begin_split", 832527510, 2228306807 },
 | 
				
			||||||
 | 
							{ "draw_list_enable_scissor", 338791288, 730833978 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "draw_list_begin", 4252992020, 2468082605 },
 | 
				
			||||||
 | 
							{ "draw_list_begin_split", 832527510, 2406300660 },
 | 
				
			||||||
 | 
							{ "draw_list_enable_scissor", 338791288, 244650101 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RenderingServer", {
 | 
				
			||||||
 | 
							{ "texture_rd_create", 3291180269, 1434128712 },
 | 
				
			||||||
 | 
							{ "shader_set_default_texture_parameter", 3864903085, 4094001817 },
 | 
				
			||||||
 | 
							{ "shader_get_default_texture_parameter", 2523186822, 1464608890 },
 | 
				
			||||||
 | 
							{ "mesh_create_from_surfaces", 4007581507, 4291747531 },
 | 
				
			||||||
 | 
							{ "mesh_add_surface_from_arrays", 1247008646, 2342446560 },
 | 
				
			||||||
 | 
							{ "environment_set_ambient_light", 491659071, 1214961493 },
 | 
				
			||||||
 | 
							{ "instances_cull_aabb", 2031554939, 2570105777 },
 | 
				
			||||||
 | 
							{ "instances_cull_ray", 3388524336, 2208759584 },
 | 
				
			||||||
 | 
							{ "instances_cull_convex", 3690700105, 2488539944 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_line", 2843922985, 1819681853 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_polyline", 3438017257, 3098767073 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_multiline", 3176074788, 2088642721 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_texture_rect", 3205360868, 324864032 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_msdf_texture_rect_region", 349157222, 97408773 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_texture_rect_region", 2782979504, 485157892 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_nine_patch", 904428547, 389957886 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_polygon", 2907936855, 3580000528 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_triangle_array", 749685193, 660261329 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_multimesh", 1541595251, 2131855138 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_animation_slice", 4107531031, 2646834499 },
 | 
				
			||||||
 | 
							{ "canvas_item_set_canvas_group_mode", 41973386, 3973586316 },
 | 
				
			||||||
 | 
							{ "set_boot_image", 2244367877, 3759744527 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "viewport_attach_to_screen", 1410474027, 2248302004 },
 | 
				
			||||||
 | 
							{ "canvas_item_set_custom_rect", 2180266943, 1134449082 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_mesh", 3877492181, 3024949314 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "viewport_attach_to_screen", 1278520651, 1062245816 },
 | 
				
			||||||
 | 
							{ "canvas_item_set_custom_rect", 2180266943, 1333997032 },
 | 
				
			||||||
 | 
							{ "canvas_item_add_mesh", 3548053052, 316450961 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ResourceLoader", {
 | 
				
			||||||
 | 
							{ "load_threaded_request", 1939848623, 3614384323 },
 | 
				
			||||||
 | 
							{ "load_threaded_get_status", 3931021148, 4137685479 },
 | 
				
			||||||
 | 
							{ "load", 2622212233, 3358495409 },
 | 
				
			||||||
 | 
							{ "exists", 2220807150, 4185558881 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ResourceSaver", {
 | 
				
			||||||
 | 
							{ "save", 2303056517, 2983274697 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RichTextLabel", {
 | 
				
			||||||
 | 
							{ "push_font", 814287596, 2347424842 },
 | 
				
			||||||
 | 
							{ "push_paragraph", 3218895358, 3089306873 },
 | 
				
			||||||
 | 
							{ "push_list", 4036303897, 3017143144 },
 | 
				
			||||||
 | 
							{ "push_table", 1125058220, 2623499273 },
 | 
				
			||||||
 | 
							{ "set_table_column_expand", 4132157579, 2185176273 },
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "add_image", 3346058748, 1507062345 },
 | 
				
			||||||
 | 
							{ "push_dropcap", 981432822, 763534173 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "add_image", 3346058748, 3580801207 },
 | 
				
			||||||
 | 
							{ "push_dropcap", 311501835, 4061635501 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RigidBody2D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "apply_impulse", 496058220, 1271588277 },
 | 
				
			||||||
 | 
							{ "apply_force", 496058220, 1271588277 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 496058220, 1271588277 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "apply_impulse", 496058220, 4288681949 },
 | 
				
			||||||
 | 
							{ "apply_force", 496058220, 4288681949 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 496058220, 4288681949 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("RigidBody3D", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
							{ "apply_force", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 1002852006, 2485728502 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "apply_impulse", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
							{ "apply_force", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
							{ "add_constant_force", 1002852006, 2754756483 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("SceneMultiplayer", {
 | 
				
			||||||
 | 
							{ "send_bytes", 2742700601, 1307428718 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("SceneReplicationConfig", {
 | 
				
			||||||
 | 
							{ "add_property", 3818401521, 4094619021 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("SceneTree", {
 | 
				
			||||||
 | 
							{ "create_timer", 1780978058, 2709170273 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ScriptCreateDialog", {
 | 
				
			||||||
 | 
							{ "config", 4210001628, 869314288 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Shader", {
 | 
				
			||||||
 | 
							{ "set_default_texture_parameter", 1628453603, 2750740428 },
 | 
				
			||||||
 | 
							{ "get_default_texture_parameter", 3823812009, 3090538643 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Skeleton3D", {
 | 
				
			||||||
 | 
							{ "set_bone_enabled", 4023243586, 972357352 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("SpriteFrames", {
 | 
				
			||||||
 | 
							{ "add_frame", 407562921, 1351332740 },
 | 
				
			||||||
 | 
							{ "set_frame", 3155743884, 56804795 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("StreamPeerTCP", {
 | 
				
			||||||
 | 
							{ "bind", 4025329869, 3167955072 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("StreamPeerTLS", {
 | 
				
			||||||
 | 
							{ "connect_to_stream", 1325480781, 57169517 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("SurfaceTool", {
 | 
				
			||||||
 | 
							{ "add_triangle_fan", 297960074, 2235017613 },
 | 
				
			||||||
 | 
							{ "generate_lod", 1894448909, 1938056459 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TCPServer", {
 | 
				
			||||||
 | 
							{ "listen", 4025329869, 3167955072 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TextEdit", {
 | 
				
			||||||
 | 
							{ "get_line_width", 3294126239, 688195400 },
 | 
				
			||||||
 | 
							{ "insert_text_at_caret", 3043792800, 2697778442 },
 | 
				
			||||||
 | 
							{ "get_line_column_at_pos", 850652858, 239517838 },
 | 
				
			||||||
 | 
							{ "is_mouse_over_selection", 1099474134, 1840282309 },
 | 
				
			||||||
 | 
							{ "set_caret_line", 1413195636, 1302582944 },
 | 
				
			||||||
 | 
							{ "set_caret_column", 1071284433, 3796796178 },
 | 
				
			||||||
 | 
							{ "set_selection_mode", 2920622473, 1443345937 },
 | 
				
			||||||
 | 
							{ "select", 4269665324, 2560984452 },
 | 
				
			||||||
 | 
							{ "get_scroll_pos_for_line", 3274652423, 3929084198 },
 | 
				
			||||||
 | 
							{ "set_line_as_first_visible", 3023605688, 2230941749 },
 | 
				
			||||||
 | 
							{ "set_line_as_center_visible", 3023605688, 2230941749 },
 | 
				
			||||||
 | 
							{ "set_line_as_last_visible", 3023605688, 2230941749 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TextLine", {
 | 
				
			||||||
 | 
							{ "add_string", 867188035, 621426851 },
 | 
				
			||||||
 | 
							{ "add_object", 735420116, 1316529304 },
 | 
				
			||||||
 | 
							{ "resize_object", 960819067, 2095776372 },
 | 
				
			||||||
 | 
							{ "draw", 1164457837, 856975658 },
 | 
				
			||||||
 | 
							{ "draw_outline", 1364491366, 1343401456 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TextParagraph", {
 | 
				
			||||||
 | 
					#ifdef REAL_T_IS_DOUBLE
 | 
				
			||||||
 | 
							{ "set_dropcap", 2613124475, 2897844600 },
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							{ "set_dropcap", 2613124475, 2498990330 },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							{ "add_string", 867188035, 621426851 },
 | 
				
			||||||
 | 
							{ "add_object", 735420116, 1316529304 },
 | 
				
			||||||
 | 
							{ "resize_object", 960819067, 2095776372 },
 | 
				
			||||||
 | 
							{ "draw", 367324453, 1567802413 },
 | 
				
			||||||
 | 
							{ "draw_outline", 2159523405, 1893131224 },
 | 
				
			||||||
 | 
							{ "draw_line", 3963848920, 1242169894 },
 | 
				
			||||||
 | 
							{ "draw_line_outline", 1814903311, 2664926980 },
 | 
				
			||||||
 | 
							{ "draw_dropcap", 1164457837, 856975658 },
 | 
				
			||||||
 | 
							{ "draw_dropcap_outline", 1364491366, 1343401456 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TextServer", {
 | 
				
			||||||
 | 
							{ "font_draw_glyph", 1821196351, 1339057948 },
 | 
				
			||||||
 | 
							{ "font_draw_glyph_outline", 1124898203, 2626165733 },
 | 
				
			||||||
 | 
							{ "shaped_text_set_direction", 2616949700, 1551430183 },
 | 
				
			||||||
 | 
							{ "shaped_text_set_orientation", 104095128, 3019609126 },
 | 
				
			||||||
 | 
							{ "shaped_text_add_string", 2621279422, 623473029 },
 | 
				
			||||||
 | 
							{ "shaped_text_add_object", 2838446185, 3664424789 },
 | 
				
			||||||
 | 
							{ "shaped_text_resize_object", 2353789835, 790361552 },
 | 
				
			||||||
 | 
							{ "shaped_set_span_update_font", 1578983057, 2022725822 },
 | 
				
			||||||
 | 
							{ "shaped_text_fit_to_width", 603718830, 530670926 },
 | 
				
			||||||
 | 
							{ "shaped_text_get_line_breaks_adv", 4206849830, 2376991424 },
 | 
				
			||||||
 | 
							{ "shaped_text_get_line_breaks", 303410369, 2651359741 },
 | 
				
			||||||
 | 
							{ "shaped_text_get_word_breaks", 3299477123, 185957063 },
 | 
				
			||||||
 | 
							{ "shaped_text_overrun_trim_to_width", 1572579718, 2723146520 },
 | 
				
			||||||
 | 
							{ "shaped_text_draw", 70679950, 880389142 },
 | 
				
			||||||
 | 
							{ "shaped_text_draw_outline", 2673671346, 2559184194 },
 | 
				
			||||||
 | 
							{ "format_number", 2305636099, 2664628024 },
 | 
				
			||||||
 | 
							{ "parse_number", 2305636099, 2664628024 },
 | 
				
			||||||
 | 
							{ "string_get_word_breaks", 1398910359, 581857818 },
 | 
				
			||||||
 | 
							{ "string_get_character_breaks", 1586579831, 2333794773 },
 | 
				
			||||||
 | 
							{ "string_to_upper", 2305636099, 2664628024 },
 | 
				
			||||||
 | 
							{ "string_to_lower", 2305636099, 2664628024 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Texture2D", {
 | 
				
			||||||
 | 
							{ "draw", 1115460088, 2729649137 },
 | 
				
			||||||
 | 
							{ "draw_rect", 575156982, 3499451691 },
 | 
				
			||||||
 | 
							{ "draw_rect_region", 1066564656, 2963678660 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Thread", {
 | 
				
			||||||
 | 
							{ "start", 2779832528, 1327203254 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileMap", {
 | 
				
			||||||
 | 
							{ "set_cell", 1732664643, 966713560 },
 | 
				
			||||||
 | 
							{ "set_cells_terrain_connect", 3072115677, 3578627656 },
 | 
				
			||||||
 | 
							{ "set_cells_terrain_path", 3072115677, 3578627656 },
 | 
				
			||||||
 | 
							{ "get_used_cells_by_id", 4152068407, 2931012785 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileMapPattern", {
 | 
				
			||||||
 | 
							{ "set_cell", 634000503, 2224802556 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileSet", {
 | 
				
			||||||
 | 
							{ "add_source", 276991387, 1059186179 },
 | 
				
			||||||
 | 
							{ "add_terrain", 3023605688, 1230568737 },
 | 
				
			||||||
 | 
							{ "add_pattern", 3009264082, 763712015 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileSetAtlasSource", {
 | 
				
			||||||
 | 
							{ "create_tile", 1583819816, 190528769 },
 | 
				
			||||||
 | 
							{ "move_tile_in_atlas", 1375626516, 3870111920 },
 | 
				
			||||||
 | 
							{ "has_room_for_tile", 4182444377, 3018597268 },
 | 
				
			||||||
 | 
							{ "create_alternative_tile", 3531100812, 2226298068 },
 | 
				
			||||||
 | 
							{ "get_tile_texture_region", 1321423751, 241857547 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TileSetScenesCollectionSource", {
 | 
				
			||||||
 | 
							{ "create_scene_tile", 2633389122, 1117465415 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Translation", {
 | 
				
			||||||
 | 
							{ "add_message", 971803314, 3898530326 },
 | 
				
			||||||
 | 
							{ "add_plural_message", 360316719, 2356982266 },
 | 
				
			||||||
 | 
							{ "get_message", 58037827, 1829228469 },
 | 
				
			||||||
 | 
							{ "get_plural_message", 1333931916, 229954002 },
 | 
				
			||||||
 | 
							{ "erase_message", 3919944288, 3959009644 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TranslationServer", {
 | 
				
			||||||
 | 
							{ "translate", 58037827, 1829228469 },
 | 
				
			||||||
 | 
							{ "translate_plural", 1333931916, 229954002 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Tree", {
 | 
				
			||||||
 | 
							{ "get_item_area_rect", 1235226180, 47968679 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("TreeItem", {
 | 
				
			||||||
 | 
							{ "propagate_check", 4023243586, 972357352 },
 | 
				
			||||||
 | 
							{ "add_button", 1507727907, 1688223362 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("UDPServer", {
 | 
				
			||||||
 | 
							{ "listen", 4025329869, 3167955072 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("UPNP", {
 | 
				
			||||||
 | 
							{ "add_port_mapping", 3358934458, 818314583 },
 | 
				
			||||||
 | 
							{ "delete_port_mapping", 760296170, 3444187325 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("UPNPDevice", {
 | 
				
			||||||
 | 
							{ "add_port_mapping", 3358934458, 818314583 },
 | 
				
			||||||
 | 
							{ "delete_port_mapping", 760296170, 3444187325 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("UndoRedo", {
 | 
				
			||||||
 | 
							{ "create_action", 3900135403, 3171901514 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("VideoStreamPlayback", {
 | 
				
			||||||
 | 
							{ "mix_audio", 1369271885, 93876830 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("WebRTCMultiplayerPeer", {
 | 
				
			||||||
 | 
							{ "create_client", 1777354631, 2641732907 },
 | 
				
			||||||
 | 
							{ "create_mesh", 1777354631, 2641732907 },
 | 
				
			||||||
 | 
							{ "add_peer", 2555866323, 4078953270 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("WebRTCPeerConnection", {
 | 
				
			||||||
 | 
							{ "create_data_channel", 3997447457, 1288557393 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("WebSocketMultiplayerPeer", {
 | 
				
			||||||
 | 
							{ "create_client", 3097527179, 1966198364 },
 | 
				
			||||||
 | 
							{ "create_server", 337374795, 2400822951 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("WebSocketPeer", {
 | 
				
			||||||
 | 
							{ "connect_to_url", 3097527179, 1966198364 },
 | 
				
			||||||
 | 
							{ "send", 3440492527, 2780360567 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("Window", {
 | 
				
			||||||
 | 
							{ "get_theme_icon", 2336455395, 3163973443 },
 | 
				
			||||||
 | 
							{ "get_theme_stylebox", 2759935355, 604739069 },
 | 
				
			||||||
 | 
							{ "get_theme_font", 387378635, 2826986490 },
 | 
				
			||||||
 | 
							{ "get_theme_font_size", 229578101, 1327056374 },
 | 
				
			||||||
 | 
							{ "get_theme_color", 2377051548, 2798751242 },
 | 
				
			||||||
 | 
							{ "get_theme_constant", 229578101, 1327056374 },
 | 
				
			||||||
 | 
							{ "has_theme_icon", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_stylebox", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_font", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_font_size", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_color", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "has_theme_constant", 1187511791, 866386512 },
 | 
				
			||||||
 | 
							{ "popup_exclusive", 1728044812, 2134721627 },
 | 
				
			||||||
 | 
							{ "popup_exclusive_centered", 2561668109, 3357594017 },
 | 
				
			||||||
 | 
							{ "popup_exclusive_centered_ratio", 4257659513, 2284776287 },
 | 
				
			||||||
 | 
							{ "popup_exclusive_centered_clamped", 224798062, 2612708785 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("WorkerThreadPool", {
 | 
				
			||||||
 | 
							{ "add_task", 3976347598, 3745067146 },
 | 
				
			||||||
 | 
							{ "add_group_task", 2377228549, 1801953219 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ZIPPacker", {
 | 
				
			||||||
 | 
							{ "open", 3715508516, 1936816515 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						mappings.insert("ZIPReader", {
 | 
				
			||||||
 | 
							{ "read_file", 156385007, 740857591 },
 | 
				
			||||||
 | 
							{ "file_exists", 1676256, 35364943 },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionCompatHashes::finalize() {
 | 
				
			||||||
 | 
						mappings.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
							
								
								
									
										58
									
								
								engine/core/extension/gdextension_compat_hashes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								engine/core/extension/gdextension_compat_hashes.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_compat_hashes.h                                           */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_COMPAT_HASHES_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_COMPAT_HASHES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/string/string_name.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
 | 
					#include "core/templates/local_vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionCompatHashes {
 | 
				
			||||||
 | 
						struct Mapping {
 | 
				
			||||||
 | 
							StringName method;
 | 
				
			||||||
 | 
							uint32_t legacy_hash;
 | 
				
			||||||
 | 
							uint32_t current_hash;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static HashMap<StringName, LocalVector<Mapping>> mappings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static void initialize();
 | 
				
			||||||
 | 
						static void finalize();
 | 
				
			||||||
 | 
						static bool lookup_current_hash(const StringName &p_class, const StringName &p_method, uint32_t p_legacy_hash, uint32_t *r_current_hash);
 | 
				
			||||||
 | 
						static bool get_legacy_hashes(const StringName &p_class, const StringName &p_method, Array &r_hashes, bool p_check_valid = true);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_COMPAT_HASHES_H
 | 
				
			||||||
							
								
								
									
										1715
									
								
								engine/core/extension/gdextension_interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1715
									
								
								engine/core/extension/gdextension_interface.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										2964
									
								
								engine/core/extension/gdextension_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2964
									
								
								engine/core/extension/gdextension_interface.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										304
									
								
								engine/core/extension/gdextension_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								engine/core/extension/gdextension_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,304 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_manager.cpp                                               */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gdextension_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/extension/gdextension_compat_hashes.h"
 | 
				
			||||||
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
 | 
					#include "core/object/script_language.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension) {
 | 
				
			||||||
 | 
						if (level >= 0) { // Already initialized up to some level.
 | 
				
			||||||
 | 
							int32_t minimum_level = p_extension->get_minimum_library_initialization_level();
 | 
				
			||||||
 | 
							if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
 | 
				
			||||||
 | 
								return LOAD_STATUS_NEEDS_RESTART;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Initialize up to current level.
 | 
				
			||||||
 | 
							for (int32_t i = minimum_level; i <= level; i++) {
 | 
				
			||||||
 | 
								p_extension->initialize_library(GDExtension::InitializationLevel(i));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
 | 
				
			||||||
 | 
							gdextension_class_icon_paths[kv.key] = kv.value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(const Ref<GDExtension> &p_extension) {
 | 
				
			||||||
 | 
						if (level >= 0) { // Already initialized up to some level.
 | 
				
			||||||
 | 
							// Deinitialize down from current level.
 | 
				
			||||||
 | 
							for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
 | 
				
			||||||
 | 
								p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
 | 
				
			||||||
 | 
							gdextension_class_icon_paths.erase(kv.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
 | 
				
			||||||
 | 
						if (gdextension_map.has(p_path)) {
 | 
				
			||||||
 | 
							return LOAD_STATUS_ALREADY_LOADED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Ref<GDExtension> extension = ResourceLoader::load(p_path);
 | 
				
			||||||
 | 
						if (extension.is_null()) {
 | 
				
			||||||
 | 
							return LOAD_STATUS_FAILED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LoadStatus status = _load_extension_internal(extension);
 | 
				
			||||||
 | 
						if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gdextension_map[p_path] = extension;
 | 
				
			||||||
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String &p_path) {
 | 
				
			||||||
 | 
					#ifndef TOOLS_ENABLED
 | 
				
			||||||
 | 
						ERR_FAIL_V_MSG(LOAD_STATUS_FAILED, "GDExtensions can only be reloaded in an editor build.");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!gdextension_map.has(p_path)) {
 | 
				
			||||||
 | 
							return LOAD_STATUS_NOT_LOADED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<GDExtension> extension = gdextension_map[p_path];
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!extension->is_reloadable(), LOAD_STATUS_FAILED, vformat("This GDExtension is not marked as 'reloadable' or doesn't support reloading: %s.", p_path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LoadStatus status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						extension->prepare_reload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Unload library if it's open. It may not be open if the developer made a
 | 
				
			||||||
 | 
						// change that broke loading in a previous hot-reload attempt.
 | 
				
			||||||
 | 
						if (extension->is_library_open()) {
 | 
				
			||||||
 | 
							status = _unload_extension_internal(extension);
 | 
				
			||||||
 | 
							if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
 | 
								// We need to clear these no matter what.
 | 
				
			||||||
 | 
								extension->clear_instance_bindings();
 | 
				
			||||||
 | 
								return status;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							extension->clear_instance_bindings();
 | 
				
			||||||
 | 
							extension->close_library();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err = GDExtensionResourceLoader::load_gdextension_resource(p_path, extension);
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							return LOAD_STATUS_FAILED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = _load_extension_internal(extension);
 | 
				
			||||||
 | 
						if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						extension->finish_reload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
 | 
				
			||||||
 | 
						if (!gdextension_map.has(p_path)) {
 | 
				
			||||||
 | 
							return LOAD_STATUS_NOT_LOADED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<GDExtension> extension = gdextension_map[p_path];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LoadStatus status = _unload_extension_internal(extension);
 | 
				
			||||||
 | 
						if (status != LOAD_STATUS_OK) {
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gdextension_map.erase(p_path);
 | 
				
			||||||
 | 
						return LOAD_STATUS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionManager::is_extension_loaded(const String &p_path) const {
 | 
				
			||||||
 | 
						return gdextension_map.has(p_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vector<String> GDExtensionManager::get_loaded_extensions() const {
 | 
				
			||||||
 | 
						Vector<String> ret;
 | 
				
			||||||
 | 
						for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							ret.push_back(E.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					Ref<GDExtension> GDExtensionManager::get_extension(const String &p_path) {
 | 
				
			||||||
 | 
						HashMap<String, Ref<GDExtension>>::Iterator E = gdextension_map.find(p_path);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!E, Ref<GDExtension>());
 | 
				
			||||||
 | 
						return E->value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GDExtensionManager::class_has_icon_path(const String &p_class) const {
 | 
				
			||||||
 | 
						// TODO: Check that the icon belongs to a registered class somehow.
 | 
				
			||||||
 | 
						return gdextension_class_icon_paths.has(p_class);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String GDExtensionManager::class_get_icon_path(const String &p_class) const {
 | 
				
			||||||
 | 
						// TODO: Check that the icon belongs to a registered class somehow.
 | 
				
			||||||
 | 
						if (gdextension_class_icon_paths.has(p_class)) {
 | 
				
			||||||
 | 
							return gdextension_class_icon_paths[p_class];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND(int32_t(p_level) - 1 != level);
 | 
				
			||||||
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							E.value->initialize_library(p_level);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						level = p_level;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND(int32_t(p_level) != level);
 | 
				
			||||||
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							E.value->deinitialize_library(p_level);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						level = int32_t(p_level) - 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
					void GDExtensionManager::track_instance_binding(void *p_token, Object *p_object) {
 | 
				
			||||||
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							if (E.value.ptr() == p_token) {
 | 
				
			||||||
 | 
								if (E.value->is_reloadable()) {
 | 
				
			||||||
 | 
									E.value->track_instance_binding(p_object);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::untrack_instance_binding(void *p_token, Object *p_object) {
 | 
				
			||||||
 | 
						for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							if (E.value.ptr() == p_token) {
 | 
				
			||||||
 | 
								if (E.value->is_reloadable()) {
 | 
				
			||||||
 | 
									E.value->untrack_instance_binding(p_object);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::_reload_all_scripts() {
 | 
				
			||||||
 | 
						for (int i = 0; i < ScriptServer::get_language_count(); i++) {
 | 
				
			||||||
 | 
							ScriptServer::get_language(i)->reload_all_scripts();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::load_extensions() {
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
 | 
				
			||||||
 | 
						while (f.is_valid() && !f->eof_reached()) {
 | 
				
			||||||
 | 
							String s = f->get_line().strip_edges();
 | 
				
			||||||
 | 
							if (!s.is_empty()) {
 | 
				
			||||||
 | 
								LoadStatus err = load_extension(s);
 | 
				
			||||||
 | 
								ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, "Error loading extension: " + s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OS::get_singleton()->load_platform_gdextensions();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::reload_extensions() {
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						bool reloaded = false;
 | 
				
			||||||
 | 
						for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
 | 
				
			||||||
 | 
							if (!E.value->is_reloadable()) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (E.value->has_library_changed()) {
 | 
				
			||||||
 | 
								reloaded = true;
 | 
				
			||||||
 | 
								reload_extension(E.value->get_path());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reloaded) {
 | 
				
			||||||
 | 
							emit_signal("extensions_reloaded");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Reload all scripts to clear out old references.
 | 
				
			||||||
 | 
							callable_mp_static(&GDExtensionManager::_reload_all_scripts).call_deferred();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager *GDExtensionManager::get_singleton() {
 | 
				
			||||||
 | 
						return singleton;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GDExtensionManager::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &GDExtensionManager::get_loaded_extensions);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_extension", "path"), &GDExtensionManager::get_extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_OK);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED);
 | 
				
			||||||
 | 
						BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_SIGNAL(MethodInfo("extensions_reloaded"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager *GDExtensionManager::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::GDExtensionManager() {
 | 
				
			||||||
 | 
						ERR_FAIL_COND(singleton != nullptr);
 | 
				
			||||||
 | 
						singleton = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						GDExtensionCompatHashes::initialize();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDExtensionManager::~GDExtensionManager() {
 | 
				
			||||||
 | 
						if (singleton == this) {
 | 
				
			||||||
 | 
							singleton = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						GDExtensionCompatHashes::finalize();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										94
									
								
								engine/core/extension/gdextension_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								engine/core/extension/gdextension_manager.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  gdextension_manager.h                                                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_MANAGER_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_MANAGER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/extension/gdextension.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GDExtensionManager : public Object {
 | 
				
			||||||
 | 
						GDCLASS(GDExtensionManager, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int32_t level = -1;
 | 
				
			||||||
 | 
						HashMap<String, Ref<GDExtension>> gdextension_map;
 | 
				
			||||||
 | 
						HashMap<String, String> gdextension_class_icon_paths;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static GDExtensionManager *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum LoadStatus {
 | 
				
			||||||
 | 
							LOAD_STATUS_OK,
 | 
				
			||||||
 | 
							LOAD_STATUS_FAILED,
 | 
				
			||||||
 | 
							LOAD_STATUS_ALREADY_LOADED,
 | 
				
			||||||
 | 
							LOAD_STATUS_NOT_LOADED,
 | 
				
			||||||
 | 
							LOAD_STATUS_NEEDS_RESTART,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						LoadStatus _load_extension_internal(const Ref<GDExtension> &p_extension);
 | 
				
			||||||
 | 
						LoadStatus _unload_extension_internal(const Ref<GDExtension> &p_extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						static void _reload_all_scripts();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						LoadStatus load_extension(const String &p_path);
 | 
				
			||||||
 | 
						LoadStatus reload_extension(const String &p_path);
 | 
				
			||||||
 | 
						LoadStatus unload_extension(const String &p_path);
 | 
				
			||||||
 | 
						bool is_extension_loaded(const String &p_path) const;
 | 
				
			||||||
 | 
						Vector<String> get_loaded_extensions() const;
 | 
				
			||||||
 | 
						Ref<GDExtension> get_extension(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool class_has_icon_path(const String &p_class) const;
 | 
				
			||||||
 | 
						String class_get_icon_path(const String &p_class) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void initialize_extensions(GDExtension::InitializationLevel p_level);
 | 
				
			||||||
 | 
						void deinitialize_extensions(GDExtension::InitializationLevel p_level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						void track_instance_binding(void *p_token, Object *p_object);
 | 
				
			||||||
 | 
						void untrack_instance_binding(void *p_token, Object *p_object);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static GDExtensionManager *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void load_extensions();
 | 
				
			||||||
 | 
						void reload_extensions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GDExtensionManager();
 | 
				
			||||||
 | 
						~GDExtensionManager();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_MANAGER_H
 | 
				
			||||||
							
								
								
									
										55
									
								
								engine/core/extension/make_interface_dumper.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								engine/core/extension/make_interface_dumper.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					import zlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run(target, source, env):
 | 
				
			||||||
 | 
					    src = str(source[0])
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					    with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
 | 
				
			||||||
 | 
					        buf = f.read()
 | 
				
			||||||
 | 
					        decomp_size = len(buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Use maximum zlib compression level to further reduce file size
 | 
				
			||||||
 | 
					        # (at the cost of initial build times).
 | 
				
			||||||
 | 
					        buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write(
 | 
				
			||||||
 | 
					            """/* THIS FILE IS GENERATED DO NOT EDIT */
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_INTERFACE_DUMP_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_INTERFACE_DUMP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/compression.h"
 | 
				
			||||||
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("static const int _gdextension_interface_data_compressed_size = " + str(len(buf)) + ";\n")
 | 
				
			||||||
 | 
					        g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n")
 | 
				
			||||||
 | 
					        g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n")
 | 
				
			||||||
 | 
					        for i in range(len(buf)):
 | 
				
			||||||
 | 
					            g.write("\t" + str(buf[i]) + ",\n")
 | 
				
			||||||
 | 
					        g.write("};\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write(
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					class GDExtensionInterfaceDump {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        static void generate_gdextension_interface_file(const String &p_path) {
 | 
				
			||||||
 | 
					            Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
 | 
				
			||||||
 | 
					            ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
 | 
				
			||||||
 | 
					            Vector<uint8_t> data;
 | 
				
			||||||
 | 
					            data.resize(_gdextension_interface_data_uncompressed_size);
 | 
				
			||||||
 | 
					            int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
 | 
				
			||||||
 | 
					            ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
 | 
				
			||||||
 | 
					            fa->store_buffer(data.ptr(), data.size());
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // TOOLS_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // GDEXTENSION_INTERFACE_DUMP_H
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
							
								
								
									
										144
									
								
								engine/core/extension/make_wrappers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								engine/core/extension/make_wrappers.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,144 @@
 | 
				
			||||||
 | 
					proto_mod = """
 | 
				
			||||||
 | 
					#define MODBIND$VER($RETTYPE m_name$ARG) \\
 | 
				
			||||||
 | 
					virtual $RETVAL _##m_name($FUNCARGS) $CONST; \\
 | 
				
			||||||
 | 
					_FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
 | 
				
			||||||
 | 
					    $RETX _##m_name($CALLARGS);\\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_mod_version(argcount, const=False, returns=False):
 | 
				
			||||||
 | 
					    s = proto_mod
 | 
				
			||||||
 | 
					    sproto = str(argcount)
 | 
				
			||||||
 | 
					    if returns:
 | 
				
			||||||
 | 
					        sproto += "R"
 | 
				
			||||||
 | 
					        s = s.replace("$RETTYPE", "m_ret, ")
 | 
				
			||||||
 | 
					        s = s.replace("$RETVAL", "m_ret")
 | 
				
			||||||
 | 
					        s = s.replace("$RETX", "return")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$RETTYPE", "")
 | 
				
			||||||
 | 
					        s = s.replace("$RETVAL", "void")
 | 
				
			||||||
 | 
					        s = s.replace("$RETX", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if const:
 | 
				
			||||||
 | 
					        sproto += "C"
 | 
				
			||||||
 | 
					        s = s.replace("$CONST", "const")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$CONST", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = s.replace("$VER", sproto)
 | 
				
			||||||
 | 
					    argtext = ""
 | 
				
			||||||
 | 
					    funcargs = ""
 | 
				
			||||||
 | 
					    callargs = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for i in range(argcount):
 | 
				
			||||||
 | 
					        if i > 0:
 | 
				
			||||||
 | 
					            funcargs += ", "
 | 
				
			||||||
 | 
					            callargs += ", "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        argtext += ", m_type" + str(i + 1)
 | 
				
			||||||
 | 
					        funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
 | 
				
			||||||
 | 
					        callargs += "arg" + str(i + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if argcount:
 | 
				
			||||||
 | 
					        s = s.replace("$ARG", argtext)
 | 
				
			||||||
 | 
					        s = s.replace("$FUNCARGS", funcargs)
 | 
				
			||||||
 | 
					        s = s.replace("$CALLARGS", callargs)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$ARG", "")
 | 
				
			||||||
 | 
					        s = s.replace("$FUNCARGS", funcargs)
 | 
				
			||||||
 | 
					        s = s.replace("$CALLARGS", callargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proto_ex = """
 | 
				
			||||||
 | 
					#define EXBIND$VER($RETTYPE m_name$ARG) \\
 | 
				
			||||||
 | 
					GDVIRTUAL$VER($RETTYPE_##m_name$ARG)\\
 | 
				
			||||||
 | 
					virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
 | 
				
			||||||
 | 
					    $RETPRE\\
 | 
				
			||||||
 | 
					    GDVIRTUAL_REQUIRED_CALL(_##m_name$CALLARGS$RETREF);\\
 | 
				
			||||||
 | 
					    $RETPOST\\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_ex_version(argcount, const=False, returns=False):
 | 
				
			||||||
 | 
					    s = proto_ex
 | 
				
			||||||
 | 
					    sproto = str(argcount)
 | 
				
			||||||
 | 
					    if returns:
 | 
				
			||||||
 | 
					        sproto += "R"
 | 
				
			||||||
 | 
					        s = s.replace("$RETTYPE", "m_ret, ")
 | 
				
			||||||
 | 
					        s = s.replace("$RETVAL", "m_ret")
 | 
				
			||||||
 | 
					        s = s.replace("$RETPRE", "m_ret ret; ZeroInitializer<m_ret>::initialize(ret);\\\n")
 | 
				
			||||||
 | 
					        s = s.replace("$RETPOST", "return ret;\\\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$RETTYPE", "")
 | 
				
			||||||
 | 
					        s = s.replace("$RETVAL", "void")
 | 
				
			||||||
 | 
					        s = s.replace("$RETPRE", "")
 | 
				
			||||||
 | 
					        s = s.replace("$RETPOST", "return;")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if const:
 | 
				
			||||||
 | 
					        sproto += "C"
 | 
				
			||||||
 | 
					        s = s.replace("$CONST", "const")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$CONST", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = s.replace("$VER", sproto)
 | 
				
			||||||
 | 
					    argtext = ""
 | 
				
			||||||
 | 
					    funcargs = ""
 | 
				
			||||||
 | 
					    callargs = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for i in range(argcount):
 | 
				
			||||||
 | 
					        if i > 0:
 | 
				
			||||||
 | 
					            funcargs += ", "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        argtext += ", m_type" + str(i + 1)
 | 
				
			||||||
 | 
					        funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
 | 
				
			||||||
 | 
					        callargs += ", arg" + str(i + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if argcount:
 | 
				
			||||||
 | 
					        s = s.replace("$ARG", argtext)
 | 
				
			||||||
 | 
					        s = s.replace("$FUNCARGS", funcargs)
 | 
				
			||||||
 | 
					        s = s.replace("$CALLARGS", callargs)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$ARG", "")
 | 
				
			||||||
 | 
					        s = s.replace("$FUNCARGS", funcargs)
 | 
				
			||||||
 | 
					        s = s.replace("$CALLARGS", callargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if returns:
 | 
				
			||||||
 | 
					        s = s.replace("$RETREF", ", ret")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        s = s.replace("$RETREF", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run(target, source, env):
 | 
				
			||||||
 | 
					    max_versions = 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    txt = """
 | 
				
			||||||
 | 
					#ifndef GDEXTENSION_WRAPPERS_GEN_H
 | 
				
			||||||
 | 
					#define GDEXTENSION_WRAPPERS_GEN_H
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for i in range(max_versions + 1):
 | 
				
			||||||
 | 
					        txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n"
 | 
				
			||||||
 | 
					        txt += generate_ex_version(i, False, False)
 | 
				
			||||||
 | 
					        txt += generate_ex_version(i, False, True)
 | 
				
			||||||
 | 
					        txt += generate_ex_version(i, True, False)
 | 
				
			||||||
 | 
					        txt += generate_ex_version(i, True, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for i in range(max_versions + 1):
 | 
				
			||||||
 | 
					        txt += "\n/* Module Wrapper " + str(i) + " Arguments */\n"
 | 
				
			||||||
 | 
					        txt += generate_mod_version(i, False, False)
 | 
				
			||||||
 | 
					        txt += generate_mod_version(i, False, True)
 | 
				
			||||||
 | 
					        txt += generate_mod_version(i, True, False)
 | 
				
			||||||
 | 
					        txt += generate_mod_version(i, True, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    txt += "\n#endif\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
 | 
				
			||||||
 | 
					        f.write(txt)
 | 
				
			||||||
							
								
								
									
										20
									
								
								engine/core/input/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								engine/core/input/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import input_builders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Order matters here. Higher index controller database files write on top of lower index database files.
 | 
				
			||||||
 | 
					controller_databases = [
 | 
				
			||||||
 | 
					    "gamecontrollerdb.txt",
 | 
				
			||||||
 | 
					    "godotcontrollerdb.txt",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gensource = env.CommandNoCache(
 | 
				
			||||||
 | 
					    "default_controller_mappings.gen.cpp",
 | 
				
			||||||
 | 
					    controller_databases,
 | 
				
			||||||
 | 
					    env.Run(input_builders.make_default_controller_mappings),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, gensource)
 | 
				
			||||||
							
								
								
									
										39
									
								
								engine/core/input/default_controller_mappings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								engine/core/input/default_controller_mappings.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  default_controller_mappings.h                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DEFAULT_CONTROLLER_MAPPINGS_H
 | 
				
			||||||
 | 
					#define DEFAULT_CONTROLLER_MAPPINGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DefaultControllerMappings {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static const char *mappings[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DEFAULT_CONTROLLER_MAPPINGS_H
 | 
				
			||||||
							
								
								
									
										2040
									
								
								engine/core/input/gamecontrollerdb.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2040
									
								
								engine/core/input/gamecontrollerdb.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										35
									
								
								engine/core/input/godotcontrollerdb.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								engine/core/input/godotcontrollerdb.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					# Game Controller DB for Godot in SDL 2.0.16 format
 | 
				
			||||||
 | 
					# Source: https://github.com/godotengine/godot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows
 | 
				
			||||||
 | 
					__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Android
 | 
				
			||||||
 | 
					Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Web
 | 
				
			||||||
 | 
					standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger: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,
 | 
				
			||||||
 | 
					Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
 | 
				
			||||||
 | 
					Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Web,
 | 
				
			||||||
 | 
					Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Web,
 | 
				
			||||||
 | 
					MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
 | 
				
			||||||
 | 
					MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
 | 
				
			||||||
 | 
					Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
 | 
				
			||||||
 | 
					Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
 | 
				
			||||||
 | 
					MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Web
 | 
				
			||||||
 | 
					Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
 | 
				
			||||||
 | 
					Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
 | 
				
			||||||
 | 
					Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
 | 
				
			||||||
 | 
					Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
 | 
				
			||||||
 | 
					Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
 | 
				
			||||||
							
								
								
									
										41
									
								
								engine/core/input/input.compat.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								engine/core/input/input.compat.inc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input.compat.inc                                                      */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::_vibrate_handheld_bind_compat_91143(int p_duration_ms) {
 | 
				
			||||||
 | 
						vibrate_handheld(p_duration_ms, -1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Input::_bind_compatibility_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_compatibility_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::_vibrate_handheld_bind_compat_91143, DEFVAL(500));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
							
								
								
									
										1692
									
								
								engine/core/input/input.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1692
									
								
								engine/core/input/input.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										386
									
								
								engine/core/input/input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								engine/core/input/input.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,386 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input.h                                                               */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef INPUT_H
 | 
				
			||||||
 | 
					#define INPUT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/input_event.h"
 | 
				
			||||||
 | 
					#include "core/object/object.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					#include "core/os/thread_safe.h"
 | 
				
			||||||
 | 
					#include "core/templates/rb_set.h"
 | 
				
			||||||
 | 
					#include "core/variant/typed_array.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Input : public Object {
 | 
				
			||||||
 | 
						GDCLASS(Input, Object);
 | 
				
			||||||
 | 
						_THREAD_SAFE_CLASS_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Input *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr uint64_t MAX_EVENT = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum MouseMode {
 | 
				
			||||||
 | 
							MOUSE_MODE_VISIBLE,
 | 
				
			||||||
 | 
							MOUSE_MODE_HIDDEN,
 | 
				
			||||||
 | 
							MOUSE_MODE_CAPTURED,
 | 
				
			||||||
 | 
							MOUSE_MODE_CONFINED,
 | 
				
			||||||
 | 
							MOUSE_MODE_CONFINED_HIDDEN,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef CursorShape
 | 
				
			||||||
 | 
						enum CursorShape {
 | 
				
			||||||
 | 
							CURSOR_ARROW,
 | 
				
			||||||
 | 
							CURSOR_IBEAM,
 | 
				
			||||||
 | 
							CURSOR_POINTING_HAND,
 | 
				
			||||||
 | 
							CURSOR_CROSS,
 | 
				
			||||||
 | 
							CURSOR_WAIT,
 | 
				
			||||||
 | 
							CURSOR_BUSY,
 | 
				
			||||||
 | 
							CURSOR_DRAG,
 | 
				
			||||||
 | 
							CURSOR_CAN_DROP,
 | 
				
			||||||
 | 
							CURSOR_FORBIDDEN,
 | 
				
			||||||
 | 
							CURSOR_VSIZE,
 | 
				
			||||||
 | 
							CURSOR_HSIZE,
 | 
				
			||||||
 | 
							CURSOR_BDIAGSIZE,
 | 
				
			||||||
 | 
							CURSOR_FDIAGSIZE,
 | 
				
			||||||
 | 
							CURSOR_MOVE,
 | 
				
			||||||
 | 
							CURSOR_VSPLIT,
 | 
				
			||||||
 | 
							CURSOR_HSPLIT,
 | 
				
			||||||
 | 
							CURSOR_HELP,
 | 
				
			||||||
 | 
							CURSOR_MAX
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum {
 | 
				
			||||||
 | 
							JOYPADS_MAX = 16,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						BitField<MouseButtonMask> mouse_button_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RBSet<Key> key_label_pressed;
 | 
				
			||||||
 | 
						RBSet<Key> physical_keys_pressed;
 | 
				
			||||||
 | 
						RBSet<Key> keys_pressed;
 | 
				
			||||||
 | 
						RBSet<JoyButton> joy_buttons_pressed;
 | 
				
			||||||
 | 
						RBMap<JoyAxis, float> _joy_axis;
 | 
				
			||||||
 | 
						//RBMap<StringName,int> custom_action_press;
 | 
				
			||||||
 | 
						Vector3 gravity;
 | 
				
			||||||
 | 
						Vector3 accelerometer;
 | 
				
			||||||
 | 
						Vector3 magnetometer;
 | 
				
			||||||
 | 
						Vector3 gyroscope;
 | 
				
			||||||
 | 
						Vector2 mouse_pos;
 | 
				
			||||||
 | 
						int64_t mouse_window = 0;
 | 
				
			||||||
 | 
						bool legacy_just_pressed_behavior = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ActionState {
 | 
				
			||||||
 | 
							uint64_t pressed_physics_frame = UINT64_MAX;
 | 
				
			||||||
 | 
							uint64_t pressed_process_frame = UINT64_MAX;
 | 
				
			||||||
 | 
							uint64_t released_physics_frame = UINT64_MAX;
 | 
				
			||||||
 | 
							uint64_t released_process_frame = UINT64_MAX;
 | 
				
			||||||
 | 
							bool exact = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct DeviceState {
 | 
				
			||||||
 | 
								bool pressed[MAX_EVENT] = { false };
 | 
				
			||||||
 | 
								float strength[MAX_EVENT] = { 0.0 };
 | 
				
			||||||
 | 
								float raw_strength[MAX_EVENT] = { 0.0 };
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							bool api_pressed = false;
 | 
				
			||||||
 | 
							float api_strength = 0.0;
 | 
				
			||||||
 | 
							HashMap<int, DeviceState> device_states;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Cache.
 | 
				
			||||||
 | 
							struct ActionStateCache {
 | 
				
			||||||
 | 
								bool pressed = false;
 | 
				
			||||||
 | 
								float strength = false;
 | 
				
			||||||
 | 
								float raw_strength = false;
 | 
				
			||||||
 | 
							} cache;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<StringName, ActionState> action_states;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool emulate_touch_from_mouse = false;
 | 
				
			||||||
 | 
						bool emulate_mouse_from_touch = false;
 | 
				
			||||||
 | 
						bool agile_input_event_flushing = false;
 | 
				
			||||||
 | 
						bool use_accumulated_input = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int mouse_from_touch_index = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct VibrationInfo {
 | 
				
			||||||
 | 
							float weak_magnitude;
 | 
				
			||||||
 | 
							float strong_magnitude;
 | 
				
			||||||
 | 
							float duration; // Duration in seconds
 | 
				
			||||||
 | 
							uint64_t timestamp;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<int, VibrationInfo> joy_vibration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct VelocityTrack {
 | 
				
			||||||
 | 
							uint64_t last_tick = 0;
 | 
				
			||||||
 | 
							Vector2 velocity;
 | 
				
			||||||
 | 
							Vector2 screen_velocity;
 | 
				
			||||||
 | 
							Vector2 accum;
 | 
				
			||||||
 | 
							Vector2 screen_accum;
 | 
				
			||||||
 | 
							float accum_t = 0.0f;
 | 
				
			||||||
 | 
							float min_ref_frame;
 | 
				
			||||||
 | 
							float max_ref_frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void update(const Vector2 &p_delta_p, const Vector2 &p_screen_delta_p);
 | 
				
			||||||
 | 
							void reset();
 | 
				
			||||||
 | 
							VelocityTrack();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Joypad {
 | 
				
			||||||
 | 
							StringName name;
 | 
				
			||||||
 | 
							StringName uid;
 | 
				
			||||||
 | 
							bool connected = false;
 | 
				
			||||||
 | 
							bool last_buttons[(size_t)JoyButton::MAX] = { false };
 | 
				
			||||||
 | 
							float last_axis[(size_t)JoyAxis::MAX] = { 0.0f };
 | 
				
			||||||
 | 
							HatMask last_hat = HatMask::CENTER;
 | 
				
			||||||
 | 
							int mapping = -1;
 | 
				
			||||||
 | 
							int hat_current = 0;
 | 
				
			||||||
 | 
							Dictionary info;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VelocityTrack mouse_velocity_track;
 | 
				
			||||||
 | 
						HashMap<int, VelocityTrack> touch_velocity_track;
 | 
				
			||||||
 | 
						HashMap<int, Joypad> joy_names;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashSet<uint32_t> ignored_device_ids;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int fallback_mapping = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CursorShape default_shape = CURSOR_ARROW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum JoyType {
 | 
				
			||||||
 | 
							TYPE_BUTTON,
 | 
				
			||||||
 | 
							TYPE_AXIS,
 | 
				
			||||||
 | 
							TYPE_HAT,
 | 
				
			||||||
 | 
							TYPE_MAX,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum JoyAxisRange {
 | 
				
			||||||
 | 
							NEGATIVE_HALF_AXIS = -1,
 | 
				
			||||||
 | 
							FULL_AXIS = 0,
 | 
				
			||||||
 | 
							POSITIVE_HALF_AXIS = 1
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct JoyEvent {
 | 
				
			||||||
 | 
							int type = TYPE_MAX;
 | 
				
			||||||
 | 
							int index = -1; // Can be either JoyAxis or JoyButton.
 | 
				
			||||||
 | 
							float value = 0.f;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct JoyBinding {
 | 
				
			||||||
 | 
							JoyType inputType;
 | 
				
			||||||
 | 
							union {
 | 
				
			||||||
 | 
								JoyButton button;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct {
 | 
				
			||||||
 | 
									JoyAxis axis;
 | 
				
			||||||
 | 
									JoyAxisRange range;
 | 
				
			||||||
 | 
									bool invert;
 | 
				
			||||||
 | 
								} axis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct {
 | 
				
			||||||
 | 
									HatDir hat;
 | 
				
			||||||
 | 
									HatMask hat_mask;
 | 
				
			||||||
 | 
								} hat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JoyType outputType;
 | 
				
			||||||
 | 
							union {
 | 
				
			||||||
 | 
								JoyButton button;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct {
 | 
				
			||||||
 | 
									JoyAxis axis;
 | 
				
			||||||
 | 
									JoyAxisRange range;
 | 
				
			||||||
 | 
								} axis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} output;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct JoyDeviceMapping {
 | 
				
			||||||
 | 
							String uid;
 | 
				
			||||||
 | 
							String name;
 | 
				
			||||||
 | 
							Vector<JoyBinding> bindings;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<JoyDeviceMapping> map_db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
 | 
				
			||||||
 | 
						JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
 | 
				
			||||||
 | 
						void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
 | 
				
			||||||
 | 
						JoyButton _get_output_button(const String &output);
 | 
				
			||||||
 | 
						JoyAxis _get_output_axis(const String &output);
 | 
				
			||||||
 | 
						void _button_event(int p_device, JoyButton p_index, bool p_pressed);
 | 
				
			||||||
 | 
						void _axis_event(int p_device, JoyAxis p_axis, float p_value);
 | 
				
			||||||
 | 
						void _update_action_cache(const StringName &p_action_name, ActionState &r_action_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Ref<InputEvent>> buffered_events;
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						HashSet<Ref<InputEvent>> frame_parsed_events;
 | 
				
			||||||
 | 
						uint64_t last_parsed_frame = UINT64_MAX;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class DisplayServer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void (*set_mouse_mode_func)(MouseMode);
 | 
				
			||||||
 | 
						static MouseMode (*get_mouse_mode_func)();
 | 
				
			||||||
 | 
						static void (*warp_mouse_func)(const Vector2 &p_position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static CursorShape (*get_current_cursor_shape_func)();
 | 
				
			||||||
 | 
						static void (*set_custom_mouse_cursor_func)(const Ref<Resource> &, CursorShape, const Vector2 &);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EventDispatchFunc event_dispatch_function = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DISABLE_DEPRECATED
 | 
				
			||||||
 | 
						void _vibrate_handheld_bind_compat_91143(int p_duration_ms = 500);
 | 
				
			||||||
 | 
						static void _bind_compatibility_methods();
 | 
				
			||||||
 | 
					#endif // DISABLE_DEPRECATED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_mouse_mode(MouseMode p_mode);
 | 
				
			||||||
 | 
						MouseMode get_mouse_mode() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Input *get_singleton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_anything_pressed() const;
 | 
				
			||||||
 | 
						bool is_key_pressed(Key p_keycode) const;
 | 
				
			||||||
 | 
						bool is_physical_key_pressed(Key p_keycode) const;
 | 
				
			||||||
 | 
						bool is_key_label_pressed(Key p_keycode) const;
 | 
				
			||||||
 | 
						bool is_mouse_button_pressed(MouseButton p_button) const;
 | 
				
			||||||
 | 
						bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
 | 
				
			||||||
 | 
						bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
 | 
				
			||||||
 | 
						bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
 | 
				
			||||||
 | 
						bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
 | 
				
			||||||
 | 
						float get_action_strength(const StringName &p_action, bool p_exact = false) const;
 | 
				
			||||||
 | 
						float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
 | 
				
			||||||
 | 
						Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float get_joy_axis(int p_device, JoyAxis p_axis) const;
 | 
				
			||||||
 | 
						String get_joy_name(int p_idx);
 | 
				
			||||||
 | 
						TypedArray<int> get_connected_joypads();
 | 
				
			||||||
 | 
						Vector2 get_joy_vibration_strength(int p_device);
 | 
				
			||||||
 | 
						float get_joy_vibration_duration(int p_device);
 | 
				
			||||||
 | 
						uint64_t get_joy_vibration_timestamp(int p_device);
 | 
				
			||||||
 | 
						void joy_connection_changed(int p_idx, bool p_connected, const String &p_name, const String &p_guid = "", const Dictionary &p_joypad_info = Dictionary());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector3 get_gravity() const;
 | 
				
			||||||
 | 
						Vector3 get_accelerometer() const;
 | 
				
			||||||
 | 
						Vector3 get_magnetometer() const;
 | 
				
			||||||
 | 
						Vector3 get_gyroscope() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Point2 get_mouse_position() const;
 | 
				
			||||||
 | 
						Vector2 get_last_mouse_velocity();
 | 
				
			||||||
 | 
						Vector2 get_last_mouse_screen_velocity();
 | 
				
			||||||
 | 
						BitField<MouseButtonMask> get_mouse_button_mask() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void warp_mouse(const Vector2 &p_position);
 | 
				
			||||||
 | 
						Point2 warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void parse_input_event(const Ref<InputEvent> &p_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_gravity(const Vector3 &p_gravity);
 | 
				
			||||||
 | 
						void set_accelerometer(const Vector3 &p_accel);
 | 
				
			||||||
 | 
						void set_magnetometer(const Vector3 &p_magnetometer);
 | 
				
			||||||
 | 
						void set_gyroscope(const Vector3 &p_gyroscope);
 | 
				
			||||||
 | 
						void set_joy_axis(int p_device, JoyAxis p_axis, float p_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
 | 
				
			||||||
 | 
						void stop_joy_vibration(int p_device);
 | 
				
			||||||
 | 
						void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_mouse_position(const Point2 &p_posf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void action_press(const StringName &p_action, float p_strength = 1.f);
 | 
				
			||||||
 | 
						void action_release(const StringName &p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_emulate_touch_from_mouse(bool p_emulate);
 | 
				
			||||||
 | 
						bool is_emulating_touch_from_mouse() const;
 | 
				
			||||||
 | 
						void ensure_touch_mouse_raised();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_emulate_mouse_from_touch(bool p_emulate);
 | 
				
			||||||
 | 
						bool is_emulating_mouse_from_touch() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CursorShape get_default_cursor_shape() const;
 | 
				
			||||||
 | 
						void set_default_cursor_shape(CursorShape p_shape);
 | 
				
			||||||
 | 
						CursorShape get_current_cursor_shape() const;
 | 
				
			||||||
 | 
						void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void parse_mapping(const String &p_mapping);
 | 
				
			||||||
 | 
						void joy_button(int p_device, JoyButton p_button, bool p_pressed);
 | 
				
			||||||
 | 
						void joy_axis(int p_device, JoyAxis p_axis, float p_value);
 | 
				
			||||||
 | 
						void joy_hat(int p_device, BitField<HatMask> p_val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void add_joy_mapping(const String &p_mapping, bool p_update_existing = false);
 | 
				
			||||||
 | 
						void remove_joy_mapping(const String &p_guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int get_unused_joy_id();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_joy_known(int p_device);
 | 
				
			||||||
 | 
						String get_joy_guid(int p_device) const;
 | 
				
			||||||
 | 
						bool should_ignore_device(int p_vendor_id, int p_product_id) const;
 | 
				
			||||||
 | 
						Dictionary get_joy_info(int p_device) const;
 | 
				
			||||||
 | 
						void set_fallback_mapping(const String &p_guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
 | 
						void flush_frame_parsed_events();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						void flush_buffered_events();
 | 
				
			||||||
 | 
						bool is_agile_input_event_flushing();
 | 
				
			||||||
 | 
						void set_agile_input_event_flushing(bool p_enable);
 | 
				
			||||||
 | 
						void set_use_accumulated_input(bool p_enable);
 | 
				
			||||||
 | 
						bool is_using_accumulated_input();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void release_pressed_events();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_event_dispatch_function(EventDispatchFunc p_function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Input();
 | 
				
			||||||
 | 
						~Input();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(Input::MouseMode);
 | 
				
			||||||
 | 
					VARIANT_ENUM_CAST(Input::CursorShape);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // INPUT_H
 | 
				
			||||||
							
								
								
									
										59
									
								
								engine/core/input/input_builders.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								engine/core/input/input_builders.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					"""Functions used to generate source files during build time"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import OrderedDict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_default_controller_mappings(target, source, env):
 | 
				
			||||||
 | 
					    dst = str(target[0])
 | 
				
			||||||
 | 
					    with open(dst, "w", encoding="utf-8", newline="\n") as g:
 | 
				
			||||||
 | 
					        g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
 | 
				
			||||||
 | 
					        g.write('#include "core/typedefs.h"\n')
 | 
				
			||||||
 | 
					        g.write('#include "core/input/default_controller_mappings.h"\n')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # ensure mappings have a consistent order
 | 
				
			||||||
 | 
					        platform_mappings: dict = OrderedDict()
 | 
				
			||||||
 | 
					        for src_path in source:
 | 
				
			||||||
 | 
					            with open(str(src_path), "r", encoding="utf-8") as f:
 | 
				
			||||||
 | 
					                # read mapping file and skip header
 | 
				
			||||||
 | 
					                mapping_file_lines = f.readlines()[2:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            current_platform = None
 | 
				
			||||||
 | 
					            for line in mapping_file_lines:
 | 
				
			||||||
 | 
					                if not line:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                line = line.strip()
 | 
				
			||||||
 | 
					                if len(line) == 0:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                if line[0] == "#":
 | 
				
			||||||
 | 
					                    current_platform = line[1:].strip()
 | 
				
			||||||
 | 
					                    if current_platform not in platform_mappings:
 | 
				
			||||||
 | 
					                        platform_mappings[current_platform] = {}
 | 
				
			||||||
 | 
					                elif current_platform:
 | 
				
			||||||
 | 
					                    line_parts = line.split(",")
 | 
				
			||||||
 | 
					                    guid = line_parts[0]
 | 
				
			||||||
 | 
					                    if guid in platform_mappings[current_platform]:
 | 
				
			||||||
 | 
					                        g.write(
 | 
				
			||||||
 | 
					                            "// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
 | 
				
			||||||
 | 
					                                src_path, current_platform, platform_mappings[current_platform][guid]
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    platform_mappings[current_platform][guid] = line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        platform_variables = {
 | 
				
			||||||
 | 
					            "Linux": "#ifdef LINUXBSD_ENABLED",
 | 
				
			||||||
 | 
					            "Windows": "#ifdef WINDOWS_ENABLED",
 | 
				
			||||||
 | 
					            "Mac OS X": "#ifdef MACOS_ENABLED",
 | 
				
			||||||
 | 
					            "Android": "#ifdef ANDROID_ENABLED",
 | 
				
			||||||
 | 
					            "iOS": "#ifdef IOS_ENABLED",
 | 
				
			||||||
 | 
					            "Web": "#ifdef WEB_ENABLED",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("const char* DefaultControllerMappings::mappings[] = {\n")
 | 
				
			||||||
 | 
					        for platform, mappings in platform_mappings.items():
 | 
				
			||||||
 | 
					            variable = platform_variables[platform]
 | 
				
			||||||
 | 
					            g.write("{}\n".format(variable))
 | 
				
			||||||
 | 
					            for mapping in mappings.values():
 | 
				
			||||||
 | 
					                g.write('\t"{}",\n'.format(mapping))
 | 
				
			||||||
 | 
					            g.write("#endif\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g.write("\tnullptr\n};\n")
 | 
				
			||||||
							
								
								
									
										137
									
								
								engine/core/input/input_enums.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								engine/core/input/input_enums.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,137 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input_enums.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef INPUT_ENUMS_H
 | 
				
			||||||
 | 
					#define INPUT_ENUMS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class HatDir {
 | 
				
			||||||
 | 
						UP = 0,
 | 
				
			||||||
 | 
						RIGHT = 1,
 | 
				
			||||||
 | 
						DOWN = 2,
 | 
				
			||||||
 | 
						LEFT = 3,
 | 
				
			||||||
 | 
						MAX = 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class HatMask {
 | 
				
			||||||
 | 
						CENTER = 0,
 | 
				
			||||||
 | 
						UP = 1,
 | 
				
			||||||
 | 
						RIGHT = 2,
 | 
				
			||||||
 | 
						DOWN = 4,
 | 
				
			||||||
 | 
						LEFT = 8,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class JoyAxis {
 | 
				
			||||||
 | 
						INVALID = -1,
 | 
				
			||||||
 | 
						LEFT_X = 0,
 | 
				
			||||||
 | 
						LEFT_Y = 1,
 | 
				
			||||||
 | 
						RIGHT_X = 2,
 | 
				
			||||||
 | 
						RIGHT_Y = 3,
 | 
				
			||||||
 | 
						TRIGGER_LEFT = 4,
 | 
				
			||||||
 | 
						TRIGGER_RIGHT = 5,
 | 
				
			||||||
 | 
						SDL_MAX = 6,
 | 
				
			||||||
 | 
						MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class JoyButton {
 | 
				
			||||||
 | 
						INVALID = -1,
 | 
				
			||||||
 | 
						A = 0,
 | 
				
			||||||
 | 
						B = 1,
 | 
				
			||||||
 | 
						X = 2,
 | 
				
			||||||
 | 
						Y = 3,
 | 
				
			||||||
 | 
						BACK = 4,
 | 
				
			||||||
 | 
						GUIDE = 5,
 | 
				
			||||||
 | 
						START = 6,
 | 
				
			||||||
 | 
						LEFT_STICK = 7,
 | 
				
			||||||
 | 
						RIGHT_STICK = 8,
 | 
				
			||||||
 | 
						LEFT_SHOULDER = 9,
 | 
				
			||||||
 | 
						RIGHT_SHOULDER = 10,
 | 
				
			||||||
 | 
						DPAD_UP = 11,
 | 
				
			||||||
 | 
						DPAD_DOWN = 12,
 | 
				
			||||||
 | 
						DPAD_LEFT = 13,
 | 
				
			||||||
 | 
						DPAD_RIGHT = 14,
 | 
				
			||||||
 | 
						MISC1 = 15,
 | 
				
			||||||
 | 
						PADDLE1 = 16,
 | 
				
			||||||
 | 
						PADDLE2 = 17,
 | 
				
			||||||
 | 
						PADDLE3 = 18,
 | 
				
			||||||
 | 
						PADDLE4 = 19,
 | 
				
			||||||
 | 
						TOUCHPAD = 20,
 | 
				
			||||||
 | 
						SDL_MAX = 21,
 | 
				
			||||||
 | 
						MAX = 128, // Android supports up to 36 buttons. DirectInput supports up to 128 buttons.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class MIDIMessage {
 | 
				
			||||||
 | 
						NONE = 0,
 | 
				
			||||||
 | 
						NOTE_OFF = 0x8,
 | 
				
			||||||
 | 
						NOTE_ON = 0x9,
 | 
				
			||||||
 | 
						AFTERTOUCH = 0xA,
 | 
				
			||||||
 | 
						CONTROL_CHANGE = 0xB,
 | 
				
			||||||
 | 
						PROGRAM_CHANGE = 0xC,
 | 
				
			||||||
 | 
						CHANNEL_PRESSURE = 0xD,
 | 
				
			||||||
 | 
						PITCH_BEND = 0xE,
 | 
				
			||||||
 | 
						SYSTEM_EXCLUSIVE = 0xF0,
 | 
				
			||||||
 | 
						QUARTER_FRAME = 0xF1,
 | 
				
			||||||
 | 
						SONG_POSITION_POINTER = 0xF2,
 | 
				
			||||||
 | 
						SONG_SELECT = 0xF3,
 | 
				
			||||||
 | 
						TUNE_REQUEST = 0xF6,
 | 
				
			||||||
 | 
						TIMING_CLOCK = 0xF8,
 | 
				
			||||||
 | 
						START = 0xFA,
 | 
				
			||||||
 | 
						CONTINUE = 0xFB,
 | 
				
			||||||
 | 
						STOP = 0xFC,
 | 
				
			||||||
 | 
						ACTIVE_SENSING = 0xFE,
 | 
				
			||||||
 | 
						SYSTEM_RESET = 0xFF,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class MouseButton {
 | 
				
			||||||
 | 
						NONE = 0,
 | 
				
			||||||
 | 
						LEFT = 1,
 | 
				
			||||||
 | 
						RIGHT = 2,
 | 
				
			||||||
 | 
						MIDDLE = 3,
 | 
				
			||||||
 | 
						WHEEL_UP = 4,
 | 
				
			||||||
 | 
						WHEEL_DOWN = 5,
 | 
				
			||||||
 | 
						WHEEL_LEFT = 6,
 | 
				
			||||||
 | 
						WHEEL_RIGHT = 7,
 | 
				
			||||||
 | 
						MB_XBUTTON1 = 8, // "XBUTTON1" is a reserved word on Windows.
 | 
				
			||||||
 | 
						MB_XBUTTON2 = 9, // "XBUTTON2" is a reserved word on Windows.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class MouseButtonMask {
 | 
				
			||||||
 | 
						NONE = 0,
 | 
				
			||||||
 | 
						LEFT = (1 << (int(MouseButton::LEFT) - 1)),
 | 
				
			||||||
 | 
						RIGHT = (1 << (int(MouseButton::RIGHT) - 1)),
 | 
				
			||||||
 | 
						MIDDLE = (1 << (int(MouseButton::MIDDLE) - 1)),
 | 
				
			||||||
 | 
						MB_XBUTTON1 = (1 << (int(MouseButton::MB_XBUTTON1) - 1)),
 | 
				
			||||||
 | 
						MB_XBUTTON2 = (1 << (int(MouseButton::MB_XBUTTON2) - 1)),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
 | 
				
			||||||
 | 
						return MouseButtonMask(1 << ((int)button - 1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // INPUT_ENUMS_H
 | 
				
			||||||
							
								
								
									
										1920
									
								
								engine/core/input/input_event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1920
									
								
								engine/core/input/input_event.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										599
									
								
								engine/core/input/input_event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										599
									
								
								engine/core/input/input_event.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,599 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input_event.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef INPUT_EVENT_H
 | 
				
			||||||
 | 
					#define INPUT_EVENT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/input_enums.h"
 | 
				
			||||||
 | 
					#include "core/io/resource.h"
 | 
				
			||||||
 | 
					#include "core/math/transform_2d.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					#include "core/typedefs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Input Event classes. These are used in the main loop.
 | 
				
			||||||
 | 
					 * The events are pretty obvious.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Shortcut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Input Modifier Status
 | 
				
			||||||
 | 
					 * for keyboard/mouse events.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEvent : public Resource {
 | 
				
			||||||
 | 
						GDCLASS(InputEvent, Resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int device = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						bool canceled = false;
 | 
				
			||||||
 | 
						bool pressed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static const int DEVICE_ID_EMULATION;
 | 
				
			||||||
 | 
						static const int DEVICE_ID_INTERNAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_device(int p_device);
 | 
				
			||||||
 | 
						int get_device() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_action(const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_canceled() const;
 | 
				
			||||||
 | 
						bool is_pressed() const;
 | 
				
			||||||
 | 
						bool is_released() const;
 | 
				
			||||||
 | 
						virtual bool is_echo() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEvent() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventFromWindow : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventFromWindow, InputEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int64_t window_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_window_id(int64_t p_id);
 | 
				
			||||||
 | 
						int64_t get_window_id() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventFromWindow() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventWithModifiers : public InputEventFromWindow {
 | 
				
			||||||
 | 
						GDCLASS(InputEventWithModifiers, InputEventFromWindow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool command_or_control_autoremap = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool shift_pressed = false;
 | 
				
			||||||
 | 
						bool alt_pressed = false;
 | 
				
			||||||
 | 
						bool meta_pressed = false; // "Command" on macOS, "Meta/Win" key on other platforms.
 | 
				
			||||||
 | 
						bool ctrl_pressed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
						void _validate_property(PropertyInfo &p_property) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_command_or_control_autoremap(bool p_enabled);
 | 
				
			||||||
 | 
						bool is_command_or_control_autoremap() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_command_or_control_pressed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_shift_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						bool is_shift_pressed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_alt_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						bool is_alt_pressed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_ctrl_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						bool is_ctrl_pressed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_meta_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						bool is_meta_pressed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_modifiers_from_event(const InputEventWithModifiers *event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BitField<KeyModifierMask> get_modifiers_mask() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventWithModifiers() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventKey : public InputEventWithModifiers {
 | 
				
			||||||
 | 
						GDCLASS(InputEventKey, InputEventWithModifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Key keycode = Key::NONE; // Key enum, without modifier masks.
 | 
				
			||||||
 | 
						Key physical_keycode = Key::NONE;
 | 
				
			||||||
 | 
						Key key_label = Key::NONE;
 | 
				
			||||||
 | 
						uint32_t unicode = 0; ///unicode
 | 
				
			||||||
 | 
						KeyLocation location = KeyLocation::UNSPECIFIED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool echo = false; /// true if this is an echo key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_pressed(bool p_pressed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_keycode(Key p_keycode);
 | 
				
			||||||
 | 
						Key get_keycode() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_physical_keycode(Key p_keycode);
 | 
				
			||||||
 | 
						Key get_physical_keycode() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_key_label(Key p_key_label);
 | 
				
			||||||
 | 
						Key get_key_label() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_unicode(char32_t p_unicode);
 | 
				
			||||||
 | 
						char32_t get_unicode() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_location(KeyLocation p_key_location);
 | 
				
			||||||
 | 
						KeyLocation get_location() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_echo(bool p_enable);
 | 
				
			||||||
 | 
						virtual bool is_echo() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Key get_keycode_with_modifiers() const;
 | 
				
			||||||
 | 
						Key get_physical_keycode_with_modifiers() const;
 | 
				
			||||||
 | 
						Key get_key_label_with_modifiers() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const override { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text_physical_keycode() const;
 | 
				
			||||||
 | 
						virtual String as_text_keycode() const;
 | 
				
			||||||
 | 
						virtual String as_text_key_label() const;
 | 
				
			||||||
 | 
						virtual String as_text_location() const;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventKey() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventMouse : public InputEventWithModifiers {
 | 
				
			||||||
 | 
						GDCLASS(InputEventMouse, InputEventWithModifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BitField<MouseButtonMask> button_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector2 pos;
 | 
				
			||||||
 | 
						Vector2 global_pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_button_mask(BitField<MouseButtonMask> p_mask);
 | 
				
			||||||
 | 
						BitField<MouseButtonMask> get_button_mask() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_position(const Vector2 &p_pos);
 | 
				
			||||||
 | 
						Vector2 get_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_global_position(const Vector2 &p_global_pos);
 | 
				
			||||||
 | 
						Vector2 get_global_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventMouse() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventMouseButton : public InputEventMouse {
 | 
				
			||||||
 | 
						GDCLASS(InputEventMouseButton, InputEventMouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float factor = 1;
 | 
				
			||||||
 | 
						MouseButton button_index = MouseButton::NONE;
 | 
				
			||||||
 | 
						bool double_click = false; //last even less than double click time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_factor(float p_factor);
 | 
				
			||||||
 | 
						float get_factor() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_button_index(MouseButton p_index);
 | 
				
			||||||
 | 
						MouseButton get_button_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						void set_canceled(bool p_canceled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_double_click(bool p_double_click);
 | 
				
			||||||
 | 
						bool is_double_click() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const override { return true; }
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventMouseButton() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventMouseMotion : public InputEventMouse {
 | 
				
			||||||
 | 
						GDCLASS(InputEventMouseMotion, InputEventMouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector2 tilt;
 | 
				
			||||||
 | 
						float pressure = 0;
 | 
				
			||||||
 | 
						Vector2 relative;
 | 
				
			||||||
 | 
						Vector2 screen_relative;
 | 
				
			||||||
 | 
						Vector2 velocity;
 | 
				
			||||||
 | 
						Vector2 screen_velocity;
 | 
				
			||||||
 | 
						bool pen_inverted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_tilt(const Vector2 &p_tilt);
 | 
				
			||||||
 | 
						Vector2 get_tilt() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressure(float p_pressure);
 | 
				
			||||||
 | 
						float get_pressure() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pen_inverted(bool p_inverted);
 | 
				
			||||||
 | 
						bool get_pen_inverted() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_relative(const Vector2 &p_relative);
 | 
				
			||||||
 | 
						Vector2 get_relative() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_relative_screen_position(const Vector2 &p_relative);
 | 
				
			||||||
 | 
						Vector2 get_relative_screen_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_velocity(const Vector2 &p_velocity);
 | 
				
			||||||
 | 
						Vector2 get_velocity() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_screen_velocity(const Vector2 &p_velocity);
 | 
				
			||||||
 | 
						Vector2 get_screen_velocity() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool accumulate(const Ref<InputEvent> &p_event) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventMouseMotion() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventJoypadMotion : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventJoypadMotion, InputEvent);
 | 
				
			||||||
 | 
						JoyAxis axis = (JoyAxis)0; ///< Joypad axis
 | 
				
			||||||
 | 
						float axis_value = 0; ///< -1 to 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_axis(JoyAxis p_axis);
 | 
				
			||||||
 | 
						JoyAxis get_axis() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_axis_value(float p_value);
 | 
				
			||||||
 | 
						float get_axis_value() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const override { return true; }
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<InputEventJoypadMotion> create_reference(JoyAxis p_axis, float p_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventJoypadMotion() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventJoypadButton : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventJoypadButton, InputEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						JoyButton button_index = (JoyButton)0;
 | 
				
			||||||
 | 
						float pressure = 0; //0 to 1
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_button_index(JoyButton p_index);
 | 
				
			||||||
 | 
						JoyButton get_button_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressed(bool p_pressed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressure(float p_pressure);
 | 
				
			||||||
 | 
						float get_pressure() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const override { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<InputEventJoypadButton> create_reference(JoyButton p_btn_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventJoypadButton() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventScreenTouch : public InputEventFromWindow {
 | 
				
			||||||
 | 
						GDCLASS(InputEventScreenTouch, InputEventFromWindow);
 | 
				
			||||||
 | 
						int index = 0;
 | 
				
			||||||
 | 
						Vector2 pos;
 | 
				
			||||||
 | 
						bool double_tap = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_index(int p_index);
 | 
				
			||||||
 | 
						int get_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_position(const Vector2 &p_pos);
 | 
				
			||||||
 | 
						Vector2 get_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressed(bool p_pressed);
 | 
				
			||||||
 | 
						void set_canceled(bool p_canceled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_double_tap(bool p_double_tap);
 | 
				
			||||||
 | 
						bool is_double_tap() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventScreenTouch() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventScreenDrag : public InputEventFromWindow {
 | 
				
			||||||
 | 
						GDCLASS(InputEventScreenDrag, InputEventFromWindow);
 | 
				
			||||||
 | 
						int index = 0;
 | 
				
			||||||
 | 
						Vector2 pos;
 | 
				
			||||||
 | 
						Vector2 relative;
 | 
				
			||||||
 | 
						Vector2 screen_relative;
 | 
				
			||||||
 | 
						Vector2 velocity;
 | 
				
			||||||
 | 
						Vector2 screen_velocity;
 | 
				
			||||||
 | 
						Vector2 tilt;
 | 
				
			||||||
 | 
						float pressure = 0;
 | 
				
			||||||
 | 
						bool pen_inverted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_index(int p_index);
 | 
				
			||||||
 | 
						int get_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_tilt(const Vector2 &p_tilt);
 | 
				
			||||||
 | 
						Vector2 get_tilt() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressure(float p_pressure);
 | 
				
			||||||
 | 
						float get_pressure() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pen_inverted(bool p_inverted);
 | 
				
			||||||
 | 
						bool get_pen_inverted() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_position(const Vector2 &p_pos);
 | 
				
			||||||
 | 
						Vector2 get_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_relative(const Vector2 &p_relative);
 | 
				
			||||||
 | 
						Vector2 get_relative() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_relative_screen_position(const Vector2 &p_relative);
 | 
				
			||||||
 | 
						Vector2 get_relative_screen_position() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_velocity(const Vector2 &p_velocity);
 | 
				
			||||||
 | 
						Vector2 get_velocity() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_screen_velocity(const Vector2 &p_velocity);
 | 
				
			||||||
 | 
						Vector2 get_screen_velocity() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool accumulate(const Ref<InputEvent> &p_event) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventScreenDrag() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventAction : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventAction, InputEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						StringName action;
 | 
				
			||||||
 | 
						float strength = 1.0f;
 | 
				
			||||||
 | 
						int event_index = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_action(const StringName &p_action);
 | 
				
			||||||
 | 
						StringName get_action() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressed(bool p_pressed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_strength(float p_strength);
 | 
				
			||||||
 | 
						float get_strength() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_event_index(int p_index);
 | 
				
			||||||
 | 
						int get_event_index() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action(const StringName &p_action) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
 | 
				
			||||||
 | 
						virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_action_type() const override { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventAction() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventGesture : public InputEventWithModifiers {
 | 
				
			||||||
 | 
						GDCLASS(InputEventGesture, InputEventWithModifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector2 pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_position(const Vector2 &p_pos);
 | 
				
			||||||
 | 
						Vector2 get_position() const;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventMagnifyGesture : public InputEventGesture {
 | 
				
			||||||
 | 
						GDCLASS(InputEventMagnifyGesture, InputEventGesture);
 | 
				
			||||||
 | 
						real_t factor = 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_factor(real_t p_factor);
 | 
				
			||||||
 | 
						real_t get_factor() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventMagnifyGesture() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventPanGesture : public InputEventGesture {
 | 
				
			||||||
 | 
						GDCLASS(InputEventPanGesture, InputEventGesture);
 | 
				
			||||||
 | 
						Vector2 delta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_delta(const Vector2 &p_delta);
 | 
				
			||||||
 | 
						Vector2 get_delta() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventPanGesture() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventMIDI : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventMIDI, InputEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int channel = 0;
 | 
				
			||||||
 | 
						MIDIMessage message = MIDIMessage::NONE;
 | 
				
			||||||
 | 
						int pitch = 0;
 | 
				
			||||||
 | 
						int velocity = 0;
 | 
				
			||||||
 | 
						int instrument = 0;
 | 
				
			||||||
 | 
						int pressure = 0;
 | 
				
			||||||
 | 
						int controller_number = 0;
 | 
				
			||||||
 | 
						int controller_value = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_channel(const int p_channel);
 | 
				
			||||||
 | 
						int get_channel() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_message(const MIDIMessage p_message);
 | 
				
			||||||
 | 
						MIDIMessage get_message() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pitch(const int p_pitch);
 | 
				
			||||||
 | 
						int get_pitch() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_velocity(const int p_velocity);
 | 
				
			||||||
 | 
						int get_velocity() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_instrument(const int p_instrument);
 | 
				
			||||||
 | 
						int get_instrument() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_pressure(const int p_pressure);
 | 
				
			||||||
 | 
						int get_pressure() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_controller_number(const int p_controller_number);
 | 
				
			||||||
 | 
						int get_controller_number() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_controller_value(const int p_controller_value);
 | 
				
			||||||
 | 
						int get_controller_value() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventMIDI() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputEventShortcut : public InputEvent {
 | 
				
			||||||
 | 
						GDCLASS(InputEventShortcut, InputEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<Shortcut> shortcut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_shortcut(Ref<Shortcut> p_shortcut);
 | 
				
			||||||
 | 
						Ref<Shortcut> get_shortcut();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String as_text() const override;
 | 
				
			||||||
 | 
						virtual String to_string() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputEventShortcut();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // INPUT_EVENT_H
 | 
				
			||||||
							
								
								
									
										860
									
								
								engine/core/input/input_map.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										860
									
								
								engine/core/input/input_map.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,860 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input_map.cpp                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "input_map.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/input/input.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "core/variant/typed_array.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					InputMap *InputMap::singleton = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int InputMap::ALL_DEVICES = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns an nonexistent action error message with a suggestion of the closest
 | 
				
			||||||
 | 
					 * matching action name (if possible).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					String InputMap::suggest_actions(const StringName &p_action) const {
 | 
				
			||||||
 | 
						List<StringName> actions = get_actions();
 | 
				
			||||||
 | 
						StringName closest_action;
 | 
				
			||||||
 | 
						float closest_similarity = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Find the most action with the most similar name.
 | 
				
			||||||
 | 
						for (const StringName &action : actions) {
 | 
				
			||||||
 | 
							const float similarity = String(action).similarity(p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (similarity > closest_similarity) {
 | 
				
			||||||
 | 
								closest_action = action;
 | 
				
			||||||
 | 
								closest_similarity = similarity;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (closest_similarity >= 0.4) {
 | 
				
			||||||
 | 
							// Only include a suggestion in the error message if it's similar enough.
 | 
				
			||||||
 | 
							error_message += vformat(" Did you mean \"%s\"?", closest_action);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return error_message;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
					void InputMap::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
 | 
				
			||||||
 | 
						const String pf = p_function;
 | 
				
			||||||
 | 
						bool first_argument_is_action = false;
 | 
				
			||||||
 | 
						if (p_idx == 0) {
 | 
				
			||||||
 | 
							first_argument_is_action = (pf == "has_action" || pf == "erase_action" ||
 | 
				
			||||||
 | 
									pf == "action_set_deadzone" || pf == "action_get_deadzone" ||
 | 
				
			||||||
 | 
									pf == "action_has_event" || pf == "action_add_event" || pf == "action_get_events" ||
 | 
				
			||||||
 | 
									pf == "action_erase_event" || pf == "action_erase_events");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (first_argument_is_action || (p_idx == 1 && pf == "event_is_action")) {
 | 
				
			||||||
 | 
							// Cannot rely on `get_actions()`, otherwise the actions would be in the context of the Editor (no user-defined actions).
 | 
				
			||||||
 | 
							List<PropertyInfo> pinfo;
 | 
				
			||||||
 | 
							ProjectSettings::get_singleton()->get_property_list(&pinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const PropertyInfo &pi : pinfo) {
 | 
				
			||||||
 | 
								if (!pi.name.begins_with("input/")) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
 | 
				
			||||||
 | 
								r_options->push_back(name.quote());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Object::get_argument_options(p_function, p_idx, r_options);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::add_action(const StringName &p_action, float p_deadzone) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\".");
 | 
				
			||||||
 | 
						input_map[p_action] = Action();
 | 
				
			||||||
 | 
						static int last_id = 1;
 | 
				
			||||||
 | 
						input_map[p_action].id = last_id;
 | 
				
			||||||
 | 
						input_map[p_action].deadzone = p_deadzone;
 | 
				
			||||||
 | 
						last_id++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::erase_action(const StringName &p_action) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_map.erase(p_action);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypedArray<StringName> InputMap::_get_actions() {
 | 
				
			||||||
 | 
						TypedArray<StringName> ret;
 | 
				
			||||||
 | 
						List<StringName> actions = get_actions();
 | 
				
			||||||
 | 
						if (actions.is_empty()) {
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const StringName &E : actions) {
 | 
				
			||||||
 | 
							ret.push_back(E);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					List<StringName> InputMap::get_actions() const {
 | 
				
			||||||
 | 
						List<StringName> actions = List<StringName>();
 | 
				
			||||||
 | 
						if (input_map.is_empty()) {
 | 
				
			||||||
 | 
							return actions;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<StringName, Action> &E : input_map) {
 | 
				
			||||||
 | 
							actions.push_back(E.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return actions;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
 | 
				
			||||||
 | 
							int device = E->get()->get_device();
 | 
				
			||||||
 | 
							if (device == ALL_DEVICES || device == p_event->get_device()) {
 | 
				
			||||||
 | 
								if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
 | 
				
			||||||
 | 
									if (r_event_index) {
 | 
				
			||||||
 | 
										*r_event_index = i;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return E;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool InputMap::has_action(const StringName &p_action) const {
 | 
				
			||||||
 | 
						return input_map.has(p_action);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float InputMap::action_get_deadzone(const StringName &p_action) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return input_map[p_action].deadzone;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_map[p_action].deadzone = p_deadzone;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
 | 
				
			||||||
 | 
						if (_find_event(input_map[p_action], p_event, true)) {
 | 
				
			||||||
 | 
							return; // Already added.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_map[p_action].inputs.push_back(p_event);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, suggest_actions(p_action));
 | 
				
			||||||
 | 
						return (_find_event(input_map[p_action], p_event, true) != nullptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
 | 
				
			||||||
 | 
						if (E) {
 | 
				
			||||||
 | 
							input_map[p_action].inputs.erase(E);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Input::get_singleton()->is_action_pressed(p_action)) {
 | 
				
			||||||
 | 
								Input::get_singleton()->action_release(p_action);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::action_erase_events(const StringName &p_action) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_map[p_action].inputs.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) {
 | 
				
			||||||
 | 
						TypedArray<InputEvent> ret;
 | 
				
			||||||
 | 
						const List<Ref<InputEvent>> *al = action_get_events(p_action);
 | 
				
			||||||
 | 
						if (al) {
 | 
				
			||||||
 | 
							for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
 | 
				
			||||||
 | 
								ret.push_back(E->get());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
 | 
				
			||||||
 | 
						HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
 | 
				
			||||||
 | 
						if (!E) {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &E->value.inputs;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
 | 
				
			||||||
 | 
						return event_get_action_status(p_event, p_action, p_exact_match);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
 | 
				
			||||||
 | 
						int index = -1;
 | 
				
			||||||
 | 
						event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
 | 
				
			||||||
 | 
						return index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
 | 
				
			||||||
 | 
						HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<InputEventAction> input_event_action = p_event;
 | 
				
			||||||
 | 
						if (input_event_action.is_valid()) {
 | 
				
			||||||
 | 
							const bool pressed = input_event_action->is_pressed();
 | 
				
			||||||
 | 
							if (r_pressed != nullptr) {
 | 
				
			||||||
 | 
								*r_pressed = pressed;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							const float strength = pressed ? input_event_action->get_strength() : 0.0f;
 | 
				
			||||||
 | 
							if (r_strength != nullptr) {
 | 
				
			||||||
 | 
								*r_strength = strength;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (r_raw_strength != nullptr) {
 | 
				
			||||||
 | 
								*r_raw_strength = strength;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (r_event_index) {
 | 
				
			||||||
 | 
								if (input_event_action->get_event_index() >= 0) {
 | 
				
			||||||
 | 
									*r_event_index = input_event_action->get_event_index();
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*r_event_index = E->value.inputs.size();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return input_event_action->get_action() == p_action;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index);
 | 
				
			||||||
 | 
						return event != nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const HashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
 | 
				
			||||||
 | 
						return input_map;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::load_from_project_settings() {
 | 
				
			||||||
 | 
						input_map.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<PropertyInfo> pinfo;
 | 
				
			||||||
 | 
						ProjectSettings::get_singleton()->get_property_list(&pinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const PropertyInfo &pi : pinfo) {
 | 
				
			||||||
 | 
							if (!pi.name.begins_with("input/")) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Dictionary action = GLOBAL_GET(pi.name);
 | 
				
			||||||
 | 
							float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
 | 
				
			||||||
 | 
							Array events = action["events"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							add_action(name, deadzone);
 | 
				
			||||||
 | 
							for (int i = 0; i < events.size(); i++) {
 | 
				
			||||||
 | 
								Ref<InputEvent> event = events[i];
 | 
				
			||||||
 | 
								if (event.is_null()) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								action_add_event(name, event);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _BuiltinActionDisplayName {
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						const char *display_name;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
 | 
				
			||||||
 | 
						/* clang-format off */
 | 
				
			||||||
 | 
					    { "ui_accept",                                     TTRC("Accept") },
 | 
				
			||||||
 | 
					    { "ui_select",                                     TTRC("Select") },
 | 
				
			||||||
 | 
					    { "ui_cancel",                                     TTRC("Cancel") },
 | 
				
			||||||
 | 
					    { "ui_focus_next",                                 TTRC("Focus Next") },
 | 
				
			||||||
 | 
					    { "ui_focus_prev",                                 TTRC("Focus Prev") },
 | 
				
			||||||
 | 
					    { "ui_left",                                       TTRC("Left") },
 | 
				
			||||||
 | 
					    { "ui_right",                                      TTRC("Right") },
 | 
				
			||||||
 | 
					    { "ui_up",                                         TTRC("Up") },
 | 
				
			||||||
 | 
					    { "ui_down",                                       TTRC("Down") },
 | 
				
			||||||
 | 
					    { "ui_page_up",                                    TTRC("Page Up") },
 | 
				
			||||||
 | 
					    { "ui_page_down",                                  TTRC("Page Down") },
 | 
				
			||||||
 | 
					    { "ui_home",                                       TTRC("Home") },
 | 
				
			||||||
 | 
					    { "ui_end",                                        TTRC("End") },
 | 
				
			||||||
 | 
					    { "ui_cut",                                        TTRC("Cut") },
 | 
				
			||||||
 | 
					    { "ui_copy",                                       TTRC("Copy") },
 | 
				
			||||||
 | 
					    { "ui_paste",                                      TTRC("Paste") },
 | 
				
			||||||
 | 
					    { "ui_undo",                                       TTRC("Undo") },
 | 
				
			||||||
 | 
					    { "ui_redo",                                       TTRC("Redo") },
 | 
				
			||||||
 | 
					    { "ui_text_completion_query",                      TTRC("Completion Query") },
 | 
				
			||||||
 | 
					    { "ui_text_newline",                               TTRC("New Line") },
 | 
				
			||||||
 | 
					    { "ui_text_newline_blank",                         TTRC("New Blank Line") },
 | 
				
			||||||
 | 
					    { "ui_text_newline_above",                         TTRC("New Line Above") },
 | 
				
			||||||
 | 
					    { "ui_text_indent",                                TTRC("Indent") },
 | 
				
			||||||
 | 
					    { "ui_text_dedent",                                TTRC("Dedent") },
 | 
				
			||||||
 | 
					    { "ui_text_backspace",                             TTRC("Backspace") },
 | 
				
			||||||
 | 
					    { "ui_text_backspace_word",                        TTRC("Backspace Word") },
 | 
				
			||||||
 | 
					    { "ui_text_backspace_word.macos",                  TTRC("Backspace Word") },
 | 
				
			||||||
 | 
					    { "ui_text_backspace_all_to_left",                 TTRC("Backspace all to Left") },
 | 
				
			||||||
 | 
					    { "ui_text_backspace_all_to_left.macos",           TTRC("Backspace all to Left") },
 | 
				
			||||||
 | 
					    { "ui_text_delete",                                TTRC("Delete") },
 | 
				
			||||||
 | 
					    { "ui_text_delete_word",                           TTRC("Delete Word") },
 | 
				
			||||||
 | 
					    { "ui_text_delete_word.macos",                     TTRC("Delete Word") },
 | 
				
			||||||
 | 
					    { "ui_text_delete_all_to_right",                   TTRC("Delete all to Right") },
 | 
				
			||||||
 | 
					    { "ui_text_delete_all_to_right.macos",             TTRC("Delete all to Right") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_left",                            TTRC("Caret Left") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_word_left",                       TTRC("Caret Word Left") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_word_left.macos",                 TTRC("Caret Word Left") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_right",                           TTRC("Caret Right") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_word_right",                      TTRC("Caret Word Right") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_word_right.macos",                TTRC("Caret Word Right") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_up",                              TTRC("Caret Up") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_down",                            TTRC("Caret Down") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_line_start",                      TTRC("Caret Line Start") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_line_start.macos",                TTRC("Caret Line Start") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_line_end",                        TTRC("Caret Line End") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_line_end.macos",                  TTRC("Caret Line End") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_page_up",                         TTRC("Caret Page Up") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_page_down",                       TTRC("Caret Page Down") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_document_start",                  TTRC("Caret Document Start") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_document_start.macos",            TTRC("Caret Document Start") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_document_end",                    TTRC("Caret Document End") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_document_end.macos",              TTRC("Caret Document End") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_add_below",                       TTRC("Caret Add Below") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_add_below.macos",                 TTRC("Caret Add Below") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_add_above",                       TTRC("Caret Add Above") },
 | 
				
			||||||
 | 
					    { "ui_text_caret_add_above.macos",                 TTRC("Caret Add Above") },
 | 
				
			||||||
 | 
					    { "ui_text_scroll_up",                             TTRC("Scroll Up") },
 | 
				
			||||||
 | 
					    { "ui_text_scroll_up.macos",                       TTRC("Scroll Up") },
 | 
				
			||||||
 | 
					    { "ui_text_scroll_down",                           TTRC("Scroll Down") },
 | 
				
			||||||
 | 
					    { "ui_text_scroll_down.macos",                     TTRC("Scroll Down") },
 | 
				
			||||||
 | 
					    { "ui_text_select_all",                            TTRC("Select All") },
 | 
				
			||||||
 | 
					    { "ui_text_select_word_under_caret",               TTRC("Select Word Under Caret") },
 | 
				
			||||||
 | 
					    { "ui_text_add_selection_for_next_occurrence",     TTRC("Add Selection for Next Occurrence") },
 | 
				
			||||||
 | 
					    { "ui_text_skip_selection_for_next_occurrence",    TTRC("Skip Selection for Next Occurrence") },
 | 
				
			||||||
 | 
					    { "ui_text_clear_carets_and_selection",            TTRC("Clear Carets and Selection") },
 | 
				
			||||||
 | 
					    { "ui_text_toggle_insert_mode",                    TTRC("Toggle Insert Mode") },
 | 
				
			||||||
 | 
					    { "ui_text_submit",                                TTRC("Submit Text") },
 | 
				
			||||||
 | 
					    { "ui_graph_duplicate",                            TTRC("Duplicate Nodes") },
 | 
				
			||||||
 | 
					    { "ui_graph_delete",                               TTRC("Delete Nodes") },
 | 
				
			||||||
 | 
					    { "ui_filedialog_up_one_level",                    TTRC("Go Up One Level") },
 | 
				
			||||||
 | 
					    { "ui_filedialog_refresh",                         TTRC("Refresh") },
 | 
				
			||||||
 | 
					    { "ui_filedialog_show_hidden",                     TTRC("Show Hidden") },
 | 
				
			||||||
 | 
					    { "ui_swap_input_direction ",                      TTRC("Swap Input Direction") },
 | 
				
			||||||
 | 
					    { "",                                              ""}
 | 
				
			||||||
 | 
						/* clang-format on */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String InputMap::get_builtin_display_name(const String &p_name) const {
 | 
				
			||||||
 | 
						int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							if (_builtin_action_display_names[i].name == p_name) {
 | 
				
			||||||
 | 
								return RTR(_builtin_action_display_names[i].display_name);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return p_name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
 | 
				
			||||||
 | 
						// Return cache if it has already been built.
 | 
				
			||||||
 | 
						if (default_builtin_cache.size()) {
 | 
				
			||||||
 | 
							return default_builtin_cache;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Ref<InputEvent>> inputs;
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::SPACE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_accept", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::Y));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::SPACE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_select", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_cancel", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::TAB));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_focus_next", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_focus_prev", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::LEFT));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_LEFT));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, -1.0));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_left", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_RIGHT));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, 1.0));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_right", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_UP));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, -1.0));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_up", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_DOWN));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, 1.0));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_down", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_page_up", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_page_down", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::HOME));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_home", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::END));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_end", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ///// UI basic Shortcuts /////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::X | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_cut", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::C | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_copy", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_paste", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_undo", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::Y | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_redo", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ///// UI Text Input Shortcuts /////
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::SPACE | KeyModifierMask::CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_completion_query", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_completion_accept", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::TAB));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_completion_replace", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Newlines
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_newline", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_newline_blank", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_newline_above", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Indentation
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::TAB));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_indent", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_dedent", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Backspace and Delete
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::SHIFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_backspace", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_backspace_word", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_backspace_word.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_backspace_all_to_left.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_delete", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_delete_word", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_delete_word.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_delete_all_to_right.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Movement Left/Right
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::LEFT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_left", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_word_left", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_word_left.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_right", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_word_right", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_word_right.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Movement Up/Down
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_up", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_down", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Movement Line Start/End
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::HOME));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_line_start", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::HOME));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_line_start.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::END));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_line_end", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::E | KeyModifierMask::CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::END));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_line_end.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Movement Page Up/Down
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_page_up", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_page_down", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Movement Document Start/End
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_document_start", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_document_start.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_document_end", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Caret Addition Below/Above
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_add_below", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_add_above", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Scrolling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_scroll_up", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_scroll_up.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_scroll_down", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_scroll_down.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text Misc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_select_all", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::CTRL | KeyModifierMask::META));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_select_word_under_caret.macos", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_skip_selection_for_next_occurrence", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::INSERT));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::MENU));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_menu", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::ENTER));
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_text_submit", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ///// UI Graph Shortcuts /////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_graph_duplicate", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_graph_delete", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ///// UI File Dialog Shortcuts /////
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::F5));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_filedialog_refresh", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::H));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputs = List<Ref<InputEvent>>();
 | 
				
			||||||
 | 
						inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
 | 
				
			||||||
 | 
						default_builtin_cache.insert("ui_swap_input_direction", inputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return default_builtin_cache;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_feature_overrides_applied() {
 | 
				
			||||||
 | 
						if (default_builtin_with_overrides_cache.size() > 0) {
 | 
				
			||||||
 | 
							return default_builtin_with_overrides_cache;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const HashMap<String, List<Ref<InputEvent>>> &builtins = get_builtins();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get a list of all built in inputs which are valid overrides for the OS
 | 
				
			||||||
 | 
						// Key = builtin name (e.g. ui_accept)
 | 
				
			||||||
 | 
						// Value = override/feature names (e.g. macos, if it was defined as "ui_accept.macos" and the platform supports that feature)
 | 
				
			||||||
 | 
						HashMap<String, Vector<String>> builtins_with_overrides;
 | 
				
			||||||
 | 
						for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
 | 
				
			||||||
 | 
							String fullname = E.key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Vector<String> split = fullname.split(".");
 | 
				
			||||||
 | 
							const String &name = split[0];
 | 
				
			||||||
 | 
							String override_for = split.size() > 1 ? split[1] : String();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!override_for.is_empty() && OS::get_singleton()->has_feature(override_for)) {
 | 
				
			||||||
 | 
								builtins_with_overrides[name].push_back(override_for);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
 | 
				
			||||||
 | 
							String fullname = E.key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Vector<String> split = fullname.split(".");
 | 
				
			||||||
 | 
							const String &name = split[0];
 | 
				
			||||||
 | 
							String override_for = split.size() > 1 ? split[1] : String();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (builtins_with_overrides.has(name) && override_for.is_empty()) {
 | 
				
			||||||
 | 
								// Builtin has an override but this particular one is not an override, so skip.
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!override_for.is_empty() && !OS::get_singleton()->has_feature(override_for)) {
 | 
				
			||||||
 | 
								// OS does not support this override - skip.
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default_builtin_with_overrides_cache.insert(name, E.value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return default_builtin_with_overrides_cache;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InputMap::load_default() {
 | 
				
			||||||
 | 
						HashMap<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
 | 
				
			||||||
 | 
							String name = E.key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							add_action(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const List<Ref<InputEvent>> &inputs = E.value;
 | 
				
			||||||
 | 
							for (const List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
 | 
				
			||||||
 | 
								Ref<InputEventKey> iek = I->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// For the editor, only add keyboard actions.
 | 
				
			||||||
 | 
								if (iek.is_valid()) {
 | 
				
			||||||
 | 
									action_add_event(name, I->get());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					InputMap::InputMap() {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(singleton, "Singleton in InputMap already exist.");
 | 
				
			||||||
 | 
						singleton = this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					InputMap::~InputMap() {
 | 
				
			||||||
 | 
						singleton = nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										111
									
								
								engine/core/input/input_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								engine/core/input/input_map.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  input_map.h                                                           */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef INPUT_MAP_H
 | 
				
			||||||
 | 
					#define INPUT_MAP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/input_event.h"
 | 
				
			||||||
 | 
					#include "core/object/class_db.h"
 | 
				
			||||||
 | 
					#include "core/object/object.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class TypedArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InputMap : public Object {
 | 
				
			||||||
 | 
						GDCLASS(InputMap, Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * A special value used to signify that a given Action can be triggered by any device
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static int ALL_DEVICES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Action {
 | 
				
			||||||
 | 
							int id;
 | 
				
			||||||
 | 
							float deadzone;
 | 
				
			||||||
 | 
							List<Ref<InputEvent>> inputs;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						static InputMap *singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutable HashMap<StringName, Action> input_map;
 | 
				
			||||||
 | 
						HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
 | 
				
			||||||
 | 
						HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypedArray<InputEvent> _action_get_events(const StringName &p_action);
 | 
				
			||||||
 | 
						TypedArray<StringName> _get_actions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_action(const StringName &p_action) const;
 | 
				
			||||||
 | 
						List<StringName> get_actions() const;
 | 
				
			||||||
 | 
						void add_action(const StringName &p_action, float p_deadzone = 0.5);
 | 
				
			||||||
 | 
						void erase_action(const StringName &p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float action_get_deadzone(const StringName &p_action);
 | 
				
			||||||
 | 
						void action_set_deadzone(const StringName &p_action, float p_deadzone);
 | 
				
			||||||
 | 
						void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
 | 
				
			||||||
 | 
						bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
 | 
				
			||||||
 | 
						void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
 | 
				
			||||||
 | 
						void action_erase_events(const StringName &p_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
 | 
				
			||||||
 | 
						bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
 | 
				
			||||||
 | 
						bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const HashMap<StringName, Action> &get_action_map() const;
 | 
				
			||||||
 | 
						void load_from_project_settings();
 | 
				
			||||||
 | 
						void load_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String suggest_actions(const StringName &p_action) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TOOLS_ENABLED
 | 
				
			||||||
 | 
						virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_builtin_display_name(const String &p_name) const;
 | 
				
			||||||
 | 
						// Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat.
 | 
				
			||||||
 | 
						const HashMap<String, List<Ref<InputEvent>>> &get_builtins();
 | 
				
			||||||
 | 
						const HashMap<String, List<Ref<InputEvent>>> &get_builtins_with_feature_overrides_applied();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputMap();
 | 
				
			||||||
 | 
						~InputMap();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // INPUT_MAP_H
 | 
				
			||||||
							
								
								
									
										132
									
								
								engine/core/input/shortcut.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								engine/core/input/shortcut.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  shortcut.cpp                                                          */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "shortcut.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Shortcut::set_events(const Array &p_events) {
 | 
				
			||||||
 | 
						for (int i = 0; i < p_events.size(); i++) {
 | 
				
			||||||
 | 
							Ref<InputEventShortcut> ies = p_events[i];
 | 
				
			||||||
 | 
							ERR_FAIL_COND_MSG(ies.is_valid(), "Cannot set a shortcut event to an instance of InputEventShortcut.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						events = p_events;
 | 
				
			||||||
 | 
						emit_changed();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Shortcut::set_events_list(const List<Ref<InputEvent>> *p_events) {
 | 
				
			||||||
 | 
						events.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const Ref<InputEvent> &ie : *p_events) {
 | 
				
			||||||
 | 
							events.push_back(ie);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array Shortcut::get_events() const {
 | 
				
			||||||
 | 
						return events;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
 | 
				
			||||||
 | 
						Ref<InputEventShortcut> ies = p_event;
 | 
				
			||||||
 | 
						if (ies.is_valid()) {
 | 
				
			||||||
 | 
							if (ies->get_shortcut().ptr() == this) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < events.size(); i++) {
 | 
				
			||||||
 | 
							Ref<InputEvent> ie = events[i];
 | 
				
			||||||
 | 
							bool valid = ie.is_valid() && ie->is_match(p_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Stop on first valid event - don't need to check further.
 | 
				
			||||||
 | 
							if (valid) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String Shortcut::get_as_text() const {
 | 
				
			||||||
 | 
						for (int i = 0; i < events.size(); i++) {
 | 
				
			||||||
 | 
							Ref<InputEvent> ie = events[i];
 | 
				
			||||||
 | 
							// Return first shortcut which is valid
 | 
				
			||||||
 | 
							if (ie.is_valid()) {
 | 
				
			||||||
 | 
								return ie->as_text();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return "None";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Shortcut::has_valid_event() const {
 | 
				
			||||||
 | 
						// Tests if there is ANY input event which is valid.
 | 
				
			||||||
 | 
						for (int i = 0; i < events.size(); i++) {
 | 
				
			||||||
 | 
							Ref<InputEvent> ie = events[i];
 | 
				
			||||||
 | 
							if (ie.is_valid()) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Shortcut::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("set_events", "events"), &Shortcut::set_events);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_events"), &Shortcut::get_events);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("InputEvent")), "set_events", "get_events");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Shortcut::is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2) {
 | 
				
			||||||
 | 
						if (p_event_array1.size() != p_event_array2.size()) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_same = true;
 | 
				
			||||||
 | 
						for (int i = 0; i < p_event_array1.size(); i++) {
 | 
				
			||||||
 | 
							Ref<InputEvent> ie_1 = p_event_array1[i];
 | 
				
			||||||
 | 
							Ref<InputEvent> ie_2 = p_event_array2[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							is_same = ie_1->is_match(ie_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Break on the first that doesn't match - don't need to check further.
 | 
				
			||||||
 | 
							if (!is_same) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return is_same;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								engine/core/input/shortcut.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								engine/core/input/shortcut.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  shortcut.h                                                            */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SHORTCUT_H
 | 
				
			||||||
 | 
					#define SHORTCUT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/input/input_event.h"
 | 
				
			||||||
 | 
					#include "core/io/resource.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Shortcut : public Resource {
 | 
				
			||||||
 | 
						GDCLASS(Shortcut, Resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Array events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_events(const Array &p_events);
 | 
				
			||||||
 | 
						Array get_events() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_events_list(const List<Ref<InputEvent>> *p_events);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool matches_event(const Ref<InputEvent> &p_event) const;
 | 
				
			||||||
 | 
						bool has_valid_event() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String get_as_text() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SHORTCUT_H
 | 
				
			||||||
							
								
								
									
										5
									
								
								engine/core/io/SCsub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								engine/core/io/SCsub
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Import("env")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env.add_source_files(env.core_sources, "*.cpp")
 | 
				
			||||||
							
								
								
									
										357
									
								
								engine/core/io/compression.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								engine/core/io/compression.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,357 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  compression.cpp                                                       */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "compression.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/io/zip_io.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "thirdparty/misc/fastlz.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <zlib.h>
 | 
				
			||||||
 | 
					#include <zstd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef BROTLI_ENABLED
 | 
				
			||||||
 | 
					#include <brotli/decode.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
				
			||||||
 | 
						switch (p_mode) {
 | 
				
			||||||
 | 
							case MODE_BROTLI: {
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(-1, "Only brotli decompression is supported.");
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_FASTLZ: {
 | 
				
			||||||
 | 
								if (p_src_size < 16) {
 | 
				
			||||||
 | 
									uint8_t src[16];
 | 
				
			||||||
 | 
									memset(&src[p_src_size], 0, 16 - p_src_size);
 | 
				
			||||||
 | 
									memcpy(src, p_src, p_src_size);
 | 
				
			||||||
 | 
									return fastlz_compress(src, 16, p_dst);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return fastlz_compress(p_src, p_src_size, p_dst);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_DEFLATE:
 | 
				
			||||||
 | 
							case MODE_GZIP: {
 | 
				
			||||||
 | 
								int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								z_stream strm;
 | 
				
			||||||
 | 
								strm.zalloc = zipio_alloc;
 | 
				
			||||||
 | 
								strm.zfree = zipio_free;
 | 
				
			||||||
 | 
								strm.opaque = Z_NULL;
 | 
				
			||||||
 | 
								int level = p_mode == MODE_DEFLATE ? zlib_level : gzip_level;
 | 
				
			||||||
 | 
								int err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
 | 
				
			||||||
 | 
								if (err != Z_OK) {
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								strm.avail_in = p_src_size;
 | 
				
			||||||
 | 
								int aout = deflateBound(&strm, p_src_size);
 | 
				
			||||||
 | 
								strm.avail_out = aout;
 | 
				
			||||||
 | 
								strm.next_in = (Bytef *)p_src;
 | 
				
			||||||
 | 
								strm.next_out = p_dst;
 | 
				
			||||||
 | 
								deflate(&strm, Z_FINISH);
 | 
				
			||||||
 | 
								aout = aout - strm.avail_out;
 | 
				
			||||||
 | 
								deflateEnd(&strm);
 | 
				
			||||||
 | 
								return aout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_ZSTD: {
 | 
				
			||||||
 | 
								ZSTD_CCtx *cctx = ZSTD_createCCtx();
 | 
				
			||||||
 | 
								ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, zstd_level);
 | 
				
			||||||
 | 
								if (zstd_long_distance_matching) {
 | 
				
			||||||
 | 
									ZSTD_CCtx_setParameter(cctx, ZSTD_c_enableLongDistanceMatching, 1);
 | 
				
			||||||
 | 
									ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, zstd_window_log_size);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								int max_dst_size = get_max_compressed_buffer_size(p_src_size, MODE_ZSTD);
 | 
				
			||||||
 | 
								int ret = ZSTD_compressCCtx(cctx, p_dst, max_dst_size, p_src, p_src_size, zstd_level);
 | 
				
			||||||
 | 
								ZSTD_freeCCtx(cctx);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_V(-1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Compression::get_max_compressed_buffer_size(int p_src_size, Mode p_mode) {
 | 
				
			||||||
 | 
						switch (p_mode) {
 | 
				
			||||||
 | 
							case MODE_BROTLI: {
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(-1, "Only brotli decompression is supported.");
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_FASTLZ: {
 | 
				
			||||||
 | 
								int ss = p_src_size + p_src_size * 6 / 100;
 | 
				
			||||||
 | 
								if (ss < 66) {
 | 
				
			||||||
 | 
									ss = 66;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_DEFLATE:
 | 
				
			||||||
 | 
							case MODE_GZIP: {
 | 
				
			||||||
 | 
								int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								z_stream strm;
 | 
				
			||||||
 | 
								strm.zalloc = zipio_alloc;
 | 
				
			||||||
 | 
								strm.zfree = zipio_free;
 | 
				
			||||||
 | 
								strm.opaque = Z_NULL;
 | 
				
			||||||
 | 
								int err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
 | 
				
			||||||
 | 
								if (err != Z_OK) {
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								int aout = deflateBound(&strm, p_src_size);
 | 
				
			||||||
 | 
								deflateEnd(&strm);
 | 
				
			||||||
 | 
								return aout;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_ZSTD: {
 | 
				
			||||||
 | 
								return ZSTD_compressBound(p_src_size);
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_V(-1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
				
			||||||
 | 
						switch (p_mode) {
 | 
				
			||||||
 | 
							case MODE_BROTLI: {
 | 
				
			||||||
 | 
					#ifdef BROTLI_ENABLED
 | 
				
			||||||
 | 
								size_t ret_size = p_dst_max_size;
 | 
				
			||||||
 | 
								BrotliDecoderResult res = BrotliDecoderDecompress(p_src_size, p_src, &ret_size, p_dst);
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(res != BROTLI_DECODER_RESULT_SUCCESS, -1);
 | 
				
			||||||
 | 
								return ret_size;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(-1, "Godot was compiled without brotli support.");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_FASTLZ: {
 | 
				
			||||||
 | 
								int ret_size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p_dst_max_size < 16) {
 | 
				
			||||||
 | 
									uint8_t dst[16];
 | 
				
			||||||
 | 
									fastlz_decompress(p_src, p_src_size, dst, 16);
 | 
				
			||||||
 | 
									memcpy(p_dst, dst, p_dst_max_size);
 | 
				
			||||||
 | 
									ret_size = p_dst_max_size;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ret_size;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_DEFLATE:
 | 
				
			||||||
 | 
							case MODE_GZIP: {
 | 
				
			||||||
 | 
								int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								z_stream strm;
 | 
				
			||||||
 | 
								strm.zalloc = zipio_alloc;
 | 
				
			||||||
 | 
								strm.zfree = zipio_free;
 | 
				
			||||||
 | 
								strm.opaque = Z_NULL;
 | 
				
			||||||
 | 
								strm.avail_in = 0;
 | 
				
			||||||
 | 
								strm.next_in = Z_NULL;
 | 
				
			||||||
 | 
								int err = inflateInit2(&strm, window_bits);
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(err != Z_OK, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								strm.avail_in = p_src_size;
 | 
				
			||||||
 | 
								strm.avail_out = p_dst_max_size;
 | 
				
			||||||
 | 
								strm.next_in = (Bytef *)p_src;
 | 
				
			||||||
 | 
								strm.next_out = p_dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = inflate(&strm, Z_FINISH);
 | 
				
			||||||
 | 
								int total = strm.total_out;
 | 
				
			||||||
 | 
								inflateEnd(&strm);
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V(err != Z_STREAM_END, -1);
 | 
				
			||||||
 | 
								return total;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case MODE_ZSTD: {
 | 
				
			||||||
 | 
								ZSTD_DCtx *dctx = ZSTD_createDCtx();
 | 
				
			||||||
 | 
								if (zstd_long_distance_matching) {
 | 
				
			||||||
 | 
									ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
 | 
				
			||||||
 | 
								ZSTD_freeDCtx(dctx);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_V(-1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						This will handle both Gzip and Deflate streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
 | 
				
			||||||
 | 
						This is required for compressed data whose final uncompressed size is unknown, as is the case for HTTP response bodies.
 | 
				
			||||||
 | 
						This is much slower however than using Compression::decompress because it may result in multiple full copies of the output buffer.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
 | 
				
			||||||
 | 
						uint8_t *dst = nullptr;
 | 
				
			||||||
 | 
						int out_mark = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V(p_src_size <= 0, Z_DATA_ERROR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_mode == MODE_BROTLI) {
 | 
				
			||||||
 | 
					#ifdef BROTLI_ENABLED
 | 
				
			||||||
 | 
							BrotliDecoderResult ret;
 | 
				
			||||||
 | 
							BrotliDecoderState *state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
 | 
				
			||||||
 | 
							ERR_FAIL_NULL_V(state, Z_DATA_ERROR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Setup the stream inputs.
 | 
				
			||||||
 | 
							const uint8_t *next_in = p_src;
 | 
				
			||||||
 | 
							size_t avail_in = p_src_size;
 | 
				
			||||||
 | 
							uint8_t *next_out = nullptr;
 | 
				
			||||||
 | 
							size_t avail_out = 0;
 | 
				
			||||||
 | 
							size_t total_out = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Ensure the destination buffer is empty.
 | 
				
			||||||
 | 
							p_dst_vect->clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Decompress until stream ends or end of file.
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								// Add another chunk size to the output buffer.
 | 
				
			||||||
 | 
								// This forces a copy of the whole buffer.
 | 
				
			||||||
 | 
								p_dst_vect->resize(p_dst_vect->size() + gzip_chunk);
 | 
				
			||||||
 | 
								// Get pointer to the actual output buffer.
 | 
				
			||||||
 | 
								dst = p_dst_vect->ptrw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Set the stream to the new output stream.
 | 
				
			||||||
 | 
								// Since it was copied, we need to reset the stream to the new buffer.
 | 
				
			||||||
 | 
								next_out = &(dst[out_mark]);
 | 
				
			||||||
 | 
								avail_out += gzip_chunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ret = BrotliDecoderDecompressStream(state, &avail_in, &next_in, &avail_out, &next_out, &total_out);
 | 
				
			||||||
 | 
								if (ret == BROTLI_DECODER_RESULT_ERROR) {
 | 
				
			||||||
 | 
									WARN_PRINT(BrotliDecoderErrorString(BrotliDecoderGetErrorCode(state)));
 | 
				
			||||||
 | 
									BrotliDecoderDestroyInstance(state);
 | 
				
			||||||
 | 
									p_dst_vect->clear();
 | 
				
			||||||
 | 
									return Z_DATA_ERROR;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								out_mark += gzip_chunk - avail_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Enforce max output size.
 | 
				
			||||||
 | 
								if (p_max_dst_size > -1 && total_out > (uint64_t)p_max_dst_size) {
 | 
				
			||||||
 | 
									BrotliDecoderDestroyInstance(state);
 | 
				
			||||||
 | 
									p_dst_vect->clear();
 | 
				
			||||||
 | 
									return Z_BUF_ERROR;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} while (ret != BROTLI_DECODER_RESULT_SUCCESS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If all done successfully, resize the output if it's larger than the actual output.
 | 
				
			||||||
 | 
							if ((unsigned long)p_dst_vect->size() > total_out) {
 | 
				
			||||||
 | 
								p_dst_vect->resize(total_out);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Clean up and return.
 | 
				
			||||||
 | 
							BrotliDecoderDestroyInstance(state);
 | 
				
			||||||
 | 
							return Z_OK;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							ERR_FAIL_V_MSG(Z_ERRNO, "Godot was compiled without brotli support.");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// This function only supports GZip and Deflate.
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(p_mode != MODE_DEFLATE && p_mode != MODE_GZIP, Z_ERRNO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
							z_stream strm;
 | 
				
			||||||
 | 
							int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize the stream.
 | 
				
			||||||
 | 
							strm.zalloc = Z_NULL;
 | 
				
			||||||
 | 
							strm.zfree = Z_NULL;
 | 
				
			||||||
 | 
							strm.opaque = Z_NULL;
 | 
				
			||||||
 | 
							strm.avail_in = 0;
 | 
				
			||||||
 | 
							strm.next_in = Z_NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int err = inflateInit2(&strm, window_bits);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(err != Z_OK, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Setup the stream inputs.
 | 
				
			||||||
 | 
							strm.next_in = (Bytef *)p_src;
 | 
				
			||||||
 | 
							strm.avail_in = p_src_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Ensure the destination buffer is empty.
 | 
				
			||||||
 | 
							p_dst_vect->clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Decompress until deflate stream ends or end of file.
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								// Add another chunk size to the output buffer.
 | 
				
			||||||
 | 
								// This forces a copy of the whole buffer.
 | 
				
			||||||
 | 
								p_dst_vect->resize(p_dst_vect->size() + gzip_chunk);
 | 
				
			||||||
 | 
								// Get pointer to the actual output buffer.
 | 
				
			||||||
 | 
								dst = p_dst_vect->ptrw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Set the stream to the new output stream.
 | 
				
			||||||
 | 
								// Since it was copied, we need to reset the stream to the new buffer.
 | 
				
			||||||
 | 
								strm.next_out = &(dst[out_mark]);
 | 
				
			||||||
 | 
								strm.avail_out = gzip_chunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Run inflate() on input until output buffer is full and needs to be resized or input runs out.
 | 
				
			||||||
 | 
								do {
 | 
				
			||||||
 | 
									ret = inflate(&strm, Z_SYNC_FLUSH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									switch (ret) {
 | 
				
			||||||
 | 
										case Z_NEED_DICT:
 | 
				
			||||||
 | 
											ret = Z_DATA_ERROR;
 | 
				
			||||||
 | 
											[[fallthrough]];
 | 
				
			||||||
 | 
										case Z_DATA_ERROR:
 | 
				
			||||||
 | 
										case Z_MEM_ERROR:
 | 
				
			||||||
 | 
										case Z_STREAM_ERROR:
 | 
				
			||||||
 | 
										case Z_BUF_ERROR:
 | 
				
			||||||
 | 
											if (strm.msg) {
 | 
				
			||||||
 | 
												WARN_PRINT(strm.msg);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											(void)inflateEnd(&strm);
 | 
				
			||||||
 | 
											p_dst_vect->clear();
 | 
				
			||||||
 | 
											return ret;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} while (strm.avail_out > 0 && strm.avail_in > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								out_mark += gzip_chunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Enforce max output size.
 | 
				
			||||||
 | 
								if (p_max_dst_size > -1 && strm.total_out > (uint64_t)p_max_dst_size) {
 | 
				
			||||||
 | 
									(void)inflateEnd(&strm);
 | 
				
			||||||
 | 
									p_dst_vect->clear();
 | 
				
			||||||
 | 
									return Z_BUF_ERROR;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} while (ret != Z_STREAM_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If all done successfully, resize the output if it's larger than the actual output.
 | 
				
			||||||
 | 
							if ((unsigned long)p_dst_vect->size() > strm.total_out) {
 | 
				
			||||||
 | 
								p_dst_vect->resize(strm.total_out);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Clean up and return.
 | 
				
			||||||
 | 
							(void)inflateEnd(&strm);
 | 
				
			||||||
 | 
							return Z_OK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
 | 
				
			||||||
 | 
					int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
 | 
				
			||||||
 | 
					int Compression::zstd_level = 3;
 | 
				
			||||||
 | 
					bool Compression::zstd_long_distance_matching = false;
 | 
				
			||||||
 | 
					int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
 | 
				
			||||||
 | 
					int Compression::gzip_chunk = 16384;
 | 
				
			||||||
							
								
								
									
										60
									
								
								engine/core/io/compression.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								engine/core/io/compression.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  compression.h                                                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*                         This file is part of:                          */
 | 
				
			||||||
 | 
					/*                             GODOT ENGINE                               */
 | 
				
			||||||
 | 
					/*                        https://godotengine.org                         */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
				
			||||||
 | 
					/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
				
			||||||
 | 
					/* a copy of this software and associated documentation files (the        */
 | 
				
			||||||
 | 
					/* "Software"), to deal in the Software without restriction, including    */
 | 
				
			||||||
 | 
					/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
				
			||||||
 | 
					/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
				
			||||||
 | 
					/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
				
			||||||
 | 
					/* the following conditions:                                              */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* The above copyright notice and this permission notice shall be         */
 | 
				
			||||||
 | 
					/* included in all copies or substantial portions of the Software.        */
 | 
				
			||||||
 | 
					/*                                                                        */
 | 
				
			||||||
 | 
					/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
				
			||||||
 | 
					/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
				
			||||||
 | 
					/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
				
			||||||
 | 
					/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
				
			||||||
 | 
					/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
				
			||||||
 | 
					/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
				
			||||||
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMPRESSION_H
 | 
				
			||||||
 | 
					#define COMPRESSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/templates/vector.h"
 | 
				
			||||||
 | 
					#include "core/typedefs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Compression {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static int zlib_level;
 | 
				
			||||||
 | 
						static int gzip_level;
 | 
				
			||||||
 | 
						static int zstd_level;
 | 
				
			||||||
 | 
						static bool zstd_long_distance_matching;
 | 
				
			||||||
 | 
						static int zstd_window_log_size;
 | 
				
			||||||
 | 
						static int gzip_chunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum Mode {
 | 
				
			||||||
 | 
							MODE_FASTLZ,
 | 
				
			||||||
 | 
							MODE_DEFLATE,
 | 
				
			||||||
 | 
							MODE_ZSTD,
 | 
				
			||||||
 | 
							MODE_GZIP,
 | 
				
			||||||
 | 
							MODE_BROTLI
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
				
			||||||
 | 
						static int get_max_compressed_buffer_size(int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
				
			||||||
 | 
						static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
 | 
				
			||||||
 | 
						static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // COMPRESSION_H
 | 
				
			||||||
							
								
								
									
										350
									
								
								engine/core/io/config_file.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								engine/core/io/config_file.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,350 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  config_file.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 "config_file.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/file_access_encrypted.h"
 | 
				
			||||||
 | 
					#include "core/os/keyboard.h"
 | 
				
			||||||
 | 
					#include "core/string/string_builder.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant_parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray ConfigFile::_get_sections() const {
 | 
				
			||||||
 | 
						List<String> s;
 | 
				
			||||||
 | 
						get_sections(&s);
 | 
				
			||||||
 | 
						PackedStringArray arr;
 | 
				
			||||||
 | 
						arr.resize(s.size());
 | 
				
			||||||
 | 
						int idx = 0;
 | 
				
			||||||
 | 
						for (const String &E : s) {
 | 
				
			||||||
 | 
							arr.set(idx++, E);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray ConfigFile::_get_section_keys(const String &p_section) const {
 | 
				
			||||||
 | 
						List<String> s;
 | 
				
			||||||
 | 
						get_section_keys(p_section, &s);
 | 
				
			||||||
 | 
						PackedStringArray arr;
 | 
				
			||||||
 | 
						arr.resize(s.size());
 | 
				
			||||||
 | 
						int idx = 0;
 | 
				
			||||||
 | 
						for (const String &E : s) {
 | 
				
			||||||
 | 
							arr.set(idx++, E);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return arr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::set_value(const String &p_section, const String &p_key, const Variant &p_value) {
 | 
				
			||||||
 | 
						if (p_value.get_type() == Variant::NIL) { // Erase key.
 | 
				
			||||||
 | 
							if (!values.has(p_section)) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							values[p_section].erase(p_key);
 | 
				
			||||||
 | 
							if (values[p_section].is_empty()) {
 | 
				
			||||||
 | 
								values.erase(p_section);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (!values.has(p_section)) {
 | 
				
			||||||
 | 
								// Insert section-less keys at the beginning.
 | 
				
			||||||
 | 
								values.insert(p_section, HashMap<String, Variant>(), p_section.is_empty());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							values[p_section][p_key] = p_value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Variant ConfigFile::get_value(const String &p_section, const String &p_key, const Variant &p_default) const {
 | 
				
			||||||
 | 
						if (!values.has(p_section) || !values[p_section].has(p_key)) {
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(p_default.get_type() == Variant::NIL, Variant(),
 | 
				
			||||||
 | 
									vformat("Couldn't find the given section \"%s\" and key \"%s\", and no default was given.", p_section, p_key));
 | 
				
			||||||
 | 
							return p_default;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return values[p_section][p_key];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ConfigFile::has_section(const String &p_section) const {
 | 
				
			||||||
 | 
						return values.has(p_section);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ConfigFile::has_section_key(const String &p_section, const String &p_key) const {
 | 
				
			||||||
 | 
						if (!values.has(p_section)) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return values[p_section].has(p_key);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::get_sections(List<String> *r_sections) const {
 | 
				
			||||||
 | 
						for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
 | 
				
			||||||
 | 
							r_sections->push_back(E.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::get_section_keys(const String &p_section, List<String> *r_keys) const {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!values.has(p_section), vformat("Cannot get keys from nonexistent section \"%s\".", p_section));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const KeyValue<String, Variant> &E : values[p_section]) {
 | 
				
			||||||
 | 
							r_keys->push_back(E.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::erase_section(const String &p_section) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!values.has(p_section), vformat("Cannot erase nonexistent section \"%s\".", p_section));
 | 
				
			||||||
 | 
						values.erase(p_section);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::erase_section_key(const String &p_section, const String &p_key) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!values.has(p_section), vformat("Cannot erase key \"%s\" from nonexistent section \"%s\".", p_key, p_section));
 | 
				
			||||||
 | 
						ERR_FAIL_COND_MSG(!values[p_section].has(p_key), vformat("Cannot erase nonexistent key \"%s\" from section \"%s\".", p_key, p_section));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						values[p_section].erase(p_key);
 | 
				
			||||||
 | 
						if (values[p_section].is_empty()) {
 | 
				
			||||||
 | 
							values.erase(p_section);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String ConfigFile::encode_to_text() const {
 | 
				
			||||||
 | 
						StringBuilder sb;
 | 
				
			||||||
 | 
						bool first = true;
 | 
				
			||||||
 | 
						for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
 | 
				
			||||||
 | 
							if (first) {
 | 
				
			||||||
 | 
								first = false;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sb.append("\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!E.key.is_empty()) {
 | 
				
			||||||
 | 
								sb.append("[" + E.key + "]\n\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const KeyValue<String, Variant> &F : E.value) {
 | 
				
			||||||
 | 
								String vstr;
 | 
				
			||||||
 | 
								VariantWriter::write_to_string(F.value, vstr);
 | 
				
			||||||
 | 
								sb.append(F.key.property_name_encode() + "=" + vstr + "\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sb.as_string();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::save(const String &p_path) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return _internal_save(file);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::save_encrypted(const String &p_path, const Vector<uint8_t> &p_key) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
 | 
						fae.instantiate();
 | 
				
			||||||
 | 
						err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_WRITE_AES256);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return _internal_save(fae);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::save_encrypted_pass(const String &p_path, const String &p_pass) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
 | 
						fae.instantiate();
 | 
				
			||||||
 | 
						err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_WRITE_AES256);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return _internal_save(fae);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::_internal_save(Ref<FileAccess> file) {
 | 
				
			||||||
 | 
						bool first = true;
 | 
				
			||||||
 | 
						for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
 | 
				
			||||||
 | 
							if (first) {
 | 
				
			||||||
 | 
								first = false;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								file->store_string("\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!E.key.is_empty()) {
 | 
				
			||||||
 | 
								file->store_string("[" + E.key.replace("]", "\\]") + "]\n\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const KeyValue<String, Variant> &F : E.value) {
 | 
				
			||||||
 | 
								String vstr;
 | 
				
			||||||
 | 
								VariantWriter::write_to_string(F.value, vstr);
 | 
				
			||||||
 | 
								file->store_string(F.key.property_name_encode() + "=" + vstr + "\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::load(const String &p_path) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (f.is_null()) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return _internal_load(p_path, f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::load_encrypted(const String &p_path, const Vector<uint8_t> &p_key) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
 | 
						fae.instantiate();
 | 
				
			||||||
 | 
						err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_READ);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return _internal_load(p_path, fae);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::load_encrypted_pass(const String &p_path, const String &p_pass) {
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<FileAccessEncrypted> fae;
 | 
				
			||||||
 | 
						fae.instantiate();
 | 
				
			||||||
 | 
						err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_READ);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return _internal_load(p_path, fae);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::_internal_load(const String &p_path, Ref<FileAccess> f) {
 | 
				
			||||||
 | 
						VariantParser::StreamFile stream;
 | 
				
			||||||
 | 
						stream.f = f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error err = _parse(p_path, &stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::parse(const String &p_data) {
 | 
				
			||||||
 | 
						VariantParser::StreamString stream;
 | 
				
			||||||
 | 
						stream.s = p_data;
 | 
				
			||||||
 | 
						return _parse("<string>", &stream);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream) {
 | 
				
			||||||
 | 
						String assign;
 | 
				
			||||||
 | 
						Variant value;
 | 
				
			||||||
 | 
						VariantParser::Tag next_tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int lines = 0;
 | 
				
			||||||
 | 
						String error_text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String section;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							assign = Variant();
 | 
				
			||||||
 | 
							next_tag.fields.clear();
 | 
				
			||||||
 | 
							next_tag.name = String();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error err = VariantParser::parse_tag_assign_eof(p_stream, lines, error_text, next_tag, assign, value, nullptr, true);
 | 
				
			||||||
 | 
							if (err == ERR_FILE_EOF) {
 | 
				
			||||||
 | 
								return OK;
 | 
				
			||||||
 | 
							} else if (err != OK) {
 | 
				
			||||||
 | 
								ERR_PRINT(vformat("ConfigFile parse error at %s:%d: %s.", p_path, lines, error_text));
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!assign.is_empty()) {
 | 
				
			||||||
 | 
								set_value(section, assign, value);
 | 
				
			||||||
 | 
							} else if (!next_tag.name.is_empty()) {
 | 
				
			||||||
 | 
								section = next_tag.name.replace("\\]", "]");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::clear() {
 | 
				
			||||||
 | 
						values.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigFile::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("has_section", "section"), &ConfigFile::has_section);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("has_section_key", "section", "key"), &ConfigFile::has_section_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_sections"), &ConfigFile::_get_sections);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_section_keys", "section"), &ConfigFile::_get_section_keys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("erase_section", "section"), &ConfigFile::erase_section);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("erase_section_key", "section", "key"), &ConfigFile::erase_section_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load", "path"), &ConfigFile::load);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("encode_to_text"), &ConfigFile::encode_to_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("load_encrypted_pass", "path", "password"), &ConfigFile::load_encrypted_pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save_encrypted", "path", "key"), &ConfigFile::save_encrypted);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("save_encrypted_pass", "path", "password"), &ConfigFile::save_encrypted_pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("clear"), &ConfigFile::clear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								engine/core/io/config_file.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								engine/core/io/config_file.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,82 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  config_file.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 CONFIG_FILE_H
 | 
				
			||||||
 | 
					#define CONFIG_FILE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					#include "core/templates/hash_map.h"
 | 
				
			||||||
 | 
					#include "core/variant/variant_parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigFile : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(ConfigFile, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HashMap<String, HashMap<String, Variant>> values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PackedStringArray _get_sections() const;
 | 
				
			||||||
 | 
						PackedStringArray _get_section_keys(const String &p_section) const;
 | 
				
			||||||
 | 
						Error _internal_load(const String &p_path, Ref<FileAccess> f);
 | 
				
			||||||
 | 
						Error _internal_save(Ref<FileAccess> file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _parse(const String &p_path, VariantParser::Stream *p_stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_value(const String &p_section, const String &p_key, const Variant &p_value);
 | 
				
			||||||
 | 
						Variant get_value(const String &p_section, const String &p_key, const Variant &p_default = Variant()) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_section(const String &p_section) const;
 | 
				
			||||||
 | 
						bool has_section_key(const String &p_section, const String &p_key) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void get_sections(List<String> *r_sections) const;
 | 
				
			||||||
 | 
						void get_section_keys(const String &p_section, List<String> *r_keys) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void erase_section(const String &p_section);
 | 
				
			||||||
 | 
						void erase_section_key(const String &p_section, const String &p_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error save(const String &p_path);
 | 
				
			||||||
 | 
						Error load(const String &p_path);
 | 
				
			||||||
 | 
						Error parse(const String &p_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String encode_to_text() const; // used by exporter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
 | 
				
			||||||
 | 
						Error load_encrypted_pass(const String &p_path, const String &p_pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error save_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
 | 
				
			||||||
 | 
						Error save_encrypted_pass(const String &p_path, const String &p_pass);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CONFIG_FILE_H
 | 
				
			||||||
							
								
								
									
										600
									
								
								engine/core/io/dir_access.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										600
									
								
								engine/core/io/dir_access.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,600 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  dir_access.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 "dir_access.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/config/project_settings.h"
 | 
				
			||||||
 | 
					#include "core/io/file_access.h"
 | 
				
			||||||
 | 
					#include "core/os/memory.h"
 | 
				
			||||||
 | 
					#include "core/os/os.h"
 | 
				
			||||||
 | 
					#include "core/templates/local_vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					thread_local Error DirAccess::last_dir_open_error = OK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::_get_root_path() const {
 | 
				
			||||||
 | 
						switch (_access_type) {
 | 
				
			||||||
 | 
							case ACCESS_RESOURCES:
 | 
				
			||||||
 | 
								return ProjectSettings::get_singleton()->get_resource_path();
 | 
				
			||||||
 | 
							case ACCESS_USERDATA:
 | 
				
			||||||
 | 
								return OS::get_singleton()->get_user_data_dir();
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::_get_root_string() const {
 | 
				
			||||||
 | 
						switch (_access_type) {
 | 
				
			||||||
 | 
							case ACCESS_RESOURCES:
 | 
				
			||||||
 | 
								return "res://";
 | 
				
			||||||
 | 
							case ACCESS_USERDATA:
 | 
				
			||||||
 | 
								return "user://";
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int DirAccess::get_current_drive() {
 | 
				
			||||||
 | 
						String path = get_current_dir().to_lower();
 | 
				
			||||||
 | 
						for (int i = 0; i < get_drive_count(); i++) {
 | 
				
			||||||
 | 
							String d = get_drive(i).to_lower();
 | 
				
			||||||
 | 
							if (path.begins_with(d)) {
 | 
				
			||||||
 | 
								return i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::drives_are_shortcuts() {
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Error _erase_recursive(DirAccess *da) {
 | 
				
			||||||
 | 
						List<String> dirs;
 | 
				
			||||||
 | 
						List<String> files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						da->list_dir_begin();
 | 
				
			||||||
 | 
						String n = da->get_next();
 | 
				
			||||||
 | 
						while (!n.is_empty()) {
 | 
				
			||||||
 | 
							if (n != "." && n != "..") {
 | 
				
			||||||
 | 
								if (da->current_is_dir() && !da->is_link(n)) {
 | 
				
			||||||
 | 
									dirs.push_back(n);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									files.push_back(n);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							n = da->get_next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						da->list_dir_end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const String &E : dirs) {
 | 
				
			||||||
 | 
							Error err = da->change_dir(E);
 | 
				
			||||||
 | 
							if (err == OK) {
 | 
				
			||||||
 | 
								err = _erase_recursive(da);
 | 
				
			||||||
 | 
								if (err) {
 | 
				
			||||||
 | 
									da->change_dir("..");
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err = da->change_dir("..");
 | 
				
			||||||
 | 
								if (err) {
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err = da->remove(da->get_current_dir().path_join(E));
 | 
				
			||||||
 | 
								if (err) {
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const String &E : files) {
 | 
				
			||||||
 | 
							Error err = da->remove(da->get_current_dir().path_join(E));
 | 
				
			||||||
 | 
							if (err) {
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::erase_contents_recursive() {
 | 
				
			||||||
 | 
						return _erase_recursive(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::make_dir_recursive(const String &p_dir) {
 | 
				
			||||||
 | 
						if (p_dir.length() < 1) {
 | 
				
			||||||
 | 
							return OK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String full_dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p_dir.is_relative_path()) {
 | 
				
			||||||
 | 
							//append current
 | 
				
			||||||
 | 
							full_dir = get_current_dir().path_join(p_dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							full_dir = p_dir;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						full_dir = full_dir.replace("\\", "/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (full_dir.begins_with("res://")) {
 | 
				
			||||||
 | 
							base = "res://";
 | 
				
			||||||
 | 
						} else if (full_dir.begins_with("user://")) {
 | 
				
			||||||
 | 
							base = "user://";
 | 
				
			||||||
 | 
						} else if (full_dir.is_network_share_path()) {
 | 
				
			||||||
 | 
							int pos = full_dir.find("/", 2);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
							pos = full_dir.find("/", pos + 1);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
							base = full_dir.substr(0, pos + 1);
 | 
				
			||||||
 | 
						} else if (full_dir.begins_with("/")) {
 | 
				
			||||||
 | 
							base = "/";
 | 
				
			||||||
 | 
						} else if (full_dir.contains(":/")) {
 | 
				
			||||||
 | 
							base = full_dir.substr(0, full_dir.find(":/") + 2);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ERR_FAIL_V(ERR_INVALID_PARAMETER);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						full_dir = full_dir.replace_first(base, "").simplify_path();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector<String> subdirs = full_dir.split("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String curpath = base;
 | 
				
			||||||
 | 
						for (int i = 0; i < subdirs.size(); i++) {
 | 
				
			||||||
 | 
							curpath = curpath.path_join(subdirs[i]);
 | 
				
			||||||
 | 
							Error err = make_dir(curpath);
 | 
				
			||||||
 | 
							if (err != OK && err != ERR_ALREADY_EXISTS) {
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirAccess::AccessType DirAccess::get_access_type() const {
 | 
				
			||||||
 | 
						return _access_type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::fix_path(const String &p_path) const {
 | 
				
			||||||
 | 
						switch (_access_type) {
 | 
				
			||||||
 | 
							case ACCESS_RESOURCES: {
 | 
				
			||||||
 | 
								if (ProjectSettings::get_singleton()) {
 | 
				
			||||||
 | 
									if (p_path.begins_with("res://")) {
 | 
				
			||||||
 | 
										String resource_path = ProjectSettings::get_singleton()->get_resource_path();
 | 
				
			||||||
 | 
										if (!resource_path.is_empty()) {
 | 
				
			||||||
 | 
											return p_path.replace_first("res:/", resource_path);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return p_path.replace_first("res://", "");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case ACCESS_USERDATA: {
 | 
				
			||||||
 | 
								if (p_path.begins_with("user://")) {
 | 
				
			||||||
 | 
									String data_dir = OS::get_singleton()->get_user_data_dir();
 | 
				
			||||||
 | 
									if (!data_dir.is_empty()) {
 | 
				
			||||||
 | 
										return p_path.replace_first("user:/", data_dir);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return p_path.replace_first("user://", "");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case ACCESS_FILESYSTEM: {
 | 
				
			||||||
 | 
								return p_path;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
							case ACCESS_MAX:
 | 
				
			||||||
 | 
								break; // Can't happen, but silences warning
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return p_path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::create_for_path(const String &p_path) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da;
 | 
				
			||||||
 | 
						if (p_path.begins_with("res://")) {
 | 
				
			||||||
 | 
							da = create(ACCESS_RESOURCES);
 | 
				
			||||||
 | 
						} else if (p_path.begins_with("user://")) {
 | 
				
			||||||
 | 
							da = create(ACCESS_USERDATA);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							da = create(ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = create_for_path(p_path);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'.");
 | 
				
			||||||
 | 
						Error err = da->change_dir(p_path);
 | 
				
			||||||
 | 
						if (r_error) {
 | 
				
			||||||
 | 
							*r_error = err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (err != OK) {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::_open(const String &p_path) {
 | 
				
			||||||
 | 
						Error err = OK;
 | 
				
			||||||
 | 
						Ref<DirAccess> da = open(p_path, &err);
 | 
				
			||||||
 | 
						last_dir_open_error = err;
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							return Ref<DirAccess>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int DirAccess::_get_drive_count() {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
						return d->get_drive_count();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::get_drive_name(int p_idx) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
						return d->get_drive(p_idx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::make_dir_absolute(const String &p_dir) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
 | 
				
			||||||
 | 
						return d->make_dir(p_dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::make_dir_recursive_absolute(const String &p_dir) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
 | 
				
			||||||
 | 
						return d->make_dir_recursive(p_dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::dir_exists_absolute(const String &p_dir) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
 | 
				
			||||||
 | 
						return d->dir_exists(p_dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
						// Support copying from res:// to user:// etc.
 | 
				
			||||||
 | 
						String from = ProjectSettings::get_singleton()->globalize_path(p_from);
 | 
				
			||||||
 | 
						String to = ProjectSettings::get_singleton()->globalize_path(p_to);
 | 
				
			||||||
 | 
						return d->copy(from, to, p_chmod_flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::rename_absolute(const String &p_from, const String &p_to) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
						String from = ProjectSettings::get_singleton()->globalize_path(p_from);
 | 
				
			||||||
 | 
						String to = ProjectSettings::get_singleton()->globalize_path(p_to);
 | 
				
			||||||
 | 
						return d->rename(from, to);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::remove_absolute(const String &p_path) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create_for_path(p_path);
 | 
				
			||||||
 | 
						return d->remove(p_path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ref<DirAccess> DirAccess::create(AccessType p_access) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
 | 
				
			||||||
 | 
						if (da.is_valid()) {
 | 
				
			||||||
 | 
							da->_access_type = p_access;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// for ACCESS_RESOURCES and ACCESS_FILESYSTEM, current_dir already defaults to where game was started
 | 
				
			||||||
 | 
							// in case current directory is force changed elsewhere for ACCESS_RESOURCES
 | 
				
			||||||
 | 
							if (p_access == ACCESS_RESOURCES) {
 | 
				
			||||||
 | 
								da->change_dir("res://");
 | 
				
			||||||
 | 
							} else if (p_access == ACCESS_USERDATA) {
 | 
				
			||||||
 | 
								da->change_dir("user://");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::get_open_error() {
 | 
				
			||||||
 | 
						return last_dir_open_error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
 | 
				
			||||||
 | 
						Ref<DirAccess> d = DirAccess::create(p_access);
 | 
				
			||||||
 | 
						if (d.is_null()) {
 | 
				
			||||||
 | 
							return p_path;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d->change_dir(p_path);
 | 
				
			||||||
 | 
						String full = d->get_current_dir();
 | 
				
			||||||
 | 
						return full;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::copy(const String &p_from, const String &p_to, int p_chmod_flags) {
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(p_from == p_to, ERR_INVALID_PARAMETER, "Source and destination path are equal.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data());
 | 
				
			||||||
 | 
						Error err;
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const size_t copy_buffer_limit = 65536; // 64 KB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fsrc->seek_end(0);
 | 
				
			||||||
 | 
							uint64_t size = fsrc->get_position();
 | 
				
			||||||
 | 
							fsrc->seek(0);
 | 
				
			||||||
 | 
							err = OK;
 | 
				
			||||||
 | 
							size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit);
 | 
				
			||||||
 | 
							LocalVector<uint8_t> buffer;
 | 
				
			||||||
 | 
							buffer.resize(buffer_size);
 | 
				
			||||||
 | 
							while (size > 0) {
 | 
				
			||||||
 | 
								if (fsrc->get_error() != OK) {
 | 
				
			||||||
 | 
									err = fsrc->get_error();
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (fdst->get_error() != OK) {
 | 
				
			||||||
 | 
									err = fdst->get_error();
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int bytes_read = fsrc->get_buffer(buffer.ptr(), buffer_size);
 | 
				
			||||||
 | 
								if (bytes_read <= 0) {
 | 
				
			||||||
 | 
									err = FAILED;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								fdst->store_buffer(buffer.ptr(), bytes_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size -= bytes_read;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err == OK && p_chmod_flags != -1) {
 | 
				
			||||||
 | 
							err = FileAccess::set_unix_permissions(p_to, p_chmod_flags);
 | 
				
			||||||
 | 
							// If running on a platform with no chmod support (i.e., Windows), don't fail
 | 
				
			||||||
 | 
							if (err == ERR_UNAVAILABLE) {
 | 
				
			||||||
 | 
								err = OK;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Changes dir for the current scope, returning back to the original dir
 | 
				
			||||||
 | 
					// when scope exits
 | 
				
			||||||
 | 
					class DirChanger {
 | 
				
			||||||
 | 
						DirAccess *da;
 | 
				
			||||||
 | 
						String original_dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						DirChanger(DirAccess *p_da, const String &p_dir) :
 | 
				
			||||||
 | 
								da(p_da),
 | 
				
			||||||
 | 
								original_dir(p_da->get_current_dir()) {
 | 
				
			||||||
 | 
							p_da->change_dir(p_dir);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~DirChanger() {
 | 
				
			||||||
 | 
							da->change_dir(original_dir);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, const String &p_to, int p_chmod_flags, bool p_copy_links) {
 | 
				
			||||||
 | 
						List<String> dirs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String curdir = get_current_dir();
 | 
				
			||||||
 | 
						list_dir_begin();
 | 
				
			||||||
 | 
						String n = get_next();
 | 
				
			||||||
 | 
						while (!n.is_empty()) {
 | 
				
			||||||
 | 
							if (n != "." && n != "..") {
 | 
				
			||||||
 | 
								if (p_copy_links && is_link(get_current_dir().path_join(n))) {
 | 
				
			||||||
 | 
									create_link(read_link(get_current_dir().path_join(n)), p_to + n);
 | 
				
			||||||
 | 
								} else if (current_is_dir()) {
 | 
				
			||||||
 | 
									dirs.push_back(n);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									const String &rel_path = n;
 | 
				
			||||||
 | 
									if (!n.is_relative_path()) {
 | 
				
			||||||
 | 
										list_dir_end();
 | 
				
			||||||
 | 
										return ERR_BUG;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									Error err = copy(get_current_dir().path_join(n), p_to + rel_path, p_chmod_flags);
 | 
				
			||||||
 | 
									if (err) {
 | 
				
			||||||
 | 
										list_dir_end();
 | 
				
			||||||
 | 
										return err;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							n = get_next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_dir_end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (const String &rel_path : dirs) {
 | 
				
			||||||
 | 
							String target_dir = p_to + rel_path;
 | 
				
			||||||
 | 
							if (!p_target_da->dir_exists(target_dir)) {
 | 
				
			||||||
 | 
								Error err = p_target_da->make_dir(target_dir);
 | 
				
			||||||
 | 
								ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + target_dir + "'.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Error err = change_dir(rel_path);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + rel_path + "'.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
 | 
				
			||||||
 | 
							if (err) {
 | 
				
			||||||
 | 
								change_dir("..");
 | 
				
			||||||
 | 
								ERR_FAIL_V_MSG(err, "Failed to copy recursively.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = change_dir("..");
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to go back.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Error DirAccess::copy_dir(const String &p_from, String p_to, int p_chmod_flags, bool p_copy_links) {
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!target_da->dir_exists(p_to)) {
 | 
				
			||||||
 | 
							Error err = target_da->make_dir_recursive(p_to);
 | 
				
			||||||
 | 
							ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p_to.ends_with("/")) {
 | 
				
			||||||
 | 
							p_to = p_to + "/";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DirChanger dir_changer(this, p_from);
 | 
				
			||||||
 | 
						Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::exists(const String &p_dir) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
 | 
				
			||||||
 | 
						return da->change_dir(p_dir) == OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray DirAccess::get_files() {
 | 
				
			||||||
 | 
						return _get_contents(false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray DirAccess::get_files_at(const String &p_path) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = DirAccess::open(p_path);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
 | 
				
			||||||
 | 
						return da->get_files();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray DirAccess::get_directories() {
 | 
				
			||||||
 | 
						return _get_contents(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray DirAccess::get_directories_at(const String &p_path) {
 | 
				
			||||||
 | 
						Ref<DirAccess> da = DirAccess::open(p_path);
 | 
				
			||||||
 | 
						ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
 | 
				
			||||||
 | 
						return da->get_directories();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PackedStringArray DirAccess::_get_contents(bool p_directories) {
 | 
				
			||||||
 | 
						PackedStringArray ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_dir_begin();
 | 
				
			||||||
 | 
						String s = _get_next();
 | 
				
			||||||
 | 
						while (!s.is_empty()) {
 | 
				
			||||||
 | 
							if (current_is_dir() == p_directories) {
 | 
				
			||||||
 | 
								ret.append(s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							s = _get_next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret.sort();
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String DirAccess::_get_next() {
 | 
				
			||||||
 | 
						String next = get_next();
 | 
				
			||||||
 | 
						while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) {
 | 
				
			||||||
 | 
							next = get_next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return next;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DirAccess::set_include_navigational(bool p_enable) {
 | 
				
			||||||
 | 
						include_navigational = p_enable;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::get_include_navigational() const {
 | 
				
			||||||
 | 
						return include_navigational;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DirAccess::set_include_hidden(bool p_enable) {
 | 
				
			||||||
 | 
						include_hidden = p_enable;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::get_include_hidden() const {
 | 
				
			||||||
 | 
						return include_hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DirAccess::is_case_sensitive(const String &p_path) const {
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DirAccess::_bind_methods() {
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
 | 
				
			||||||
 | 
						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("list_dir_end"), &DirAccess::list_dir_end);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_files_at", "path"), &DirAccess::get_files_at);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_absolute", "path"), &DirAccess::make_dir_absolute);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_recursive_absolute", "path"), &DirAccess::make_dir_recursive_absolute);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("dir_exists_absolute", "path"), &DirAccess::dir_exists_absolute);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1));
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("copy_absolute", "from", "to", "chmod_flags"), &DirAccess::copy_absolute, DEFVAL(-1));
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("rename_absolute", "from", "to"), &DirAccess::rename_absolute);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
 | 
				
			||||||
 | 
						ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_link", "path"), &DirAccess::is_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("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("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										168
									
								
								engine/core/io/dir_access.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								engine/core/io/dir_access.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,168 @@
 | 
				
			||||||
 | 
					/**************************************************************************/
 | 
				
			||||||
 | 
					/*  dir_access.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 DIR_ACCESS_H
 | 
				
			||||||
 | 
					#define DIR_ACCESS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/object/ref_counted.h"
 | 
				
			||||||
 | 
					#include "core/string/ustring.h"
 | 
				
			||||||
 | 
					#include "core/typedefs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
 | 
				
			||||||
 | 
					class DirAccess : public RefCounted {
 | 
				
			||||||
 | 
						GDCLASS(DirAccess, RefCounted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum AccessType {
 | 
				
			||||||
 | 
							ACCESS_RESOURCES,
 | 
				
			||||||
 | 
							ACCESS_USERDATA,
 | 
				
			||||||
 | 
							ACCESS_FILESYSTEM,
 | 
				
			||||||
 | 
							ACCESS_MAX
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef Ref<DirAccess> (*CreateFunc)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						AccessType _access_type = ACCESS_FILESYSTEM;
 | 
				
			||||||
 | 
						static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
 | 
				
			||||||
 | 
						static Ref<DirAccess> _open(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error _copy_dir(Ref<DirAccess> &p_target_da, const String &p_to, int p_chmod_flags, bool p_copy_links);
 | 
				
			||||||
 | 
						PackedStringArray _get_contents(bool p_directories);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						thread_local static Error last_dir_open_error;
 | 
				
			||||||
 | 
						bool include_navigational = false;
 | 
				
			||||||
 | 
						bool include_hidden = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						static void _bind_methods();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String _get_root_path() const;
 | 
				
			||||||
 | 
						virtual String _get_root_string() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AccessType get_access_type() const;
 | 
				
			||||||
 | 
						virtual String fix_path(const String &p_path) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename T>
 | 
				
			||||||
 | 
						static Ref<DirAccess> _create_builtin() {
 | 
				
			||||||
 | 
							return memnew(T);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual Error list_dir_begin() = 0; ///< This starts dir listing
 | 
				
			||||||
 | 
						virtual String get_next() = 0;
 | 
				
			||||||
 | 
						virtual bool current_is_dir() const = 0;
 | 
				
			||||||
 | 
						virtual bool current_is_hidden() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void list_dir_end() = 0; ///<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual int get_drive_count() = 0;
 | 
				
			||||||
 | 
						virtual String get_drive(int p_drive) = 0;
 | 
				
			||||||
 | 
						virtual int get_current_drive();
 | 
				
			||||||
 | 
						virtual bool drives_are_shortcuts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Error change_dir(String p_dir) = 0; ///< can be relative or absolute, return false on success
 | 
				
			||||||
 | 
						virtual String get_current_dir(bool p_include_drive = true) const = 0; ///< return current dir location
 | 
				
			||||||
 | 
						virtual Error make_dir(String p_dir) = 0;
 | 
				
			||||||
 | 
						virtual Error make_dir_recursive(const String &p_dir);
 | 
				
			||||||
 | 
						virtual Error erase_contents_recursive(); //super dangerous, use with care!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool file_exists(String p_file) = 0;
 | 
				
			||||||
 | 
						virtual bool dir_exists(String p_dir) = 0;
 | 
				
			||||||
 | 
						virtual bool is_readable(String p_dir) { return true; };
 | 
				
			||||||
 | 
						virtual bool is_writable(String p_dir) { return true; };
 | 
				
			||||||
 | 
						static bool exists(const String &p_dir);
 | 
				
			||||||
 | 
						virtual uint64_t get_space_left() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Error copy_dir(const String &p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false);
 | 
				
			||||||
 | 
						virtual Error copy(const String &p_from, const String &p_to, int p_chmod_flags = -1);
 | 
				
			||||||
 | 
						virtual Error rename(String p_from, String p_to) = 0;
 | 
				
			||||||
 | 
						virtual Error remove(String p_name) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_link(String p_file) = 0;
 | 
				
			||||||
 | 
						virtual String read_link(String p_file) = 0;
 | 
				
			||||||
 | 
						virtual Error create_link(String p_source, String p_target) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Meant for editor code when we want to quickly remove a file without custom
 | 
				
			||||||
 | 
						// handling (e.g. removing a cache file).
 | 
				
			||||||
 | 
						static void remove_file_or_error(const String &p_path) {
 | 
				
			||||||
 | 
							Ref<DirAccess> da = create(ACCESS_FILESYSTEM);
 | 
				
			||||||
 | 
							if (da->file_exists(p_path)) {
 | 
				
			||||||
 | 
								if (da->remove(p_path) != OK) {
 | 
				
			||||||
 | 
									ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual String get_filesystem_type() const = 0;
 | 
				
			||||||
 | 
						static String get_full_path(const String &p_path, AccessType p_access);
 | 
				
			||||||
 | 
						static Ref<DirAccess> create_for_path(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<DirAccess> create(AccessType p_access);
 | 
				
			||||||
 | 
						static Error get_open_error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename T>
 | 
				
			||||||
 | 
						static void make_default(AccessType p_access) {
 | 
				
			||||||
 | 
							create_func[p_access] = _create_builtin<T>;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static int _get_drive_count();
 | 
				
			||||||
 | 
						static String get_drive_name(int p_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Error make_dir_absolute(const String &p_dir);
 | 
				
			||||||
 | 
						static Error make_dir_recursive_absolute(const String &p_dir);
 | 
				
			||||||
 | 
						static bool dir_exists_absolute(const String &p_dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Error copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags = -1);
 | 
				
			||||||
 | 
						static Error rename_absolute(const String &p_from, const String &p_to);
 | 
				
			||||||
 | 
						static Error remove_absolute(const String &p_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PackedStringArray get_files();
 | 
				
			||||||
 | 
						static PackedStringArray get_files_at(const String &p_path);
 | 
				
			||||||
 | 
						PackedStringArray get_directories();
 | 
				
			||||||
 | 
						static PackedStringArray get_directories_at(const String &p_path);
 | 
				
			||||||
 | 
						String _get_next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_include_navigational(bool p_enable);
 | 
				
			||||||
 | 
						bool get_include_navigational() const;
 | 
				
			||||||
 | 
						void set_include_hidden(bool p_enable);
 | 
				
			||||||
 | 
						bool get_include_hidden() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual bool is_case_sensitive(const String &p_path) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DirAccess() {}
 | 
				
			||||||
 | 
						virtual ~DirAccess() {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DIR_ACCESS_H
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue