forked from hertog/godot-module-template
Compare commits
10 commits
developmen
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d7050a065 | ||
![]() |
49689745db | ||
![]() |
0e78ce5031 | ||
![]() |
31c715db98 | ||
![]() |
202693b275 | ||
![]() |
58690660c4 | ||
|
f0fc98b2b8 | ||
![]() |
c420f4b4a8 | ||
![]() |
c33d2130cc | ||
|
dfb5e645cd |
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -7,3 +7,8 @@ config.log
|
|||
.sconf_temp
|
||||
|
||||
engine/.github
|
||||
project/.godot
|
||||
build/PROJECT.pck
|
||||
build/PROJECT.x86_64
|
||||
build/PROJECT.exe
|
||||
build.zip
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "engine"]
|
||||
path = engine
|
||||
url = https://github.com/godotengine/godot.git
|
1
engine
Submodule
1
engine
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 215acd52e82f4c575abb715e25e54558deeef998
|
|
@ -1,238 +0,0 @@
|
|||
# Commented out parameters are those with the same value as base LLVM style.
|
||||
# We can uncomment them if we want to change their value, or enforce the
|
||||
# chosen value in case the base style changes (last sync: Clang 17.0.6).
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
# AlignArrayOfStructures: None
|
||||
# AlignConsecutiveAssignments:
|
||||
# Enabled: false
|
||||
# AcrossEmptyLines: false
|
||||
# AcrossComments: false
|
||||
# AlignCompound: false
|
||||
# PadOperators: true
|
||||
# AlignConsecutiveBitFields:
|
||||
# Enabled: false
|
||||
# AcrossEmptyLines: false
|
||||
# AcrossComments: false
|
||||
# AlignCompound: false
|
||||
# PadOperators: false
|
||||
# AlignConsecutiveDeclarations:
|
||||
# Enabled: false
|
||||
# AcrossEmptyLines: false
|
||||
# AcrossComments: false
|
||||
# AlignCompound: false
|
||||
# PadOperators: false
|
||||
# AlignConsecutiveMacros:
|
||||
# Enabled: false
|
||||
# AcrossEmptyLines: false
|
||||
# AcrossComments: false
|
||||
# AlignCompound: false
|
||||
# PadOperators: false
|
||||
# AlignConsecutiveShortCaseStatements:
|
||||
# Enabled: false
|
||||
# AcrossEmptyLines: false
|
||||
# AcrossComments: false
|
||||
# AlignCaseColons: false
|
||||
# AlignEscapedNewlines: Right
|
||||
AlignOperands: DontAlign
|
||||
AlignTrailingComments:
|
||||
Kind: Never
|
||||
OverEmptyLines: 0
|
||||
# AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# AllowShortBlocksOnASingleLine: Never
|
||||
# AllowShortCaseLabelsOnASingleLine: false
|
||||
# AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
# AllowShortIfStatementsOnASingleLine: Never
|
||||
# AllowShortLambdasOnASingleLine: All
|
||||
# AllowShortLoopsOnASingleLine: false
|
||||
# AlwaysBreakAfterDefinitionReturnType: None
|
||||
# AlwaysBreakAfterReturnType: None
|
||||
# AlwaysBreakBeforeMultilineStrings: false
|
||||
# AlwaysBreakTemplateDeclarations: MultiLine
|
||||
# AttributeMacros:
|
||||
# - __capability
|
||||
# BinPackArguments: true
|
||||
# BinPackParameters: true
|
||||
# BitFieldColonSpacing: Both
|
||||
# BraceWrapping:
|
||||
# AfterCaseLabel: false
|
||||
# AfterClass: false
|
||||
# AfterControlStatement: Never
|
||||
# AfterEnum: false
|
||||
# AfterFunction: false
|
||||
# AfterNamespace: false
|
||||
# AfterObjCDeclaration: false
|
||||
# AfterStruct: false
|
||||
# AfterUnion: false
|
||||
# AfterExternBlock: false
|
||||
# BeforeCatch: false
|
||||
# BeforeElse: false
|
||||
# BeforeLambdaBody: false
|
||||
# BeforeWhile: false
|
||||
# IndentBraces: false
|
||||
# SplitEmptyFunction: true
|
||||
# SplitEmptyRecord: true
|
||||
# SplitEmptyNamespace: true
|
||||
# BreakAfterAttributes: Never
|
||||
# BreakAfterJavaFieldAnnotations: false
|
||||
# BreakArrays: true
|
||||
# BreakBeforeBinaryOperators: None
|
||||
# BreakBeforeBraces: Attach
|
||||
# BreakBeforeConceptDeclarations: Always
|
||||
# BreakBeforeInlineASMColon: OnlyMultiline
|
||||
# BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
# BreakInheritanceList: BeforeColon
|
||||
# BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
# CommentPragmas: "^ IWYU pragma:"
|
||||
# CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
# DerivePointerAlignment: false
|
||||
# DisableFormat: false
|
||||
# EmptyLineAfterAccessModifier: Never
|
||||
# EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
# ExperimentalAutoDetectBinPacking: false
|
||||
# FixNamespaceComments: true
|
||||
# ForEachMacros:
|
||||
# - foreach
|
||||
# - Q_FOREACH
|
||||
# - BOOST_FOREACH
|
||||
# IfMacros:
|
||||
# - KJ_IF_MAYBE
|
||||
# IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: ^".*"$
|
||||
Priority: 1
|
||||
- Regex: ^<.*\.h>$
|
||||
Priority: 2
|
||||
- Regex: ^<.*>$
|
||||
Priority: 3
|
||||
# IncludeIsMainRegex: (Test)?$
|
||||
# IncludeIsMainSourceRegex: ""
|
||||
# IndentAccessModifiers: false
|
||||
# IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
# IndentExternBlock: AfterExternBlock
|
||||
# IndentGotoLabels: true
|
||||
# IndentPPDirectives: None
|
||||
# IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
# IndentWrappedFunctionNames: false
|
||||
InsertBraces: true
|
||||
# InsertNewlineAtEOF: false
|
||||
# InsertTrailingCommas: None
|
||||
# IntegerLiteralSeparator:
|
||||
# Binary: 0
|
||||
# BinaryMinDigits: 0
|
||||
# Decimal: 0
|
||||
# DecimalMinDigits: 0
|
||||
# Hex: 0
|
||||
# HexMinDigits: 0
|
||||
JavaImportGroups:
|
||||
- org.godotengine
|
||||
- android
|
||||
- androidx
|
||||
- com.android
|
||||
- com.google
|
||||
- java
|
||||
- javax
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
# KeepEmptyLinesAtEOF: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# LambdaBodyIndentation: Signature
|
||||
# Language: Cpp
|
||||
# LineEnding: DeriveLF
|
||||
# MacroBlockBegin: ""
|
||||
# MacroBlockEnd: ""
|
||||
# MaxEmptyLinesToKeep: 1
|
||||
# NamespaceIndentation: None
|
||||
# ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
# ObjCBreakBeforeNestedBlockParam: true
|
||||
# ObjCSpaceAfterProperty: false
|
||||
# ObjCSpaceBeforeProtocolList: true
|
||||
# PPIndentWidth: -1
|
||||
PackConstructorInitializers: NextLine
|
||||
# PenaltyBreakAssignment: 2
|
||||
# PenaltyBreakBeforeFirstCallParameter: 19
|
||||
# PenaltyBreakComment: 300
|
||||
# PenaltyBreakFirstLessLess: 120
|
||||
# PenaltyBreakOpenParenthesis: 0
|
||||
# PenaltyBreakString: 1000
|
||||
# PenaltyBreakTemplateDeclaration: 10
|
||||
# PenaltyExcessCharacter: 1000000
|
||||
# PenaltyIndentedWhitespace: 0
|
||||
# PenaltyReturnTypeOnItsOwnLine: 60
|
||||
# PointerAlignment: Right
|
||||
# QualifierAlignment: Leave
|
||||
# ReferenceAlignment: Pointer
|
||||
# ReflowComments: true
|
||||
# RemoveBracesLLVM: false
|
||||
# RemoveParentheses: Leave
|
||||
RemoveSemicolon: true
|
||||
# RequiresClausePosition: OwnLine
|
||||
# RequiresExpressionIndentation: OuterScope
|
||||
# SeparateDefinitionBlocks: Leave
|
||||
# ShortNamespaceLines: 1
|
||||
# SortIncludes: CaseSensitive
|
||||
# SortJavaStaticImport: Before
|
||||
# SortUsingDeclarations: LexicographicNumeric
|
||||
# SpaceAfterCStyleCast: false
|
||||
# SpaceAfterLogicalNot: false
|
||||
# SpaceAfterTemplateKeyword: true
|
||||
# SpaceAroundPointerQualifiers: Default
|
||||
# SpaceBeforeAssignmentOperators: true
|
||||
# SpaceBeforeCaseColon: false
|
||||
# SpaceBeforeCpp11BracedList: false
|
||||
# SpaceBeforeCtorInitializerColon: true
|
||||
# SpaceBeforeInheritanceColon: true
|
||||
# SpaceBeforeJsonColon: false
|
||||
# SpaceBeforeParens: ControlStatements
|
||||
# SpaceBeforeParensOptions:
|
||||
# AfterControlStatements: true
|
||||
# AfterForeachMacros: true
|
||||
# AfterFunctionDeclarationName: false
|
||||
# AfterFunctionDefinitionName: false
|
||||
# AfterIfMacros: true
|
||||
# AfterOverloadedOperator: false
|
||||
# AfterRequiresInClause: false
|
||||
# AfterRequiresInExpression: false
|
||||
# BeforeNonEmptyParentheses: false
|
||||
# SpaceBeforeRangeBasedForLoopColon: true
|
||||
# SpaceBeforeSquareBrackets: false
|
||||
# SpaceInEmptyBlock: false
|
||||
# SpacesBeforeTrailingComments: 1
|
||||
# SpacesInAngles: Never
|
||||
# SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code.
|
||||
Maximum: -1
|
||||
# SpacesInParens: Never
|
||||
# SpacesInParensOptions:
|
||||
# InConditionalStatements: false
|
||||
# InCStyleCasts: false
|
||||
# InEmptyParentheses: false
|
||||
# Other: false
|
||||
# SpacesInSquareBrackets: false
|
||||
Standard: c++20
|
||||
# StatementAttributeLikeMacros:
|
||||
# - Q_EMIT
|
||||
# StatementMacros:
|
||||
# - Q_UNUSED
|
||||
# - QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
# VerilogBreakBetweenInstancePorts: true
|
||||
# WhitespaceSensitiveMacros:
|
||||
# - BOOST_PP_STRINGIZE
|
||||
# - CF_SWIFT_NAME
|
||||
# - NS_SWIFT_NAME
|
||||
# - PP_STRINGIZE
|
||||
# - STRINGIZE
|
|
@ -1,19 +0,0 @@
|
|||
Checks:
|
||||
- -*
|
||||
- cppcoreguidelines-pro-type-member-init
|
||||
- modernize-redundant-void-arg
|
||||
- modernize-use-bool-literals
|
||||
- modernize-use-default-member-init
|
||||
- modernize-use-nullptr
|
||||
- readability-braces-around-statements
|
||||
- readability-redundant-member-init
|
||||
HeaderFileExtensions: ["", h, hh, hpp, hxx, inc, glsl]
|
||||
ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java]
|
||||
HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/
|
||||
FormatStyle: file
|
||||
CheckOptions:
|
||||
cppcoreguidelines-pro-type-member-init.IgnoreArrays: true
|
||||
cppcoreguidelines-pro-type-member-init.UseAssignment: true
|
||||
modernize-use-bool-literals.IgnoreMacros: false
|
||||
modernize-use-default-member-init.IgnoreMacros: false
|
||||
modernize-use-default-member-init.UseAssignment: true
|
|
@ -1,31 +0,0 @@
|
|||
# https://clangd.llvm.org/config
|
||||
---
|
||||
# Default conditions, apply everywhere.
|
||||
|
||||
Diagnostics:
|
||||
Includes:
|
||||
IgnoreHeader:
|
||||
- core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere.
|
||||
- \.compat\.inc
|
||||
---
|
||||
# Header-specific conditions.
|
||||
|
||||
If:
|
||||
PathMatch: .*\.(h|hh|hpp|hxx|inc)
|
||||
|
||||
# Exclude certain, noisy warnings that lack full context. Replace with lowered severity if/when
|
||||
# clangd gets diagnostic severity support. (See: https://github.com/clangd/clangd/issues/1937)
|
||||
CompileFlags:
|
||||
Add:
|
||||
- -Wno-unneeded-internal-declaration
|
||||
- -Wno-unused-const-variable
|
||||
- -Wno-unused-function
|
||||
- -Wno-unused-variable
|
||||
---
|
||||
# Suppress all third-party warnings.
|
||||
|
||||
If:
|
||||
PathMatch: thirdparty/.*
|
||||
|
||||
Diagnostics:
|
||||
Suppress: "*"
|
|
@ -1,20 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.py,SConstruct,SCsub}]
|
||||
indent_style = space
|
||||
|
||||
[{*.{yml,yaml},.clang{-format,-tidy,d}}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.svg]
|
||||
insert_final_newline = false
|
|
@ -1,68 +0,0 @@
|
|||
# This file contains a list of Git commit hashes that should be hidden from the
|
||||
# regular Git history. Typically, this includes commits involving mass auto-formatting
|
||||
# or other normalizations. Commit hashes *must* use the full 40-character notation.
|
||||
# To apply the ignore list in your local Git client, you must run:
|
||||
#
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
#
|
||||
# This file is automatically used by GitHub.com's blame view.
|
||||
|
||||
# A Whole New World (clang-format edition)
|
||||
5dbf1809c6e3e905b94b8764e99491e608122261
|
||||
|
||||
# Style: clang-format: Disable KeepEmptyLinesAtTheStartOfBlocks
|
||||
0be6d925dc3c6413bce7a3ccb49631b8e4a6e67a
|
||||
|
||||
# Style: clang-format: Disable AllowShortIfStatementsOnASingleLine
|
||||
e956e80c1fa1cc8aefcb1533e5acf5cf3c8ffdd9
|
||||
|
||||
# One Copyright Update to rule them all
|
||||
d95794ec8a7c362b06a9cf080e2554ef77adb667
|
||||
|
||||
# Update copyright statements to 2022
|
||||
fe52458154c64fb1b741df4f7bd10106395f7cbd
|
||||
|
||||
# Update copyright statements to 2021
|
||||
b5334d14f7a471f94bcbd64d5bae2ad853d0b7f1
|
||||
|
||||
# Update copyright statements to 2020
|
||||
a7f49ac9a107820a62677ee3fb49d38982a25165
|
||||
|
||||
# Update copyright statements to 2019
|
||||
b16c309f82c77d606472c3c721a1857e323a09e7
|
||||
|
||||
# Update copyright statements to 2018
|
||||
b50a9114b105dafafdda8248a38653bca314a6f3
|
||||
|
||||
# Welcome in 2017, dear changelog reader!
|
||||
c7bc44d5ad9aae4902280012f7654e2318cd910e
|
||||
|
||||
# Update copyright to 2016 in headers
|
||||
5be9ff7b6715a661e85f99b108f96340de7ef435
|
||||
|
||||
# Updated copyright year in all headers
|
||||
fdaa2920eb21fff3320a17e9239e04dfadecdb00
|
||||
|
||||
# Add missing copyright headers and fix formatting
|
||||
e4213e66b2dd8f5a87d8cf5015ac83ba3143279d
|
||||
|
||||
# Use HTTPS URL for Godot's website in the headers
|
||||
bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
|
||||
|
||||
# Add "Godot Engine contributors" copyright line
|
||||
df61dc4b2bd54a5a40c515493c76f5a458e5b541
|
||||
|
||||
# Enforce template syntax `typename` over `class`
|
||||
9903e6779b70fc03aae70a37b9cf053f4f355b91
|
||||
|
||||
# Style: Apply new `clang-format` fixes
|
||||
b37fc1014abf7adda70dc30b0822d775b3a4433f
|
||||
|
||||
# Set clang-format `RemoveSemicolon` rule to `true`
|
||||
0d350e71086fffce0553811739aae9f6ad66136c
|
||||
|
||||
# Style: Apply clang-tidy fixes (superficial)
|
||||
bb5f390fb9b466be35a5df7651323d7e66afca31
|
||||
|
||||
# Style: Enforce `AllowShortFunctionsOnASingleLine`
|
||||
e06d83860d798b6766b23d6eae48557387a7db85
|
23
engine/.gitattributes
vendored
23
engine/.gitattributes
vendored
|
@ -1,23 +0,0 @@
|
|||
# Properly detect languages on Github
|
||||
*.h linguist-language=C++
|
||||
*.inc linguist-language=C++
|
||||
thirdparty/* linguist-vendored
|
||||
|
||||
# Normalize EOL for all files that Git considers text files
|
||||
* text=auto eol=lf
|
||||
# Except for Windows-only / Visual Studio files
|
||||
*.bat eol=crlf
|
||||
*.sln eol=crlf
|
||||
*.csproj eol=crlf
|
||||
misc/msvs/*.template eol=crlf
|
||||
# And some test files where the EOL matters
|
||||
*.test.txt -text
|
||||
|
||||
# The above only works properly for Git 2.10+, so for older versions
|
||||
# we need to manually list the binary files we don't want modified.
|
||||
*.icns binary
|
||||
*.ico binary
|
||||
*.jar binary
|
||||
*.png binary
|
||||
*.ttf binary
|
||||
*.tza binary
|
383
engine/.gitignore
vendored
383
engine/.gitignore
vendored
|
@ -1,383 +0,0 @@
|
|||
# Godot .gitignore config
|
||||
#
|
||||
# Aims to encompass the most commonly found files that we don't want committed
|
||||
# to Git, such as compilation output, IDE specific files, etc.
|
||||
#
|
||||
# It doesn't cover *all* thirdparty IDE extensions under the sun so if you have
|
||||
# specific needs covered here, you can add them to:
|
||||
# .git/info/exclude
|
||||
#
|
||||
# Or contribute them to this file if they're common enough that a good number of
|
||||
# users would benefit from the shared rules.
|
||||
#
|
||||
# This file is organized by sections, with subsections ordered alphabetically.
|
||||
# - Build configuration
|
||||
# - Godot generated files
|
||||
# - General build output
|
||||
# - IDE and tool specific
|
||||
# - Visual Studio specific
|
||||
# - OS specific
|
||||
|
||||
###########################
|
||||
### Build configuration ###
|
||||
###########################
|
||||
|
||||
/custom.py
|
||||
misc/hooks/pre-commit-custom-*
|
||||
|
||||
#############################
|
||||
### Godot generated files ###
|
||||
#############################
|
||||
|
||||
# Buildsystem
|
||||
bin
|
||||
*.gen.*
|
||||
compile_commands.json
|
||||
platform/windows/godot_res.res
|
||||
|
||||
# Ninja build files
|
||||
*.ninja
|
||||
.ninja/
|
||||
run_ninja_env.bat
|
||||
|
||||
# Generated by Godot binary
|
||||
.import/
|
||||
/gdextension_interface.h
|
||||
extension_api.json
|
||||
logs/
|
||||
|
||||
# Generated by unit tests
|
||||
tests/data/*.translation
|
||||
tests/data/crypto/out*
|
||||
|
||||
############################
|
||||
### General build output ###
|
||||
############################
|
||||
|
||||
# C/C++ generated
|
||||
*.a
|
||||
*.ax
|
||||
*.d
|
||||
*.dll
|
||||
*.lib
|
||||
*.lo
|
||||
*.o
|
||||
*.os
|
||||
*.ox
|
||||
*.Plo
|
||||
*.so
|
||||
# Binutils tmp linker output of the form "stXXXXXX" where "X" is alphanumeric
|
||||
st[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]
|
||||
|
||||
# Python development
|
||||
.venv
|
||||
venv
|
||||
|
||||
# Python generated
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Python modules
|
||||
.*_cache/
|
||||
|
||||
# Documentation
|
||||
doc/_build/
|
||||
|
||||
# Android
|
||||
.gradle/
|
||||
local.properties
|
||||
*.iml
|
||||
.gradletasknamecache
|
||||
project.properties
|
||||
platform/android/java/*/.cxx/
|
||||
platform/android/java/*/build/
|
||||
platform/android/java/*/libs/
|
||||
|
||||
# iOS
|
||||
*.dSYM
|
||||
|
||||
# Web platform
|
||||
*.bc
|
||||
platform/web/node_modules/
|
||||
|
||||
# Misc
|
||||
*.debug
|
||||
|
||||
#############################
|
||||
### IDE and tool specific ###
|
||||
#############################
|
||||
|
||||
# Automake
|
||||
.deps/*
|
||||
.dirstamp
|
||||
|
||||
# ccls
|
||||
.ccls-cache/
|
||||
|
||||
# clangd
|
||||
.clangd/
|
||||
.cache/
|
||||
|
||||
# CLion
|
||||
cmake-build-debug
|
||||
|
||||
# Code::Blocks
|
||||
*.cbp
|
||||
*.layout
|
||||
*.depend
|
||||
|
||||
# CodeLite
|
||||
*.project
|
||||
*.workspace
|
||||
.codelite/
|
||||
|
||||
# Cppcheck
|
||||
*.cppcheck
|
||||
cppcheck-cppcheck-build-dir/
|
||||
|
||||
# Eclipse CDT
|
||||
.cproject
|
||||
.settings/
|
||||
*.pydevproject
|
||||
*.launch
|
||||
|
||||
# Emacs
|
||||
\#*\#
|
||||
.\#*
|
||||
|
||||
# GCOV code coverage
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
# Geany
|
||||
*.geany
|
||||
.geanyprj
|
||||
|
||||
# Gprof
|
||||
gmon.out
|
||||
|
||||
# Jetbrains IDEs
|
||||
.idea/
|
||||
.fleet/
|
||||
|
||||
# Kate
|
||||
*.kate-swp
|
||||
.kateproject.build
|
||||
|
||||
# Kdevelop
|
||||
*.kdev4
|
||||
|
||||
# Qt Creator
|
||||
*.config
|
||||
*.creator
|
||||
*.creator.*
|
||||
*.files
|
||||
*.includes
|
||||
*.cflags
|
||||
*.cxxflags
|
||||
|
||||
# SCons
|
||||
.sconf_temp
|
||||
.sconsign*.dblite
|
||||
.scons_env.json
|
||||
.scons_node_count
|
||||
|
||||
# Sourcetrail
|
||||
*.srctrl*
|
||||
|
||||
# Tags
|
||||
# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
|
||||
# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
|
||||
TAGS
|
||||
!TAGS/
|
||||
tags
|
||||
*.tags
|
||||
!tags/
|
||||
gtags.files
|
||||
GTAGS
|
||||
GRTAGS
|
||||
GPATH
|
||||
cscope.files
|
||||
cscope.out
|
||||
cscope.in.out
|
||||
cscope.po.out
|
||||
|
||||
# Vim
|
||||
*.swo
|
||||
*.swp
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
.history/
|
||||
|
||||
# Xcode
|
||||
xcuserdata/
|
||||
*.xcscmblueprint
|
||||
*.xccheckout
|
||||
*.xcodeproj/*
|
||||
!misc/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
|
||||
|
||||
##############################
|
||||
### Visual Studio specific ###
|
||||
##############################
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
# Ignore Visual Studio temporary files, build results, and
|
||||
# files generated by popular Visual Studio add-ons.
|
||||
|
||||
# Actual VS project files we don't use
|
||||
*.sln
|
||||
*.vcxproj*
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Do not ignore arch-specific folders anywhere under thirdparty libraries
|
||||
!thirdparty/**/x64/
|
||||
!thirdparty/**/x86/
|
||||
!thirdparty/**/arm/
|
||||
!thirdparty/**/arm64/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
enc_temp_folder/
|
||||
~$*
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# Hint file for IntelliSense
|
||||
cpp.hint
|
||||
|
||||
###################
|
||||
### OS specific ###
|
||||
###################
|
||||
|
||||
# Linux
|
||||
*~
|
||||
.directory
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
__MACOSX
|
||||
Godot.app
|
||||
|
||||
# Windows
|
||||
# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
|
||||
[Tt]humbs.db
|
||||
[Tt]humbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
*.stackdump
|
||||
[Dd]esktop.ini
|
||||
$RECYCLE.BIN/
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
*.lnk
|
||||
*.generated.props
|
195
engine/.mailmap
195
engine/.mailmap
|
@ -1,195 +0,0 @@
|
|||
Aaron Record <aaronjrecord@gmail.com>
|
||||
ajreckof <66184050+ajreckof@users.noreply.github.com> <tbonhoure@ymail.com>
|
||||
Alexander Hartmann <alex.hart.278@gmail.com>
|
||||
Alexander Holland <alexander.holland@live.de>
|
||||
Alexander Holland <alexander.holland@live.de> <alexander.holland@haw-hamburg.de>
|
||||
Alexander Holland <alexander.holland@live.de> <AlexHolly>
|
||||
Alfred Reinold Baudisch <alfred@alfredbaudisch.com>
|
||||
Andrea Catania <info@andreacatania.com>
|
||||
Anish Bhobe <anishbhobe@hotmail.com>
|
||||
Anutrix <numaanzaheerahmed@yahoo.com>
|
||||
Aren Villanueva <arenvillanueva@yomogi-soft.com> <aren@displaysweet.com>
|
||||
Ariel Manzur <ariel@godotengine.org>
|
||||
Ariel Manzur <ariel@godotengine.org> <puntob@gmail.com>
|
||||
Ariel Manzur <ariel@godotengine.org> <punto@godotengine.org>
|
||||
Ariel Manzur <ariel@godotengine.org> <ariel@okamstudio.com>
|
||||
Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini.local>
|
||||
Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini-2.local>
|
||||
Arman Elgudzhyan <48544263+puchik@users.noreply.github.com>
|
||||
A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
|
||||
A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> <over999ships@gmail.com>
|
||||
Bastiaan Olij <mux213@gmail.com>
|
||||
Benjamin <mafortion.benjamin@gmail.com>
|
||||
Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.de>
|
||||
Bernhard Liebl <Bernhard.Liebl@gmx.org> <poke1024@gmx.org>
|
||||
Bruno Lourenço <madequa@users.noreply.github.com> <bmlourenco@gmail.com>
|
||||
Chaosus <chaosus89@gmail.com>
|
||||
ChibiDenDen <pdaniq@gmail.com>
|
||||
Chris Bradfield <chris@kidscancode.org> <cb@scribe.net>
|
||||
Clay John <claynjohn@gmail.com>
|
||||
Clay John <claynjohn@gmail.com> <clayjohn@shaw.ca>
|
||||
CookieBadger <emil.dobetsberger@gmail.com>
|
||||
Dana Olson <dana@shineuponthee.com> <adolson@gmail.com>
|
||||
dankan1890 <mewuidev2@gmail.com>
|
||||
Daniel J. Ramirez <djrmuv@gmail.com>
|
||||
Dario <dariosamo@gmail.com>
|
||||
David Cambré <david.cambre@gmail.com> <David.Cambre@gmail.com>
|
||||
DmitriySalnikov <salnikov.mine@yandex.ru>
|
||||
DmitriySalnikov <salnikov.mine@yandex.ru> <dimokgamer@gmail.com>
|
||||
Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
|
||||
DeeJayLSP <djlsplays@gmail.com> <60024671+DeeJayLSP@users.noreply.github.com>
|
||||
Emmanuel Barroga <emmanuelbarroga@gmail.com>
|
||||
Eric M <itsjusteza@gmail.com>
|
||||
Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
|
||||
Erik Selecký <35656626+rxlecky@users.noreply.github.com>
|
||||
Erik Selecký <35656626+rxlecky@users.noreply.github.com> <35656626+SeleckyErik@users.noreply.github.com>
|
||||
Eveline Jarosz <marqin.pl@gmail.com>
|
||||
Eveline Jarosz <marqin.pl@gmail.com> <marqin.pl+git@gmail.com>
|
||||
Fabian <supagu@gmail.com>
|
||||
Ferenc Arn <tagcup@yahoo.com>
|
||||
Ferenc Arn <tagcup@yahoo.com> <tagcup@users.noreply.github.com>
|
||||
FireForge <67974470+fire-forge@users.noreply.github.com> <isaacr.7.2005@gmail.com>
|
||||
Florian Kothmeier <floriankothmeier@web.de>
|
||||
foxydevloper <12120644+foxydevloper@users.noreply.github.com>
|
||||
Fredia Huya-Kouadio <fhuyakou@gmail.com>
|
||||
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@google.com>
|
||||
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@fb.com>
|
||||
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@meta.com>
|
||||
Geequlim <geequlim@gmail.com>
|
||||
Gilles Roudiere <gilles.roudiere@gmail.com>
|
||||
Gilles Roudiere <gilles.roudiere@gmail.com> <gilles.roudiere@laas.fr>
|
||||
Gordon MacPherson <gordon@gordonite.tech>
|
||||
Guilherme Felipe <guilhermefelipecgs@gmail.com>
|
||||
Hakim <hakim.rouatbi@gmail.com>
|
||||
Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
|
||||
HaSa1002 <johawitt@outlook.de>
|
||||
Hein-Pieter van Braam-Stewart <hp@tmm.cx>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> <hugo.l@openmailbox.org>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> <Calinou@users.noreply.github.com>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro> Calinou <calinou@opmbx.org>
|
||||
Ian Bishop <ianb96@gmail.com>
|
||||
Ignacio Etcheverry <ignalfonsore@gmail.com>
|
||||
Ignacio Etcheverry <ignalfonsore@gmail.com> <neikeq@users.noreply.github.com>
|
||||
Ilaria Cislaghi <cislaghi.ilaria@gmail.com>
|
||||
Ilaria Cislaghi <cislaghi.ilaria@gmail.com> <ilaria.cislaghi@simedis.com>
|
||||
Indah Sylvia <ISylvox@yahoo.com>
|
||||
Ivan Shakhov <ivan.shakhov@jetbrains.com> <Ivan.Shakhov@jetbrains.com>
|
||||
Ivan Shakhov <ivan.shakhov@jetbrains.com> <van800@gmail.com>
|
||||
iwek <miwanczuk7@gmail.com>
|
||||
J08nY <johny@neuromancer.sk> <jancar.jj@gmail.com>
|
||||
J08nY <johny@neuromancer.sk> <J08nY@users.noreply.github.com>
|
||||
Jake Young <young9003@gmail.com>
|
||||
Jakub Grzesik <kubecz3k@gmail.com>
|
||||
Jakub Marcowski <chubercikbattle@gmail.com> <01158831@pw.edu.pl>
|
||||
Jakub Marcowski <chubercikbattle@gmail.com> <37378746+Chubercik@users.noreply.github.com>
|
||||
janglee <merupatel123@gmail.com>
|
||||
Jason Knight <00jknight@gmail.com> <jason@winterpixel.com>
|
||||
Jean-Michel Bernard <jmb462@gmail.com>
|
||||
Jérôme Gully <jerome.gully0@gmail.com>
|
||||
JFonS <joan.fonssanchez@gmail.com>
|
||||
jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
|
||||
Johan Aires Rastén <johan@oljud.se>
|
||||
Juan Linietsky <reduzio@gmail.com>
|
||||
Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
|
||||
Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
|
||||
Juan Linietsky <reduzio@gmail.com> <reduz@Juans-MBP.fibertel.com.ar>
|
||||
Juan Linietsky <reduzio@gmail.com> <red@kyoko>
|
||||
Julian Murgia <the.straton@gmail.com>
|
||||
Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com>
|
||||
karroffel <therzog@mail.de>
|
||||
karroffel <therzog@mail.de> <thomas.herzog@mail.com>
|
||||
karroffel <therzog@mail.de> <thomas.herzog@simedis.com>
|
||||
Kasper Arnklit Frandsen <kasper.arnklit@gmail.com>
|
||||
Kelly Thomas <kelly.thomas@hotmail.com.au>
|
||||
Kongfa Waroros <gongpha@hotmail.com>
|
||||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
|
||||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> <fire@users.noreply.github.com>
|
||||
kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
|
||||
Leon Krause <lk@leonkrause.com> <eska@eska.me>
|
||||
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
|
||||
Liz Haas <27thLiz@gmail.com>
|
||||
Liz Haas <27thLiz@gmail.com> <liu.gam3@gmail.com>
|
||||
Liz Haas <27thLiz@gmail.com> <hinsbart@gmail.com>
|
||||
Liz Haas <27thLiz@gmail.com> <hinsbart@users.noreply.github.com>
|
||||
Liz Haas <27thLiz@gmail.com> <entenflugstuhl@gmail.com>
|
||||
Logan Lang <devloglogan@gmail.com>
|
||||
Manuele Finocchiaro <m4nu3lf@gmail.com>
|
||||
Manuel Strey <manuel.strey@gmx.de>
|
||||
Marcel Admiraal <madmiraal@users.noreply.github.com>
|
||||
Marcelo Fernandez <marcelofg55@gmail.com>
|
||||
Marcin Zawiejski <dragmz@gmail.com>
|
||||
Marcus Elg <marcusaccounts@yahoo.se>
|
||||
Mariano Javier Suligoy <marianognu.easyrpg@gmail.com>
|
||||
Mario Schlack <m4r10.5ch14ck@gmail.com>
|
||||
Mark DiBarry <markdibarry@protonmail.com>
|
||||
marxin <mliska@suse.cz>
|
||||
marynate <mary.w.nate@gmail.com> <marynate@github.com>
|
||||
Mateo Kuruk Miccino <mateomiccino@gmail.com>
|
||||
Max Hilbrunner <m.hilbrunner@gmail.com>
|
||||
Max Hilbrunner <m.hilbrunner@gmail.com> <mhilbrunner@users.noreply.github.com>
|
||||
MewPurPur <mew.pur.pur@abv.bg>
|
||||
Michael Alexsander <michaelalexsander@protonmail.com>
|
||||
Micky <micheledevita2@gmail.com> <66727710+Mickeon@users.noreply.github.com>
|
||||
Nathan Franke <natfra@pm.me> <nathanwfranke@gmail.com>
|
||||
Nathan Lovato <nathan@gdquest.com>
|
||||
Nathan Warden <nathan@nathanwarden.com> <nathanwardenlee@icloud.com>
|
||||
Nazarii <nazarii.yablonskyi.pp.2022@lpnu.ua>
|
||||
Nicholas Huelin <62965063+SirQuartz@users.noreply.github.com>
|
||||
Nils ANDRÉ-CHANG <nils@nilsand.re>
|
||||
Nils ANDRÉ-CHANG <nils@nilsand.re> <nils.andre.chang@gmail.com>
|
||||
Nông Văn Tình <vannongtinh@gmail.com>
|
||||
Nuno Donato <nunodonato@gmail.com> <n.donato@estrelasustentavel.pt>
|
||||
ocean (they/them) <anvilfolk@gmail.com>
|
||||
Pawel Kowal <pkowal1982@gmail.com>
|
||||
Pedro J. Estébanez <pedrojrulez@gmail.com> <RandomShaper@users.noreply.github.com>
|
||||
Patrick Exner <patrick.exner1@web.de>
|
||||
Patrick <firefly2442@gmail.com>
|
||||
Paul Batty <p_batty@hotmail.co.uk>
|
||||
Paul Batty <p_batty@hotmail.co.uk> <Paulb23@users.noreply.github.com>
|
||||
Pāvels Nadtočajevs <7645683+bruvzg@users.noreply.github.com>
|
||||
Pawel Kowal <pkowal1982@gmail.com> <pawel.kowal@javart.eu>
|
||||
Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
|
||||
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
|
||||
Poommetee Ketson <poommetee@protonmail.com>
|
||||
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
|
||||
Radiant <69520693+RadiantUwU@users.noreply.github.com> <i.like.using.discord@gmail.com>
|
||||
Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||
Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
|
||||
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
|
||||
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@users.noreply.github.com>
|
||||
Ramesh Ravone <ramesh.maran443@gmail.com>
|
||||
RaphaelHunter <raphael10241024@gmail.com>
|
||||
RaphaelHunter <raphael10241024@gmail.com> <Raphael10241024@gmail.com>
|
||||
RaphaelHunter <raphael10241024@gmail.com> <raphael20141024@gmail.com>
|
||||
Rémi Verschelde <rverschelde@gmail.com> <remi@verschelde.fr>
|
||||
Rhody Lugo <rhodylugo@gmail.com> <rhodylugo@me.com>
|
||||
Ricardo Subtil <ricasubtil@gmail.com>
|
||||
Rindbee <idleman@yeah.net>
|
||||
Riteo Siuga <riteo@posteo.net>
|
||||
Robin Hübner <profan@prfn.se> <robinhubner@gmail.com>
|
||||
romulox_x <romulox_x@yahoo.com>
|
||||
Rudolph Bester <Rudolph.f.Bester@gmail.com> <Rudolph.f.bester@gmail.com>
|
||||
rune-scape <allie.smith.epic@gmail.com>
|
||||
rune-scape <allie.smith.epic@gmail.com> <spartacrafter@gmail.com>
|
||||
Ruslan Mustakov <r.mustakov@gmail.com> <ruslan.mustakov@xored.com>
|
||||
Saracen <SaracenOne@gmail.com>
|
||||
sheepandshepherd <sheepandshepherd@hotmail.com> <sheepandshepherd@users.noreply.github.com>
|
||||
Silc 'Tokage' Renew <tokage.it.lab@gmail.com>
|
||||
Silc 'Tokage' Renew <tokage.it.lab@gmail.com> <61938263+TokageItLab@users.noreply.github.com>
|
||||
Swarnim Arun <swarnimarun11@gmail.com>
|
||||
TechnoPorg <jonah.janzen@gmail.com> <69441745+TechnoPorg@users.noreply.github.com>
|
||||
tetrapod00 <145553014+tetrapod00@users.noreply.github.com>
|
||||
Theo Hallenius <redsymbzone@hotmail.com>
|
||||
Tomasz Chabora <kobewi4e@gmail.com>
|
||||
Twarit <wtwarit@gmail.com>
|
||||
Vitika9 <vitika.program@gmail.com>
|
||||
V.VamsiKrishna <vk@bsb.in> <vamsikrishna.v@gmail.com>
|
||||
Wilhem Barbier <nounoursheureux@openmailbox.org> <wilhem.b@free.fr>
|
||||
Wilhem Barbier <nounoursheureux@openmailbox.org> <schtroumps31@gmail.com>
|
||||
Will Nations <willnationsdev@gmail.com>
|
||||
yg2f <yoann@terminajones.com>
|
||||
Yuri Sizov <yuris@humnom.net> <pycbouh@users.noreply.github.com>
|
||||
Yuri Sizov <yuris@humnom.net> <yaschik4ilicha@gmail.com>
|
||||
Zae <zaevi@live.com>
|
||||
Zak Stam <zakscomputers@hotmail.com>
|
||||
Zher Huei Lee <lee.zh.92@gmail.com>
|
|
@ -1,192 +0,0 @@
|
|||
default_language_version:
|
||||
python: python3
|
||||
|
||||
exclude: |
|
||||
(?x)^(
|
||||
.*thirdparty/.*|
|
||||
.*-so_wrap\.(h|c)|
|
||||
platform/android/java/editor/src/main/java/com/android/.*|
|
||||
platform/android/java/lib/src/com/google/.*
|
||||
)$
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v19.1.3
|
||||
hooks:
|
||||
- id: clang-format
|
||||
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
|
||||
types_or: [text]
|
||||
exclude: ^tests/python_build/.*
|
||||
- id: clang-format
|
||||
name: clang-format-glsl
|
||||
files: \.glsl$
|
||||
types_or: [text]
|
||||
exclude: ^tests/python_build/.*
|
||||
args: [-style=file:misc/utility/clang_format_glsl.yml]
|
||||
|
||||
- repo: https://github.com/pocc/pre-commit-hooks
|
||||
rev: v1.3.5
|
||||
hooks:
|
||||
- id: clang-tidy
|
||||
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$
|
||||
args: [--fix, --quiet, --use-color]
|
||||
types_or: [text]
|
||||
exclude: ^tests/python_build/.*
|
||||
additional_dependencies: [clang-tidy==19.1.0]
|
||||
require_serial: true
|
||||
stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.9.4
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix]
|
||||
files: (\.py|SConstruct|SCsub)$
|
||||
types_or: [text]
|
||||
- id: ruff-format
|
||||
files: (\.py|SConstruct|SCsub)$
|
||||
types_or: [text]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.14.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: \.py$
|
||||
types_or: [text]
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies: [tomli]
|
||||
|
||||
### Requires Docker; look into alternative implementation.
|
||||
# - repo: https://github.com/comkieffer/pre-commit-xmllint.git
|
||||
# rev: 1.0.0
|
||||
# hooks:
|
||||
# - id: xmllint
|
||||
# language: docker
|
||||
# types_or: [text]
|
||||
# files: ^(doc/classes|.*/doc_classes)/.*\.xml$
|
||||
# args: [--schema, doc/class.xsd]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: make-rst
|
||||
name: make-rst
|
||||
language: python
|
||||
entry: python doc/tools/make_rst.py
|
||||
args: [doc/classes, modules, platform, --dry-run, --color]
|
||||
pass_filenames: false
|
||||
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
|
||||
|
||||
- id: doc-status
|
||||
name: doc-status
|
||||
language: python
|
||||
entry: python doc/tools/doc_status.py
|
||||
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
|
||||
pass_filenames: false
|
||||
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
|
||||
|
||||
- id: eslint
|
||||
name: eslint
|
||||
language: node
|
||||
entry: eslint
|
||||
files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
|
||||
args:
|
||||
- --fix
|
||||
- --no-warn-ignored
|
||||
- --no-config-lookup
|
||||
- --config
|
||||
- platform/web/eslint.config.cjs
|
||||
additional_dependencies:
|
||||
- "@eslint/js@^9.3.0"
|
||||
- "@html-eslint/eslint-plugin@^0.24.1"
|
||||
- "@html-eslint/parser@^0.24.1"
|
||||
- "@stylistic/eslint-plugin@^2.1.0"
|
||||
- eslint@^9.3.0
|
||||
- eslint-plugin-html@^8.1.1
|
||||
- globals@^15.3.0
|
||||
- espree@^10.0.1
|
||||
|
||||
- id: jsdoc
|
||||
name: jsdoc
|
||||
language: node
|
||||
entry: jsdoc
|
||||
files: ^platform/web/js/engine/(engine|config|features)\.js$
|
||||
args:
|
||||
- --template
|
||||
- platform/web/js/jsdoc2rst/
|
||||
- platform/web/js/engine/engine.js
|
||||
- platform/web/js/engine/config.js
|
||||
- platform/web/js/engine/features.js
|
||||
- --destination
|
||||
- ""
|
||||
- -d
|
||||
- dry-run
|
||||
pass_filenames: false
|
||||
additional_dependencies: [jsdoc@^4.0.3]
|
||||
|
||||
- id: svgo
|
||||
name: svgo
|
||||
language: node
|
||||
entry: svgo
|
||||
files: \.svg$
|
||||
args: [--quiet, --config, misc/utility/svgo.config.mjs]
|
||||
additional_dependencies: [svgo@3.3.2]
|
||||
|
||||
- id: copyright-headers
|
||||
name: copyright-headers
|
||||
language: python
|
||||
entry: python misc/scripts/copyright_headers.py
|
||||
files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$
|
||||
exclude: |
|
||||
(?x)^(
|
||||
core/math/bvh_.*\.inc|
|
||||
platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
|
||||
platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java|
|
||||
platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java|
|
||||
platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java
|
||||
)$
|
||||
|
||||
- id: header-guards
|
||||
name: header-guards
|
||||
language: python
|
||||
entry: python misc/scripts/header_guards.py
|
||||
files: \.(h|hpp|hh|hxx)$
|
||||
exclude: ^.*/(dummy|thread|platform_config|platform_gl)\.h$
|
||||
|
||||
- id: file-format
|
||||
name: file-format
|
||||
language: python
|
||||
entry: python misc/scripts/file_format.py
|
||||
types_or: [text]
|
||||
exclude: |
|
||||
(?x)^(
|
||||
.*\.test\.txt|
|
||||
.*\.svg|
|
||||
.*\.patch|
|
||||
.*\.out|
|
||||
modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd|
|
||||
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.norun\.gd|
|
||||
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.norun\.gd|
|
||||
tests/data/.*\.bin
|
||||
)$
|
||||
|
||||
- id: dotnet-format
|
||||
name: dotnet-format
|
||||
language: python
|
||||
entry: python misc/scripts/dotnet_format.py
|
||||
types_or: [c#]
|
||||
#
|
||||
# End of upstream Godot pre-commit hooks.
|
||||
#
|
||||
# Keep this separation to let downstream forks add their own hooks to this file,
|
||||
# without running into merge conflicts when rebasing on latest upstream.
|
||||
#
|
||||
# Start of downstream pre-commit hooks.
|
||||
#
|
||||
# This is still the "repo: local" scope, so new local hooks can be defined directly at this indentation:
|
||||
# - id: new-local-hook
|
||||
# To add external repo hooks, bring the indentation back to:
|
||||
# - repo: my-remote-hook
|
|
@ -1,359 +0,0 @@
|
|||
# Godot Engine authors
|
||||
|
||||
Godot Engine is developed by a community of voluntary contributors who
|
||||
contribute code, bug reports, documentation, translations, support, etc.,
|
||||
across multiple repositories.
|
||||
|
||||
It is impossible to list them all; nevertheless, this file aims at listing
|
||||
the developers who contributed significant improvements to the engine code.
|
||||
|
||||
To keep the list curated, we use a threshold of a minimum of 11 commits.
|
||||
|
||||
This file does not strictly reflect copyright ownership for the engine
|
||||
source code. For this, refer to the Git history to know which contributor
|
||||
wrote which part of the codebase.
|
||||
|
||||
GitHub usernames are indicated in parentheses, or as sole entry when no other
|
||||
name is available.
|
||||
|
||||
## Project Founders
|
||||
|
||||
Juan Linietsky (reduz)
|
||||
Ariel Manzur (punto-)
|
||||
|
||||
## Lead Developer
|
||||
|
||||
Juan Linietsky (reduz)
|
||||
|
||||
## Project Manager
|
||||
|
||||
Rémi Verschelde (akien-mga)
|
||||
|
||||
## Developers
|
||||
|
||||
Aaron Franke (aaronfranke)
|
||||
Aaron Pagano (aaronp64)
|
||||
Aaron Record (LightningAA)
|
||||
Adam Scott (adamscott)
|
||||
Alexander Hartmann (Alex2782)
|
||||
Alexander Holland (AlexHolly)
|
||||
Alex Drozd (brno32)
|
||||
Alexey Khoroshavin (allkhor)
|
||||
Allen Pestaluky (allenwp)
|
||||
Alfred Reinold Baudisch (alfredbaudisch)
|
||||
Alistair Leslie-Hughes (alesliehughes)
|
||||
Alket Rexhepi (alketii)
|
||||
Alvin Wong (alvinhochun)
|
||||
Andrea Catania (AndreaCatania)
|
||||
Andreia Gaita (shana)
|
||||
Andrés Botero (0xafbf)
|
||||
Andrii Doroshenko (Xrayez)
|
||||
Andy Maloney (asmaloney)
|
||||
Andy Moss (MillionOstrich)
|
||||
Angad Kambli (angad-k)
|
||||
Anilforextra (AnilBK)
|
||||
Anish Bhobe (KidRigger)
|
||||
Anish Mishra (syntaxerror247)
|
||||
Anni Ryynänen (anniryynanen)
|
||||
Anton Yabchinskiy (a12n)
|
||||
Anutrix
|
||||
Aren Villanueva (kurikaesu)
|
||||
Ariel Manzur (punto-)
|
||||
arkology
|
||||
Arman Elgudzhyan (puchik)
|
||||
Arseny Kapoulkine (zeux)
|
||||
AThousandShips
|
||||
aXu-AP
|
||||
Bartłomiej T. Listwon (Listwon)
|
||||
Bastiaan Olij (BastiaanOlij)
|
||||
Ben Brookshire (sheepandshepherd)
|
||||
Benjamin Larsson (Nallebeorn)
|
||||
Bernhard Liebl (poke1024)
|
||||
Bhuvan Vemula (Bhu1-V)
|
||||
bitsawer
|
||||
Błażej Szczygieł (zaps166)
|
||||
BlueCube3310
|
||||
Bojidar Marinov (bojidar-bg)
|
||||
Brian Semrau (briansemrau)
|
||||
Bruno Lourenço (MadEqua)
|
||||
Cameron Reikes (creikey)
|
||||
Camille Mohr-Daurat (pouleyKetchoupp)
|
||||
Caner Demirer (cdemirer)
|
||||
Carl Olsson (not-surt)
|
||||
Carter Anderson (cart)
|
||||
ChibiDenDen
|
||||
Chris Bradfield (cbscribe)
|
||||
Chris Cranford (Naros)
|
||||
Christian Kaiser (ckaiser)
|
||||
Clay John (clayjohn)
|
||||
ConteZero
|
||||
CookieBadger
|
||||
Dana Olson (adolson)
|
||||
Daniel J. Ramirez (djrm)
|
||||
Daniel Rakos (aqnuep)
|
||||
Daniel Zilberleyb (dzil123)
|
||||
Danil Alexeev (dalexeev)
|
||||
dankan1890
|
||||
Darío Banini (DarioSamo)
|
||||
David Cambré (Gallilus)
|
||||
David Sichma (DavidSichma)
|
||||
David Snopek (dsnopek)
|
||||
derammo
|
||||
Dharkael (lupoDharkael)
|
||||
Dirk Steinmetz (rsjtdrjgfuzkfg)
|
||||
Dmitry Koteroff (Krakean)
|
||||
Dmitry Maganov (vonagam)
|
||||
Dominik Jasiński (dreamsComeTrue)
|
||||
Douglas Leão (DeeJayLSP)
|
||||
DualMatrix
|
||||
Ellen Poe (ellenhp)
|
||||
Emilio Coppola (coppolaemilio)
|
||||
Emmanuel Barroga (codecustard)
|
||||
Emmanuel Leblond (touilleMan)
|
||||
Eoin O'Neill (Eoin-ONeill-Yokai)
|
||||
Eric Lasota (elasota)
|
||||
Eric M (EricEzaM)
|
||||
Eric Rybicki (ericrybick)
|
||||
Erik Selecký (rxlecky)
|
||||
est31
|
||||
Eveline Jarosz (Marqin)
|
||||
Fabian Mathews (supagu)
|
||||
Fabio Alessandrelli (Faless)
|
||||
Fabrice Cipolla (fabriceci)
|
||||
Ferenc Arn (tagcup)
|
||||
FireForge (fire-forge)
|
||||
Florent Guiocheau (Flarkk)
|
||||
Florian Kothmeier (Dragoncraft89)
|
||||
follower
|
||||
foxydevloper
|
||||
François Belair (Razoric480)
|
||||
Franklin Sobrinho (TheHX)
|
||||
Fredia Huya-Kouadio (m4gr3d)
|
||||
Geequlim
|
||||
George Marques (vnen)
|
||||
Gerrit Großkopf (Grosskopf)
|
||||
Giganzo
|
||||
Gilles Roudiere (groud)
|
||||
Gordon MacPherson (RevoluPowered)
|
||||
Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
|
||||
Guillaume Mouton (kiroxas)
|
||||
Hakim Rouatbi (hakro)
|
||||
Hanif Bin Ariffin (hbina)
|
||||
Haoyu Qiu (timothyqiu)
|
||||
Hein-Pieter van Braam-Stewart (hpvb)
|
||||
Hendrik Brucker (Geometror)
|
||||
Hilderin
|
||||
Hiroshi Ogawa (hi-ogawa)
|
||||
HolonProduction
|
||||
homer666
|
||||
hoontee
|
||||
Hugo Locurcio (Calinou)
|
||||
Ian Bishop (ianb96)
|
||||
Ibrahn Sahir (ibrahn)
|
||||
Ignacio Roldán Etcheverry (neikeq)
|
||||
Igor Kordiukiewicz (IgorKordiukiewicz)
|
||||
Ilaria Cislaghi (QbieShay)
|
||||
Indah Sylvia (ISylvox)
|
||||
Ivan Šachov (van800)
|
||||
J08nY
|
||||
Jake Young (Duroxxigar)
|
||||
Jakub Grzesik (kubecz3k)
|
||||
Jakub Marcowski (Chubercik)
|
||||
James Buck (jbuck3)
|
||||
Jan Haller (Bromeon)
|
||||
Jason Knight (jasonwinterpixel)
|
||||
Jean-Michel Bernard (jmb462)
|
||||
Jérôme Gully (Nutriz)
|
||||
Jia Jun Chai (SkyLucilfer)
|
||||
jitspoe
|
||||
Joan Fons Sanchez (JFonS)
|
||||
Johan Aires Rastén (JohanAR)
|
||||
Johan Manuel (29jm)
|
||||
Johannes Witt (HaSa1002)
|
||||
Jonathan Nicholl (jtnicholl)
|
||||
Jordan Schidlowsky (winterpixelgames)
|
||||
Josh Jones (DarkKilauea)
|
||||
Joshua Grams (JoshuaGrams)
|
||||
Juan Linietsky (reduz)
|
||||
Julian Murgia (StraToN)
|
||||
Julien Nguyen (Blackiris)
|
||||
Jummit
|
||||
Justo Delgado (mrcdk)
|
||||
karroffel
|
||||
Kassandra Pucher (PucklaJ)
|
||||
Kelly Thomas (KellyThomas)
|
||||
kleonc
|
||||
Kongfa Waroros (gongpha)
|
||||
Kostadin Damyanov (Max-Might)
|
||||
K. S. Ernest (iFire) Lee (fire)
|
||||
Kyle Eichlin (likeich)
|
||||
Lars Pettersson (larspet)
|
||||
lawnjelly
|
||||
Leon Krause (leonkrause)
|
||||
Liz Haas (27thLiz)
|
||||
Logan Lang (devloglogan)
|
||||
Lucien Menassol (Kanabenki)
|
||||
Lukas Tenbrink (Ivorforce)
|
||||
Lyuma
|
||||
Maganty Rushyendra (mrushyendra)
|
||||
Magian (magian1127)
|
||||
Mai Lavelle (maiself)
|
||||
Malcolm Anderson (Meorge)
|
||||
Malcolm Nixon (Malcolmnixon)
|
||||
Manuele Finocchiaro (m4nu3lf)
|
||||
Marcel Admiraal (madmiraal)
|
||||
Marcelo Fernandez (marcelofg55)
|
||||
Marc Gilleron (Zylann)
|
||||
Marcin Zawiejski (dragmz)
|
||||
Marcus Brummer (mbrlabs)
|
||||
Marcus Elg (MCrafterzz)
|
||||
Mariano Javier Suligoy (MarianoGnu)
|
||||
Mario Liebisch (MarioLiebisch)
|
||||
Mario Schlack (hurikhan)
|
||||
Marios Staikopoulos (marstaik)
|
||||
Marius Hanl (Maran23)
|
||||
Mark DiBarry (markdibarry)
|
||||
Mark Riedesel (klowner)
|
||||
Markus Sauermann (Sauermann)
|
||||
Martin Capitanio (capnm)
|
||||
Martin Liška (marxin)
|
||||
Martin Sjursen (binbitten)
|
||||
marynate
|
||||
Masoud BH (masoudbh3)
|
||||
Mateo Kuruk Miccino (kuruk-mm)
|
||||
Matias N. Goldberg (darksylinc)
|
||||
Matthew Murphy (mashumafi)
|
||||
Matthew (skyace65)
|
||||
Matthias Hölzl (hoelzl)
|
||||
Max Hilbrunner (mhilbrunner)
|
||||
merumelu
|
||||
Meru Patel (Janglee123)
|
||||
MewPurPur
|
||||
Michael Alexsander (YeldhamDev)
|
||||
Michał Iwańczuk (iwek7)
|
||||
MichiRecRoom (LikeLakers2)
|
||||
Micky (Mickeon)
|
||||
Mikael Hermansson (mihe)
|
||||
Mika Viskari (miv391)
|
||||
MinusKube
|
||||
MJacred
|
||||
Mounir Tohami (WhalesState)
|
||||
mrezai
|
||||
Muhammad Huri (CakHuri)
|
||||
muiroc
|
||||
myaaaaaaaaa
|
||||
Nathalie Galla (MurderVeggie)
|
||||
Nathan Franke (nathanfranke)
|
||||
Nathan Lovato (NathanLovato)
|
||||
Nathan Warden (NathanWarden)
|
||||
Nazarii Yablonskyi (Nazarwadim)
|
||||
Nicholas Huelin (SirQuartz)
|
||||
Nikita Lita (nikitalita)
|
||||
Nils André-Chang (NilsIrl)
|
||||
Noah Beard (TwistedTwigleg)
|
||||
Nông Văn Tình (nongvantinh)
|
||||
Nuno Donato (nunodonato)
|
||||
ocean (they/them) (anvilfolk)
|
||||
Omar El Sheikh (The-O-King)
|
||||
Ovnuniarchos
|
||||
Pablo Andres Fuente (pafuent)
|
||||
Pascal Richter (ShyRed)
|
||||
passivestar
|
||||
Patrick Dawson (pkdawson)
|
||||
Patrick Exner (FlameLizard)
|
||||
Patrick (firefly2442)
|
||||
patwork
|
||||
Paul Batty (Paulb23)
|
||||
Paul Joannon (paulloz)
|
||||
Paul Trojahn (ptrojahn)
|
||||
Pāvels Nadtočajevs (bruvzg)
|
||||
Paweł Fertyk (pfertyk)
|
||||
Pawel Kowal (pkowal1982)
|
||||
Pawel Lampe (Scony)
|
||||
Pedro J. Estébanez (RandomShaper)
|
||||
Pieter-Jan Briers (PJB3005)
|
||||
Poommetee Ketson (Noshyaar)
|
||||
Przemysław Gołąb (n-pigeon)
|
||||
Radiant (radiantgurl)
|
||||
Rafael M. G. (rafallus)
|
||||
Rafał Mikrut (qarmin)
|
||||
Raffaele Picca (RPicster)
|
||||
Ralf Hölzemer (rollenrolm)
|
||||
Ramesh Ravone (RameshRavone)
|
||||
Raphael2048
|
||||
Raul Santos (raulsntos)
|
||||
Ray Koopa (RayKoopa)
|
||||
RedMser
|
||||
RedworkDE
|
||||
Rémi Verschelde (akien-mga)
|
||||
Rhody Lugo (rraallvv)
|
||||
Ricardo Buring (rburing)
|
||||
Ricardo Subtil (Ev1lbl0w)
|
||||
Riteo Siuga (Riteo)
|
||||
Roberto F. Arroyo (robfram)
|
||||
Robert Yevdokimov (ryevdokimov)
|
||||
Robin Hübner (profan)
|
||||
romulox-x
|
||||
Rudolph Bester (Rudolph-B)
|
||||
Rune Smith (rune-scape)
|
||||
Ruslan Mustakov (endragor)
|
||||
Ryan Roden-Corrent (rrcore)
|
||||
Saniko (sanikoyes)
|
||||
santouits
|
||||
SaracenOne
|
||||
Septian Ganendra S. K. (sepTN)
|
||||
Sergey Minakov (naithar)
|
||||
sersoong
|
||||
Shiqing (kawa-yoiko)
|
||||
Silc 'Tokage' Renew (TokageItLab)
|
||||
Simon Wenner (swenner)
|
||||
smix8
|
||||
snailrhymer
|
||||
Sofox (TheSofox)
|
||||
Stanislav Labzyuk (DarkMessiah)
|
||||
Stijn Hinlopen (hinlopen)
|
||||
stmSi
|
||||
Stuart Carnie (stuartcarnie)
|
||||
Swarnim Arun (minraws)
|
||||
TC (floppyhammer)
|
||||
TechnoPorg
|
||||
tetrapod00
|
||||
Thaddeus Crews (Repiteo)
|
||||
Thakee Nathees (ThakeeNathees)
|
||||
thebestnom
|
||||
Theo Hallenius (TheoXD)
|
||||
Thomas ten Cate (ttencate)
|
||||
Timo Schwarzer (timoschwarzer)
|
||||
Timothé Bonhoure (ajreckof)
|
||||
Timo (toger5)
|
||||
Tomasz Chabora (KoBeWi)
|
||||
Travis Lange (TCROC)
|
||||
trollodel
|
||||
Twarit Waikar (IronicallySerious)
|
||||
Umang Kalra (theoway)
|
||||
Victor Hampel (havi05)
|
||||
Vinzenz Feenstra (vinzenz)
|
||||
Vitika Soni (Vitika9)
|
||||
박한얼 (volzhs)
|
||||
V. Vamsi Krishna (vkbsb)
|
||||
Wilhem Barbier (nounoursheureux)
|
||||
William Deurwaarder (williamd67)
|
||||
Will Nations (willnationsdev)
|
||||
Wilson E. Alvarez (Rubonnek)
|
||||
Xavier Cho (mysticfall)
|
||||
Yaohua Xiong (xiongyaohua)
|
||||
Yevhen Babiichuk (dustdfg)
|
||||
yg2f (SuperUserNameMan)
|
||||
Yordan Dolchinkov (Jordyfel)
|
||||
Yufeng Ying (YYF233333)
|
||||
Yuri Rubinsky (Chaosus)
|
||||
Yuri Sizov (YuriSizov)
|
||||
Zae Chao (zaevi)
|
||||
Zak Stam (zaksnet)
|
||||
Zher Huei Lee (leezh)
|
||||
Zi Ye (MajorMcDoom)
|
||||
ZuBsPaCe
|
||||
Дмитрий Сальников (DmitriySalnikov)
|
||||
忘忧の (Daylily-Zeleen)
|
||||
谢天 (jsjtxietian)
|
||||
风青山 (Rindbee)
|
2953
engine/CHANGELOG.md
2953
engine/CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -1,213 +0,0 @@
|
|||
# Contributors guidelines
|
||||
|
||||
This document summarizes the most important points for people interested in
|
||||
contributing to Godot, especially via bug reports or pull requests.
|
||||
|
||||
The Godot documentation has a dedicated [Contributing section](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
|
||||
which details these points and more, and is a recommended read.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Reporting bugs](#reporting-bugs)
|
||||
- [Proposing features or improvements](#proposing-features-or-improvements)
|
||||
- [Contributing pull requests](#contributing-pull-requests)
|
||||
- [Contributing to Godot translations](#contributing-to-godot-translations)
|
||||
- [Communicating with developers](#communicating-with-developers)
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Report bugs [here](https://github.com/godotengine/godot/issues/new?assignees=&labels=&template=bug_report.yml).
|
||||
Please follow the instructions in the template when you do.
|
||||
|
||||
Notably, please include a Minimal Reproduction Project (MRP), which is a small
|
||||
Godot project which reproduces the issue, with no unnecessary files included.
|
||||
Be sure to not include the `.godot` folder in the archive to save space.
|
||||
|
||||
Make sure that the bug you are experiencing is reproducible in the latest Godot
|
||||
releases. You can find an overview of all Godot releases [on the website](https://godotengine.org/download/archive/)
|
||||
to confirm whether your current version is the latest one. It's worth testing
|
||||
against both the latest stable release and the latest dev snapshot for the next
|
||||
Godot release.
|
||||
|
||||
If you run into a bug which wasn't present in an earlier Godot version (what we
|
||||
call a _regression_), please mention it and clarify which versions you tested
|
||||
(both the one(s) working and the one(s) exhibiting the bug).
|
||||
|
||||
## Proposing features or improvements
|
||||
|
||||
**The main issue tracker is for bug reports and does not accept feature proposals.**
|
||||
|
||||
Instead, head to the [Godot Proposals repository](https://github.com/godotengine/godot-proposals)
|
||||
and follow the instructions in the README file and issue template.
|
||||
|
||||
## Contributing pull requests
|
||||
|
||||
If you want to add new engine features, please make sure that:
|
||||
|
||||
- This functionality is desired, which means that it solves a common use case
|
||||
that several users will need in their real-life projects.
|
||||
- You talked to other developers on how to implement it best. See also
|
||||
[Proposing features or improvements](#proposing-features-or-improvements).
|
||||
- Even if it doesn't get merged, your PR is useful for future work by another
|
||||
developer.
|
||||
|
||||
Similar rules can be applied when contributing bug fixes - it's always best to
|
||||
discuss the implementation in the bug report first if you are not 100% about
|
||||
what would be the best fix.
|
||||
|
||||
You can refer to the [Pull request review process](https://docs.godotengine.org/en/latest/contributing/workflow/pr_review_guidelines.html)
|
||||
for insights into the intended lifecycle of pull requests. This should help you
|
||||
ensure that your pull request fulfills the requirements.
|
||||
|
||||
In addition to the following tips, also take a look at the
|
||||
[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html)
|
||||
for an introduction to developing on Godot.
|
||||
|
||||
The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/how_to_contribute.html)
|
||||
also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
|
||||
(with a helpful guide for Git usage), and our [Code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html)
|
||||
which all contributions need to follow.
|
||||
|
||||
### Be mindful of your commits
|
||||
|
||||
Try to make simple PRs that handle one specific topic. Just like for reporting
|
||||
issues, it's better to open 3 different PRs that each address a different issue
|
||||
than one big PR with three commits. This makes it easier to review, approve, and
|
||||
merge the changes independently.
|
||||
|
||||
When updating your fork with upstream changes, please use ``git pull --rebase``
|
||||
to avoid creating "merge commits". Those commits unnecessarily pollute the git
|
||||
history when coming from PRs.
|
||||
|
||||
Also try to make commits that bring the engine from one stable state to another
|
||||
stable state, i.e. if your first commit has a bug that you fixed in the second
|
||||
commit, try to merge them together before making your pull request. This
|
||||
includes fixing build issues or typos, adding documentation, etc.
|
||||
|
||||
See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
|
||||
documentation for tips on using Git, amending commits and rebasing branches.
|
||||
|
||||
This [Git style guide](https://github.com/agis-/git-style-guide) also has some
|
||||
good practices to have in mind.
|
||||
|
||||
### Format your commit messages with readability in mind
|
||||
|
||||
The way you format your commit messages is quite important to ensure that the
|
||||
commit history and changelog will be easy to read and understand. A Git commit
|
||||
message is formatted as a short title (first line) and an extended description
|
||||
(everything after the first line and an empty separation line).
|
||||
|
||||
The short title is the most important part, as it is what will appear in the
|
||||
changelog or in the GitHub interface unless you click the "expand" button.
|
||||
Try to keep that first line under 72 characters, but you can go slightly above
|
||||
if necessary to keep the sentence clear.
|
||||
|
||||
It should be written in English, starting with a capital letter, and usually
|
||||
with a verb in imperative form. A typical bugfix would start with "Fix", while
|
||||
the addition of a new feature would start with "Add". A prefix can be added to
|
||||
specify the engine area affected by the commit. Some examples:
|
||||
|
||||
- Add C# iOS support
|
||||
- Show doc tooltips when hovering properties in the theme editor
|
||||
- Fix GLES3 instanced rendering color and custom data defaults
|
||||
- Core: Fix `Object::has_method()` for script static methods
|
||||
|
||||
If your commit fixes a reported issue, please include it in the _description_
|
||||
of the PR (not in the title, or the commit message) using one of the
|
||||
[GitHub closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
|
||||
such as "Fixes #1234". This will cause the issue to be closed automatically if
|
||||
the PR is merged. Adding it to the commit message is easier, but adds a lot of
|
||||
unnecessary updates in the issue distracting from the thread.
|
||||
|
||||
Here's an example of a well-formatted commit message (note how the extended
|
||||
description is also manually wrapped at 80 chars for readability):
|
||||
|
||||
```text
|
||||
Prevent French fries carbonization by fixing heat regulation
|
||||
|
||||
When using the French fries frying module, Godot would not regulate the heat
|
||||
and thus bring the oil bath to supercritical liquid conditions, thus causing
|
||||
unwanted side effects in the physics engine.
|
||||
|
||||
By fixing the regulation system via an added binding to the internal feature,
|
||||
this commit now ensures that Godot will not go past the ebullition temperature
|
||||
of cooking oil under normal atmospheric conditions.
|
||||
```
|
||||
|
||||
**Note:** When using the GitHub online editor or its drag-and-drop
|
||||
feature, *please* edit the commit title to something meaningful. Commits named
|
||||
"Update my_file.cpp" won't be accepted.
|
||||
|
||||
### Document your changes
|
||||
|
||||
If your pull request adds methods, properties or signals that are exposed to
|
||||
scripting APIs, you **must** update the class reference to document those.
|
||||
This is to ensure the documentation coverage doesn't decrease as contributions
|
||||
are merged.
|
||||
|
||||
[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html)
|
||||
using your compiled binary, then fill in the descriptions.
|
||||
Follow the style guide described in the
|
||||
[Documentation writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html).
|
||||
|
||||
If your pull request modifies parts of the code in a non-obvious way, make sure
|
||||
to add comments in the code as well. This helps other people understand the
|
||||
change without having to dive into the Git history.
|
||||
|
||||
### Write unit tests
|
||||
|
||||
When fixing a bug or contributing a new feature, we recommend including unit
|
||||
tests in the same commit as the rest of the pull request. Unit tests are pieces
|
||||
of code that compare the output to a predetermined *expected result* to detect
|
||||
regressions. Tests are compiled and run on GitHub Actions for every commit and
|
||||
pull request.
|
||||
|
||||
Pull requests that include tests are more likely to be merged, since we can have
|
||||
greater confidence in them not being the target of regressions in the future.
|
||||
|
||||
For bugs, the unit tests should cover the functionality that was previously
|
||||
broken. If done well, this ensures regressions won't appear in the future
|
||||
again. For new features, the unit tests should cover the newly added
|
||||
functionality, testing both the "success" and "expected failure" cases if
|
||||
applicable.
|
||||
|
||||
Feel free to contribute standalone pull requests to add new tests or improve
|
||||
existing tests as well.
|
||||
|
||||
See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html)
|
||||
for information on writing tests in Godot's C++ codebase.
|
||||
|
||||
## Contributing to Godot translations
|
||||
|
||||
You can contribute to Godot translations on [Hosted Weblate](https://hosted.weblate.org/projects/godot-engine/),
|
||||
an open source and web-based translation platform.
|
||||
|
||||
Please refer to our [editor and documentation localization guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/editor_and_docs_localization.html)
|
||||
for an overview of the translation resources and what they correspond to.
|
||||
|
||||
## Communicating with developers
|
||||
|
||||
The Godot Engine community has [many communication
|
||||
channels](https://godotengine.org/community), some used more for user-level
|
||||
discussions and support, others more for development discussions.
|
||||
|
||||
To communicate with developers (e.g. to discuss a feature you want to implement
|
||||
or a bug you want to fix), the following channels can be used:
|
||||
|
||||
- [Godot Contributors Chat](https://chat.godotengine.org): You will
|
||||
find most core developers there, so it's the go-to platform for direct chat
|
||||
about Godot Engine development. Browse the [Directory](https://chat.godotengine.org/directory/channels)
|
||||
for an overview of public channels focusing on various engine areas which you
|
||||
might be interested in.
|
||||
- [Bug tracker](https://github.com/godotengine/godot/issues): If there is an
|
||||
existing issue about a topic you want to discuss, you can participate directly.
|
||||
If not, you can open a new issue. Please mind the guidelines outlined above
|
||||
for bug reporting.
|
||||
- [Feature proposals](https://github.com/godotengine/godot-proposals/issues):
|
||||
To propose a new feature, we have a dedicated issue tracker for that. Don't
|
||||
hesitate to start by talking about your idea on the Godot Contributors Chat
|
||||
to make sure that it makes sense in Godot's context.
|
||||
|
||||
Thanks for your interest in contributing!
|
||||
|
||||
—The Godot development team
|
2209
engine/COPYRIGHT.txt
2209
engine/COPYRIGHT.txt
File diff suppressed because it is too large
Load diff
293
engine/DONORS.md
293
engine/DONORS.md
|
@ -1,293 +0,0 @@
|
|||
# Donors to the Godot Engine project
|
||||
|
||||
Godot Engine is a non-profit project developed by a community of voluntary
|
||||
contributors, as well as occasional paid contributors thanks to the financial
|
||||
support of generous donors.
|
||||
|
||||
The ways to donate to the project, as well as details on how the funds are
|
||||
used, are described on [Godot's website](https://godotengine.org/donate).
|
||||
|
||||
The following is a list of the current monthly donors, who will have their
|
||||
generous deed immortalized in the next stable release of Godot Engine.
|
||||
|
||||
## Patrons
|
||||
|
||||
Khronos® Group <https://www.khronos.org/>
|
||||
OSS Capital <https://oss.capital/>
|
||||
|
||||
## Platinum sponsors
|
||||
|
||||
Scorewarrior <https://scwr.gg/godot>
|
||||
V-Sekai <https://github.com/V-Sekai>
|
||||
W4 Games <https://w4games.com/>
|
||||
|
||||
## Gold sponsors
|
||||
|
||||
Mega Crit <https://www.megacrit.com/>
|
||||
Prehensile Tales <https://prehensile-tales.com>
|
||||
Robot Gentleman <http://robotgentleman.com/>
|
||||
|
||||
## Silver sponsors
|
||||
|
||||
Bippinbits <https://bippinbits.com/>
|
||||
Broken Rules <https://brokenrul.es>
|
||||
Chasing Carrots <https://www.chasing-carrots.com>
|
||||
Copia Wealth Studios <https://copiawealthstudios.com/>
|
||||
LoadComplete <https://loadcomplete.com/>
|
||||
Null <https://null.com/>
|
||||
Orbital Knight <https://www.orbitalknight.com/>
|
||||
Playful Studios <https://playfulstudios.com/>
|
||||
Re-Logic <https://re-logic.com/>
|
||||
|
||||
## Diamond members
|
||||
|
||||
ASIFA-Hollywood <https://www.asifa-hollywood.org/>
|
||||
Christina Coffin <https://bsky.app/profile/christinacoffin.bsky.social>
|
||||
Dominic Harris <https://wayfarer-games.com/>
|
||||
Kiri "ExpiredPopsicle" Artemis <https://expiredpopsicle.com/>
|
||||
Petr Kharitonov <https://petrkharitonov.com/>
|
||||
Seats.aero <https://seats.aero/>
|
||||
Sylv <https://rankith.itch.io/unnamed-space-idle-prototype>
|
||||
And 5 anonymous donors
|
||||
|
||||
## Titanium members
|
||||
|
||||
Adriaan de Jongh <https://adriaan.games>
|
||||
Basically Games
|
||||
Draknek & Friends <https://www.draknek.org/>
|
||||
Garry Newman
|
||||
Gigabrain AI Reddit Search Engine <https://thegigabrain.com/?utm_source=godot>
|
||||
Jettelly <https://jettelly.com/>
|
||||
Justo Delgado Baudí <https://portfolio.mrcdk.com/>
|
||||
Kenney <https://kenney.nl/>
|
||||
Lucid Silence Games
|
||||
Matthew Hall <https://crossyroad.com/>
|
||||
PolyMars <https://polymars.dev/>
|
||||
Purple Moss Collectors <https://purplemosscollectors.com/>
|
||||
RPG in a Box <https://www.rpginabox.com>
|
||||
Starkandco <https://github.com/Starkandco>
|
||||
Studio Sunshower <https://www.studiosunshower.com/>
|
||||
TrampolineTales <https://TrampolineTales.com/>
|
||||
粟二华 (Su Erhua)
|
||||
And 4 anonymous donors
|
||||
|
||||
## Platinum members
|
||||
|
||||
Andy Touch
|
||||
BlockImperiumGames (BIG)
|
||||
Bytten Studio
|
||||
Christopher Shifflett
|
||||
Cody Bentley
|
||||
Darrin Massena
|
||||
Fabio Alessandrelli
|
||||
HP van Braam
|
||||
iCommitGames
|
||||
Jason Hamilton
|
||||
Jonah Stich
|
||||
Josh Anthony
|
||||
Ludvig Temperli Risan
|
||||
Matthew Ekenstedt
|
||||
Memories in 8Bit
|
||||
Michael Martin
|
||||
Mike King
|
||||
Neal Gompa (Conan Kudo)
|
||||
Nico Ulriksen
|
||||
Nikita Blizniuk
|
||||
Raptor85
|
||||
Rémi Verschelde
|
||||
Ronnie Cheng
|
||||
Ryan Heath
|
||||
ShikadiGum
|
||||
Silver Creek Entertainment
|
||||
Stephan Kessler
|
||||
Stephen Rice
|
||||
And 14 anonymous donors
|
||||
|
||||
## Gold members
|
||||
|
||||
2 Nerdy Nerds
|
||||
73unny
|
||||
80px
|
||||
Abigail F.
|
||||
Admiral Potato
|
||||
afreytes
|
||||
AinaVT
|
||||
Ajat BlackSun
|
||||
Alex177Alex
|
||||
alMoo Games
|
||||
Alva Majo
|
||||
Andrew Eiche
|
||||
Antti Vesanen
|
||||
Arediss
|
||||
Asher Glick
|
||||
Axthelm
|
||||
BangTheWall
|
||||
Benito
|
||||
Benjamin Bridges
|
||||
Ben Rog-Wilhelm
|
||||
BetaTester704
|
||||
Brut
|
||||
Bryce Dixon
|
||||
Carlo Cabanilla
|
||||
Carlo del Mundo
|
||||
Carl van der Geest
|
||||
Chocolate Software
|
||||
Chris Backas
|
||||
Chris Lambson
|
||||
Christine Elisabeth Koppel
|
||||
Cindy Trieu
|
||||
ClarkThyLord
|
||||
Codex404
|
||||
cora
|
||||
Daniel Eichler
|
||||
Daniel Krafft
|
||||
Datzju
|
||||
David Chen Zhen
|
||||
David Coles
|
||||
David Hubber
|
||||
David Snopek
|
||||
Deakcor
|
||||
Delton Ding
|
||||
dgehrig
|
||||
Disco Cat
|
||||
Distorted Realities
|
||||
DitherDream
|
||||
Dominik Frizel
|
||||
Don't You Know Who I Am? Inc.
|
||||
Dustuu
|
||||
Dylan Dromard
|
||||
Edelweiss
|
||||
eelSkillz
|
||||
Emily Flion
|
||||
Ends
|
||||
Eren Ogrul
|
||||
Eric Brand
|
||||
Eric Phy
|
||||
Faisal Al-Kubaisi (QatariGameDev)
|
||||
Fanny Pack Studios
|
||||
Felix Adam
|
||||
FeralBytes
|
||||
Francisco Aliaga
|
||||
Francis Jasmin
|
||||
Frozen Fractal
|
||||
Gaudipern
|
||||
GetIntoGameDev
|
||||
GlassBrick
|
||||
Grau
|
||||
Grzegorz Wereszko
|
||||
Guangzhou Lingchan
|
||||
Guilherme Cattani
|
||||
Hayden Oliver
|
||||
hiulit
|
||||
https://domi.zip
|
||||
Huedeane
|
||||
Ikuti
|
||||
Illyan
|
||||
I.M.I.Self
|
||||
Immaculate Lift Studio
|
||||
Intrepid Marmot LLC
|
||||
Isaac Marovitz
|
||||
Ivan Tabashki
|
||||
jakemiki
|
||||
Jam
|
||||
Jason Cawood
|
||||
Jeff Hungerford
|
||||
Jesús Chicharro
|
||||
Johannes Wuensch
|
||||
John Gabriel
|
||||
Jonas Yamazaki
|
||||
Jonathan
|
||||
José Canepa
|
||||
Julian Todd
|
||||
Justin Laster
|
||||
Justin Sasso
|
||||
Kalydi Balázs
|
||||
KAR Games
|
||||
Kiryonn
|
||||
kodebold
|
||||
KOGA Mitsuhiro (@shiena)
|
||||
korinVR
|
||||
Kristian Kriehl
|
||||
KyletheDab
|
||||
Lars Thießen
|
||||
Lisandro Lorea (Red Mage Games)
|
||||
Logan Apple
|
||||
Luca Junge
|
||||
LyaaaaaGames
|
||||
m1n1ster
|
||||
Madison Nicole Videogames
|
||||
Mara Huldra
|
||||
Marek Belski
|
||||
Martin Šenkeřík
|
||||
Matthias B.
|
||||
Michael Alexsander
|
||||
Michael Gooch
|
||||
Michael Harrington
|
||||
Modus Ponens
|
||||
Moshe Harris
|
||||
Moth Soup
|
||||
Mr. Byte
|
||||
Muscarian Softworks
|
||||
Nassor Paulino da Silva
|
||||
Neuroticfly Games
|
||||
nezticle
|
||||
nikkehtine
|
||||
Niklas Wahrman
|
||||
Nitzan Bueno
|
||||
NotNet
|
||||
Oathbringer
|
||||
Officine Pixel
|
||||
ohanaya3
|
||||
Okatima AB
|
||||
Oscar Robin
|
||||
ovym
|
||||
Patrick Traynor
|
||||
Péter Horváth-Lázár
|
||||
Petr Maláč
|
||||
pirey
|
||||
protogames
|
||||
Rafa Laguna
|
||||
Reid Hannaford
|
||||
@reilaos
|
||||
Request
|
||||
re:thinc
|
||||
Richard Ivánek
|
||||
Robin Ward
|
||||
Ronny Mühle
|
||||
Rubén Rüger
|
||||
Samuel Judd
|
||||
Santi_FC
|
||||
Seref Karahan
|
||||
shazzner
|
||||
Shiny Shinken
|
||||
Silverclad Studios
|
||||
Skie Radscale
|
||||
Snow Diamond
|
||||
Sofox
|
||||
Space Kraken Studios
|
||||
Spoony Panda
|
||||
tenuki
|
||||
ThatGamer
|
||||
Thomas Lobig
|
||||
Tobias Bocanegra
|
||||
Tom Langwaldt
|
||||
Trevor Slocum
|
||||
tukon
|
||||
twitch.tv/RobitussinMD
|
||||
Tyler C
|
||||
Urban Protagonist
|
||||
Vincent Foulon
|
||||
Vojtech Lacina
|
||||
Voxel Floof
|
||||
Watchinofoye
|
||||
Yannick
|
||||
zikes
|
||||
Zoey Smith
|
||||
嗯大爷
|
||||
|
||||
And 143 anonymous donors
|
||||
|
||||
## Silver and bronze donors
|
||||
|
||||
There are even more donors that support the project with a small monthly donation.
|
||||
Every bit counts and we thank every one of them for their amazing support!
|
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md).
|
||||
Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,5 +0,0 @@
|
|||
Godot Engine Logo
|
||||
Copyright (c) 2017 Andrea Calabró
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 4.0 International
|
||||
license (CC BY 4.0 International): https://creativecommons.org/licenses/by/4.0/
|
|
@ -1,78 +0,0 @@
|
|||
# Godot Engine
|
||||
|
||||
<p align="center">
|
||||
<a href="https://godotengine.org">
|
||||
<img src="logo_outlined.svg" width="400" alt="Godot Engine logo">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 2D and 3D cross-platform game engine
|
||||
|
||||
**[Godot Engine](https://godotengine.org) is a feature-packed, cross-platform
|
||||
game engine to create 2D and 3D games from a unified interface.** It provides a
|
||||
comprehensive set of [common tools](https://godotengine.org/features), so that
|
||||
users can focus on making games without having to reinvent the wheel. Games can
|
||||
be exported with one click to a number of platforms, including the major desktop
|
||||
platforms (Linux, macOS, Windows), mobile platforms (Android, iOS), as well as
|
||||
Web-based platforms and [consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html).
|
||||
|
||||
## Free, open source and community-driven
|
||||
|
||||
Godot is completely free and open source under the very permissive [MIT license](https://godotengine.org/license).
|
||||
No strings attached, no royalties, nothing. The users' games are theirs, down
|
||||
to the last line of engine code. Godot's development is fully independent and
|
||||
community-driven, empowering users to help shape their engine to match their
|
||||
expectations. It is supported by the [Godot Foundation](https://godot.foundation/)
|
||||
not-for-profit.
|
||||
|
||||
Before being open sourced in [February 2014](https://github.com/godotengine/godot/commit/0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac),
|
||||
Godot had been developed by [Juan Linietsky](https://github.com/reduz) and
|
||||
[Ariel Manzur](https://github.com/punto-) (both still maintaining the project)
|
||||
for several years as an in-house engine, used to publish several work-for-hire
|
||||
titles.
|
||||
|
||||

|
||||
|
||||
## Getting the engine
|
||||
|
||||
### Binary downloads
|
||||
|
||||
Official binaries for the Godot editor and the export templates can be found
|
||||
[on the Godot website](https://godotengine.org/download).
|
||||
|
||||
### Compiling from source
|
||||
|
||||
[See the official docs](https://docs.godotengine.org/en/latest/contributing/development/compiling)
|
||||
for compilation instructions for every supported platform.
|
||||
|
||||
## Community and contributing
|
||||
|
||||
Godot is not only an engine but an ever-growing community of users and engine
|
||||
developers. The main community channels are listed [on the homepage](https://godotengine.org/community).
|
||||
|
||||
The best way to get in touch with the core engine developers is to join the
|
||||
[Godot Contributors Chat](https://chat.godotengine.org).
|
||||
|
||||
To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md).
|
||||
This document also includes guidelines for reporting bugs.
|
||||
|
||||
## Documentation and demos
|
||||
|
||||
The official documentation is hosted on [Read the Docs](https://docs.godotengine.org).
|
||||
It is maintained by the Godot community in its own [GitHub repository](https://github.com/godotengine/godot-docs).
|
||||
|
||||
The [class reference](https://docs.godotengine.org/en/latest/classes/)
|
||||
is also accessible from the Godot editor.
|
||||
|
||||
We also maintain official demos in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
|
||||
as well as a list of [awesome Godot community resources](https://github.com/godotengine/awesome-godot).
|
||||
|
||||
There are also a number of other
|
||||
[learning resources](https://docs.godotengine.org/en/latest/community/tutorials.html)
|
||||
provided by the community, such as text and video tutorials, demos, etc.
|
||||
Consult the [community channels](https://godotengine.org/community)
|
||||
for more information.
|
||||
|
||||
[](https://www.codetriage.com/godotengine/godot)
|
||||
[](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
|
||||
[](https://www.tickgit.com/browse?repo=github.com/godotengine/godot)
|
1092
engine/SConstruct
1092
engine/SConstruct
File diff suppressed because it is too large
Load diff
|
@ -1,301 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
import os
|
||||
|
||||
import core_builders
|
||||
|
||||
import methods
|
||||
|
||||
env.core_sources = []
|
||||
|
||||
# Add required thirdparty code.
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
env_thirdparty = env.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
||||
# Misc thirdparty code: header paths are hardcoded, we don't need to append
|
||||
# to the include path (saves a few chars on the compiler invocation for touchy MSVC...)
|
||||
thirdparty_misc_dir = "#thirdparty/misc/"
|
||||
thirdparty_misc_sources = [
|
||||
# C sources
|
||||
"fastlz.c",
|
||||
"r128.c",
|
||||
"smaz.c",
|
||||
# C++ sources
|
||||
"pcg.cpp",
|
||||
"polypartition.cpp",
|
||||
"smolv.cpp",
|
||||
]
|
||||
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
|
||||
|
||||
# Brotli
|
||||
if env["brotli"] and env["builtin_brotli"]:
|
||||
thirdparty_brotli_dir = "#thirdparty/brotli/"
|
||||
thirdparty_brotli_sources = [
|
||||
"common/constants.c",
|
||||
"common/context.c",
|
||||
"common/dictionary.c",
|
||||
"common/platform.c",
|
||||
"common/shared_dictionary.c",
|
||||
"common/transform.c",
|
||||
"dec/bit_reader.c",
|
||||
"dec/decode.c",
|
||||
"dec/huffman.c",
|
||||
"dec/state.c",
|
||||
]
|
||||
thirdparty_brotli_sources = [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
|
||||
|
||||
env_thirdparty.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
|
||||
env.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
|
||||
|
||||
if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
|
||||
env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_brotli_sources)
|
||||
|
||||
# Clipper2 Thirdparty source files used for polygon and polyline boolean operations.
|
||||
if env["builtin_clipper2"]:
|
||||
thirdparty_clipper_dir = "#thirdparty/clipper2/"
|
||||
thirdparty_clipper_sources = [
|
||||
"src/clipper.engine.cpp",
|
||||
"src/clipper.offset.cpp",
|
||||
"src/clipper.rectclip.cpp",
|
||||
]
|
||||
thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources]
|
||||
|
||||
env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
|
||||
env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
|
||||
|
||||
env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
|
||||
env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_clipper_sources)
|
||||
|
||||
# Zlib library, can be unbundled
|
||||
if env["builtin_zlib"]:
|
||||
thirdparty_zlib_dir = "#thirdparty/zlib/"
|
||||
thirdparty_zlib_sources = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"crc32.c",
|
||||
"deflate.c",
|
||||
"inffast.c",
|
||||
"inflate.c",
|
||||
"inftrees.c",
|
||||
"trees.c",
|
||||
"uncompr.c",
|
||||
"zutil.c",
|
||||
]
|
||||
thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
|
||||
|
||||
env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
|
||||
# Needs to be available in main env too
|
||||
env.Prepend(CPPPATH=[thirdparty_zlib_dir])
|
||||
if env.dev_build:
|
||||
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
|
||||
# Affects headers so it should also be defined for Godot code
|
||||
env.Append(CPPDEFINES=["ZLIB_DEBUG"])
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
|
||||
|
||||
# Minizip library, could be unbundled in theory
|
||||
# However, our version has some custom modifications, so it won't compile with the system one
|
||||
thirdparty_minizip_dir = "#thirdparty/minizip/"
|
||||
thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
|
||||
thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_minizip_sources)
|
||||
|
||||
# Zstd library, can be unbundled in theory
|
||||
# though we currently use some private symbols
|
||||
# https://github.com/godotengine/godot/issues/17374
|
||||
if env["builtin_zstd"]:
|
||||
thirdparty_zstd_dir = "#thirdparty/zstd/"
|
||||
thirdparty_zstd_sources = [
|
||||
"common/debug.c",
|
||||
"common/entropy_common.c",
|
||||
"common/error_private.c",
|
||||
"common/fse_decompress.c",
|
||||
"common/pool.c",
|
||||
"common/threading.c",
|
||||
"common/xxhash.c",
|
||||
"common/zstd_common.c",
|
||||
"compress/fse_compress.c",
|
||||
"compress/hist.c",
|
||||
"compress/huf_compress.c",
|
||||
"compress/zstd_compress.c",
|
||||
"compress/zstd_double_fast.c",
|
||||
"compress/zstd_fast.c",
|
||||
"compress/zstd_lazy.c",
|
||||
"compress/zstd_ldm.c",
|
||||
"compress/zstd_opt.c",
|
||||
"compress/zstdmt_compress.c",
|
||||
"compress/zstd_compress_literals.c",
|
||||
"compress/zstd_compress_sequences.c",
|
||||
"compress/zstd_compress_superblock.c",
|
||||
"decompress/huf_decompress.c",
|
||||
"decompress/zstd_ddict.c",
|
||||
"decompress/zstd_decompress_block.c",
|
||||
"decompress/zstd_decompress.c",
|
||||
]
|
||||
if env["platform"] in ["android", "ios", "linuxbsd", "macos"] and env["arch"] == "x86_64":
|
||||
# Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
|
||||
thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
|
||||
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
|
||||
|
||||
env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
|
||||
env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
|
||||
env.Prepend(CPPPATH=thirdparty_zstd_dir)
|
||||
# Also needed in main env includes will trigger warnings
|
||||
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zstd_sources)
|
||||
|
||||
|
||||
env.core_sources += thirdparty_obj
|
||||
|
||||
|
||||
# Godot source files
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
||||
|
||||
|
||||
# Generate disabled classes
|
||||
def disabled_class_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
for c in source[0].read():
|
||||
cs = c.strip()
|
||||
if cs != "":
|
||||
file.write(f"#define ClassDB_Disable_{cs} 1\n")
|
||||
|
||||
|
||||
env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
|
||||
|
||||
|
||||
# Generate version info
|
||||
def version_info_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
file.write(
|
||||
"""\
|
||||
#define VERSION_SHORT_NAME "{short_name}"
|
||||
#define VERSION_NAME "{name}"
|
||||
#define VERSION_MAJOR {major}
|
||||
#define VERSION_MINOR {minor}
|
||||
#define VERSION_PATCH {patch}
|
||||
#define VERSION_STATUS "{status}"
|
||||
#define VERSION_BUILD "{build}"
|
||||
#define VERSION_MODULE_CONFIG "{module_config}"
|
||||
#define VERSION_WEBSITE "{website}"
|
||||
#define VERSION_DOCS_BRANCH "{docs_branch}"
|
||||
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
|
||||
""".format(**env.version_info)
|
||||
)
|
||||
|
||||
|
||||
env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder))
|
||||
|
||||
|
||||
# Generate version hash
|
||||
def version_hash_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
file.write(
|
||||
"""\
|
||||
#include "core/version.h"
|
||||
|
||||
const char *const VERSION_HASH = "{git_hash}";
|
||||
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
|
||||
""".format(**env.version_info)
|
||||
)
|
||||
|
||||
|
||||
gen_hash = env.CommandNoCache(
|
||||
"version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
|
||||
)
|
||||
env.add_source_files(env.core_sources, gen_hash)
|
||||
|
||||
|
||||
# Generate AES256 script encryption key
|
||||
def encryption_key_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
file.write(
|
||||
f"""\
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
uint8_t script_encryption_key[32] = {{
|
||||
{source[0]}
|
||||
}};"""
|
||||
)
|
||||
|
||||
|
||||
gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
|
||||
ec_valid = len(gdkey) == 64
|
||||
if ec_valid:
|
||||
try:
|
||||
gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
|
||||
except Exception:
|
||||
ec_valid = False
|
||||
if not ec_valid:
|
||||
methods.print_error(
|
||||
f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
|
||||
"Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
|
||||
"or make sure that it contains exactly 64 hexadecimal characters."
|
||||
)
|
||||
Exit(255)
|
||||
gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
|
||||
env.add_source_files(env.core_sources, gen_encrypt)
|
||||
|
||||
|
||||
# Certificates
|
||||
env.Depends(
|
||||
"#core/io/certs_compressed.gen.h",
|
||||
["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
|
||||
)
|
||||
env.CommandNoCache(
|
||||
"#core/io/certs_compressed.gen.h",
|
||||
"#thirdparty/certs/ca-certificates.crt",
|
||||
env.Run(core_builders.make_certs_header),
|
||||
)
|
||||
|
||||
# Authors
|
||||
env.Depends("#core/authors.gen.h", "../AUTHORS.md")
|
||||
env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header))
|
||||
|
||||
# Donors
|
||||
env.Depends("#core/donors.gen.h", "../DONORS.md")
|
||||
env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header))
|
||||
|
||||
# License
|
||||
env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
|
||||
env.CommandNoCache(
|
||||
"#core/license.gen.h",
|
||||
["../COPYRIGHT.txt", "../LICENSE.txt"],
|
||||
env.Run(core_builders.make_license_header),
|
||||
)
|
||||
|
||||
# Chain load SCsubs
|
||||
SConscript("os/SCsub")
|
||||
SConscript("math/SCsub")
|
||||
SConscript("crypto/SCsub")
|
||||
SConscript("io/SCsub")
|
||||
SConscript("debugger/SCsub")
|
||||
SConscript("input/SCsub")
|
||||
SConscript("variant/SCsub")
|
||||
SConscript("extension/SCsub")
|
||||
SConscript("object/SCsub")
|
||||
SConscript("templates/SCsub")
|
||||
SConscript("string/SCsub")
|
||||
SConscript("config/SCsub")
|
||||
SConscript("error/SCsub")
|
||||
|
||||
|
||||
# Build it all as a library
|
||||
lib = env.add_library("core", env.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
||||
|
||||
# Needed to force rebuilding the core files when the thirdparty code is updated.
|
||||
env.Depends(lib, thirdparty_obj)
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_config = env.Clone()
|
||||
|
||||
env_config.add_source_files(env.core_sources, "*.cpp")
|
|
@ -1,446 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
#include "core/authors.gen.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/donors.gen.h"
|
||||
#include "core/license.gen.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
#include "core/version.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
void Engine::set_physics_ticks_per_second(int p_ips) {
|
||||
ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
|
||||
ips = p_ips;
|
||||
}
|
||||
|
||||
int Engine::get_physics_ticks_per_second() const {
|
||||
return ips;
|
||||
}
|
||||
|
||||
void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
|
||||
ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
|
||||
max_physics_steps_per_frame = p_max_physics_steps;
|
||||
}
|
||||
|
||||
int Engine::get_max_physics_steps_per_frame() const {
|
||||
return max_physics_steps_per_frame;
|
||||
}
|
||||
|
||||
void Engine::set_physics_jitter_fix(double p_threshold) {
|
||||
if (p_threshold < 0) {
|
||||
p_threshold = 0;
|
||||
}
|
||||
physics_jitter_fix = p_threshold;
|
||||
}
|
||||
|
||||
double Engine::get_physics_jitter_fix() const {
|
||||
return physics_jitter_fix;
|
||||
}
|
||||
|
||||
void Engine::set_max_fps(int p_fps) {
|
||||
_max_fps = p_fps > 0 ? p_fps : 0;
|
||||
|
||||
RenderingDevice *rd = RenderingDevice::get_singleton();
|
||||
if (rd) {
|
||||
rd->_set_max_fps(_max_fps);
|
||||
}
|
||||
}
|
||||
|
||||
int Engine::get_max_fps() const {
|
||||
return _max_fps;
|
||||
}
|
||||
|
||||
void Engine::set_audio_output_latency(int p_msec) {
|
||||
_audio_output_latency = p_msec > 1 ? p_msec : 1;
|
||||
}
|
||||
|
||||
int Engine::get_audio_output_latency() const {
|
||||
return _audio_output_latency;
|
||||
}
|
||||
|
||||
void Engine::increment_frames_drawn() {
|
||||
if (frame_server_synced) {
|
||||
server_syncs++;
|
||||
} else {
|
||||
server_syncs = 0;
|
||||
}
|
||||
frame_server_synced = false;
|
||||
|
||||
frames_drawn++;
|
||||
}
|
||||
|
||||
uint64_t Engine::get_frames_drawn() {
|
||||
return frames_drawn;
|
||||
}
|
||||
|
||||
void Engine::set_frame_delay(uint32_t p_msec) {
|
||||
_frame_delay = p_msec;
|
||||
}
|
||||
|
||||
uint32_t Engine::get_frame_delay() const {
|
||||
return _frame_delay;
|
||||
}
|
||||
|
||||
void Engine::set_time_scale(double p_scale) {
|
||||
_time_scale = p_scale;
|
||||
}
|
||||
|
||||
double Engine::get_time_scale() const {
|
||||
return freeze_time_scale ? 0 : _time_scale;
|
||||
}
|
||||
|
||||
double Engine::get_unfrozen_time_scale() const {
|
||||
return _time_scale;
|
||||
}
|
||||
|
||||
Dictionary Engine::get_version_info() const {
|
||||
Dictionary dict;
|
||||
dict["major"] = VERSION_MAJOR;
|
||||
dict["minor"] = VERSION_MINOR;
|
||||
dict["patch"] = VERSION_PATCH;
|
||||
dict["hex"] = VERSION_HEX;
|
||||
dict["status"] = VERSION_STATUS;
|
||||
dict["build"] = VERSION_BUILD;
|
||||
|
||||
String hash = String(VERSION_HASH);
|
||||
dict["hash"] = hash.is_empty() ? String("unknown") : hash;
|
||||
|
||||
dict["timestamp"] = VERSION_TIMESTAMP;
|
||||
|
||||
String stringver = String(dict["major"]) + "." + String(dict["minor"]);
|
||||
if ((int)dict["patch"] != 0) {
|
||||
stringver += "." + String(dict["patch"]);
|
||||
}
|
||||
stringver += "-" + String(dict["status"]) + " (" + String(dict["build"]) + ")";
|
||||
dict["string"] = stringver;
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static Array array_from_info(const char *const *info_list) {
|
||||
Array arr;
|
||||
for (int i = 0; info_list[i] != nullptr; i++) {
|
||||
arr.push_back(String::utf8(info_list[i]));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
static Array array_from_info_count(const char *const *info_list, int info_count) {
|
||||
Array arr;
|
||||
for (int i = 0; i < info_count; i++) {
|
||||
arr.push_back(String::utf8(info_list[i]));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
Dictionary Engine::get_author_info() const {
|
||||
Dictionary dict;
|
||||
|
||||
dict["lead_developers"] = array_from_info(AUTHORS_LEAD_DEVELOPERS);
|
||||
dict["project_managers"] = array_from_info(AUTHORS_PROJECT_MANAGERS);
|
||||
dict["founders"] = array_from_info(AUTHORS_FOUNDERS);
|
||||
dict["developers"] = array_from_info(AUTHORS_DEVELOPERS);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> Engine::get_copyright_info() const {
|
||||
TypedArray<Dictionary> components;
|
||||
for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
|
||||
const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
|
||||
Dictionary component_dict;
|
||||
component_dict["name"] = String::utf8(cp_info.name);
|
||||
Array parts;
|
||||
for (int i = 0; i < cp_info.part_count; i++) {
|
||||
const ComponentCopyrightPart &cp_part = cp_info.parts[i];
|
||||
Dictionary part_dict;
|
||||
part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count);
|
||||
part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count);
|
||||
part_dict["license"] = String::utf8(cp_part.license);
|
||||
parts.push_back(part_dict);
|
||||
}
|
||||
component_dict["parts"] = parts;
|
||||
|
||||
components.push_back(component_dict);
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
Dictionary Engine::get_donor_info() const {
|
||||
Dictionary donors;
|
||||
donors["patrons"] = array_from_info(DONORS_PATRONS);
|
||||
donors["platinum_sponsors"] = array_from_info(DONORS_SPONSORS_PLATINUM);
|
||||
donors["gold_sponsors"] = array_from_info(DONORS_SPONSORS_GOLD);
|
||||
donors["silver_sponsors"] = array_from_info(DONORS_SPONSORS_SILVER);
|
||||
donors["diamond_members"] = array_from_info(DONORS_MEMBERS_DIAMOND);
|
||||
donors["titanium_members"] = array_from_info(DONORS_MEMBERS_TITANIUM);
|
||||
donors["platinum_members"] = array_from_info(DONORS_MEMBERS_PLATINUM);
|
||||
donors["gold_members"] = array_from_info(DONORS_MEMBERS_GOLD);
|
||||
return donors;
|
||||
}
|
||||
|
||||
Dictionary Engine::get_license_info() const {
|
||||
Dictionary licenses;
|
||||
for (int i = 0; i < LICENSE_COUNT; i++) {
|
||||
licenses[LICENSE_NAMES[i]] = LICENSE_BODIES[i];
|
||||
}
|
||||
return licenses;
|
||||
}
|
||||
|
||||
String Engine::get_license_text() const {
|
||||
return String(GODOT_LICENSE_TEXT);
|
||||
}
|
||||
|
||||
String Engine::get_architecture_name() const {
|
||||
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
|
||||
return "x86_64";
|
||||
|
||||
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
return "x86_32";
|
||||
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
return "arm64";
|
||||
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
return "arm32";
|
||||
|
||||
#elif defined(__riscv)
|
||||
#if __riscv_xlen == 8
|
||||
return "rv64";
|
||||
#else
|
||||
return "riscv";
|
||||
#endif
|
||||
|
||||
#elif defined(__powerpc__)
|
||||
#if defined(__powerpc64__)
|
||||
return "ppc64";
|
||||
#else
|
||||
return "ppc";
|
||||
#endif
|
||||
|
||||
#elif defined(__loongarch64)
|
||||
return "loongarch64";
|
||||
|
||||
#elif defined(__wasm__)
|
||||
#if defined(__wasm64__)
|
||||
return "wasm64";
|
||||
#elif defined(__wasm32__)
|
||||
return "wasm32";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Engine::is_abort_on_gpu_errors_enabled() const {
|
||||
return abort_on_gpu_errors;
|
||||
}
|
||||
|
||||
int32_t Engine::get_gpu_index() const {
|
||||
return gpu_idx;
|
||||
}
|
||||
|
||||
bool Engine::is_validation_layers_enabled() const {
|
||||
return use_validation_layers;
|
||||
}
|
||||
|
||||
bool Engine::is_generate_spirv_debug_info_enabled() const {
|
||||
return generate_spirv_debug_info;
|
||||
}
|
||||
|
||||
bool Engine::is_extra_gpu_memory_tracking_enabled() const {
|
||||
return extra_gpu_memory_tracking;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
|
||||
bool Engine::is_accurate_breadcrumbs_enabled() const {
|
||||
return accurate_breadcrumbs;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Engine::set_print_to_stdout(bool p_enabled) {
|
||||
CoreGlobals::print_line_enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool Engine::is_printing_to_stdout() const {
|
||||
return CoreGlobals::print_line_enabled;
|
||||
}
|
||||
|
||||
void Engine::set_print_error_messages(bool p_enabled) {
|
||||
CoreGlobals::print_error_enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool Engine::is_printing_error_messages() const {
|
||||
return CoreGlobals::print_error_enabled;
|
||||
}
|
||||
|
||||
void Engine::print_header(const String &p_string) const {
|
||||
if (_print_header) {
|
||||
print_line(p_string);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::print_header_rich(const String &p_string) const {
|
||||
if (_print_header) {
|
||||
print_line_rich(p_string);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::add_singleton(const Singleton &p_singleton) {
|
||||
ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
|
||||
singletons.push_back(p_singleton);
|
||||
singleton_ptrs[p_singleton.name] = p_singleton.ptr;
|
||||
}
|
||||
|
||||
Object *Engine::get_singleton_object(const StringName &p_name) const {
|
||||
HashMap<StringName, Object *>::ConstIterator E = singleton_ptrs.find(p_name);
|
||||
ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("Failed to retrieve non-existent singleton '%s'.", p_name));
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!is_editor_hint() && is_singleton_editor_only(p_name)) {
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Can't retrieve singleton '%s' outside of editor.", p_name));
|
||||
}
|
||||
#endif
|
||||
|
||||
return E->value;
|
||||
}
|
||||
|
||||
bool Engine::is_singleton_user_created(const StringName &p_name) const {
|
||||
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
|
||||
|
||||
for (const Singleton &E : singletons) {
|
||||
if (E.name == p_name && E.user_created) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Engine::is_singleton_editor_only(const StringName &p_name) const {
|
||||
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
|
||||
|
||||
for (const Singleton &E : singletons) {
|
||||
if (E.name == p_name && E.editor_only) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Engine::remove_singleton(const StringName &p_name) {
|
||||
ERR_FAIL_COND(!singleton_ptrs.has(p_name));
|
||||
|
||||
for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) {
|
||||
if (E->get().name == p_name) {
|
||||
singletons.erase(E);
|
||||
singleton_ptrs.erase(p_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Engine::has_singleton(const StringName &p_name) const {
|
||||
return singleton_ptrs.has(p_name);
|
||||
}
|
||||
|
||||
void Engine::get_singletons(List<Singleton> *p_singletons) {
|
||||
for (const Singleton &E : singletons) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!is_editor_hint() && E.editor_only) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
p_singletons->push_back(E);
|
||||
}
|
||||
}
|
||||
|
||||
String Engine::get_write_movie_path() const {
|
||||
return write_movie_path;
|
||||
}
|
||||
|
||||
void Engine::set_write_movie_path(const String &p_path) {
|
||||
write_movie_path = p_path;
|
||||
}
|
||||
|
||||
void Engine::set_shader_cache_path(const String &p_path) {
|
||||
shader_cache_path = p_path;
|
||||
}
|
||||
String Engine::get_shader_cache_path() const {
|
||||
return shader_cache_path;
|
||||
}
|
||||
|
||||
Engine *Engine::singleton = nullptr;
|
||||
|
||||
Engine *Engine::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
bool Engine::notify_frame_server_synced() {
|
||||
frame_server_synced = true;
|
||||
return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
|
||||
}
|
||||
|
||||
void Engine::set_freeze_time_scale(bool p_frozen) {
|
||||
freeze_time_scale = p_frozen;
|
||||
}
|
||||
|
||||
void Engine::set_embedded_in_editor(bool p_enabled) {
|
||||
embedded_in_editor = p_enabled;
|
||||
}
|
||||
|
||||
bool Engine::is_embedded_in_editor() const {
|
||||
return embedded_in_editor;
|
||||
}
|
||||
|
||||
Engine::Engine() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
Engine::~Engine() {
|
||||
if (singleton == this) {
|
||||
singleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
|
||||
name(p_name),
|
||||
ptr(p_ptr),
|
||||
class_name(p_class_name) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
|
||||
if (rc && !rc->is_referenced()) {
|
||||
WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENGINE_H
|
||||
#define ENGINE_H
|
||||
|
||||
#include "core/os/main_loop.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/list.h"
|
||||
|
||||
template <typename T>
|
||||
class TypedArray;
|
||||
|
||||
class Engine {
|
||||
public:
|
||||
struct Singleton {
|
||||
StringName name;
|
||||
Object *ptr = nullptr;
|
||||
StringName class_name; // Used for binding generation hinting.
|
||||
// Singleton scope flags.
|
||||
bool user_created = false;
|
||||
bool editor_only = false;
|
||||
|
||||
Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName());
|
||||
};
|
||||
|
||||
private:
|
||||
friend class Main;
|
||||
|
||||
uint64_t frames_drawn = 0;
|
||||
uint32_t _frame_delay = 0;
|
||||
uint64_t _frame_ticks = 0;
|
||||
double _process_step = 0;
|
||||
|
||||
int ips = 60;
|
||||
double physics_jitter_fix = 0.5;
|
||||
double _fps = 1;
|
||||
int _max_fps = 0;
|
||||
int _audio_output_latency = 0;
|
||||
double _time_scale = 1.0;
|
||||
uint64_t _physics_frames = 0;
|
||||
int max_physics_steps_per_frame = 8;
|
||||
double _physics_interpolation_fraction = 0.0f;
|
||||
bool abort_on_gpu_errors = false;
|
||||
bool use_validation_layers = false;
|
||||
bool generate_spirv_debug_info = false;
|
||||
bool extra_gpu_memory_tracking = false;
|
||||
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
|
||||
bool accurate_breadcrumbs = false;
|
||||
#endif
|
||||
int32_t gpu_idx = -1;
|
||||
|
||||
uint64_t _process_frames = 0;
|
||||
bool _in_physics = false;
|
||||
|
||||
List<Singleton> singletons;
|
||||
HashMap<StringName, Object *> singleton_ptrs;
|
||||
|
||||
bool editor_hint = false;
|
||||
bool project_manager_hint = false;
|
||||
bool extension_reloading = false;
|
||||
bool embedded_in_editor = false;
|
||||
bool recovery_mode_hint = false;
|
||||
|
||||
bool _print_header = true;
|
||||
|
||||
static Engine *singleton;
|
||||
|
||||
String write_movie_path;
|
||||
String shader_cache_path;
|
||||
|
||||
static constexpr int SERVER_SYNC_FRAME_COUNT_WARNING = 5;
|
||||
int server_syncs = 0;
|
||||
bool frame_server_synced = false;
|
||||
|
||||
bool freeze_time_scale = false;
|
||||
|
||||
public:
|
||||
static Engine *get_singleton();
|
||||
|
||||
virtual void set_physics_ticks_per_second(int p_ips);
|
||||
virtual int get_physics_ticks_per_second() const;
|
||||
|
||||
virtual void set_max_physics_steps_per_frame(int p_max_physics_steps);
|
||||
virtual int get_max_physics_steps_per_frame() const;
|
||||
|
||||
void set_physics_jitter_fix(double p_threshold);
|
||||
double get_physics_jitter_fix() const;
|
||||
|
||||
virtual void set_max_fps(int p_fps);
|
||||
virtual int get_max_fps() const;
|
||||
|
||||
virtual void set_audio_output_latency(int p_msec);
|
||||
virtual int get_audio_output_latency() const;
|
||||
|
||||
virtual double get_frames_per_second() const { return _fps; }
|
||||
|
||||
uint64_t get_frames_drawn();
|
||||
|
||||
uint64_t get_physics_frames() const { return _physics_frames; }
|
||||
uint64_t get_process_frames() const { return _process_frames; }
|
||||
bool is_in_physics_frame() const { return _in_physics; }
|
||||
uint64_t get_frame_ticks() const { return _frame_ticks; }
|
||||
double get_process_step() const { return _process_step; }
|
||||
double get_physics_interpolation_fraction() const { return _physics_interpolation_fraction; }
|
||||
|
||||
void set_time_scale(double p_scale);
|
||||
double get_time_scale() const;
|
||||
double get_unfrozen_time_scale() const;
|
||||
|
||||
void set_print_to_stdout(bool p_enabled);
|
||||
bool is_printing_to_stdout() const;
|
||||
|
||||
void set_print_error_messages(bool p_enabled);
|
||||
bool is_printing_error_messages() const;
|
||||
void print_header(const String &p_string) const;
|
||||
void print_header_rich(const String &p_string) const;
|
||||
|
||||
void set_frame_delay(uint32_t p_msec);
|
||||
uint32_t get_frame_delay() const;
|
||||
|
||||
void add_singleton(const Singleton &p_singleton);
|
||||
void get_singletons(List<Singleton> *p_singletons);
|
||||
bool has_singleton(const StringName &p_name) const;
|
||||
Object *get_singleton_object(const StringName &p_name) const;
|
||||
void remove_singleton(const StringName &p_name);
|
||||
bool is_singleton_user_created(const StringName &p_name) const;
|
||||
bool is_singleton_editor_only(const StringName &p_name) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; }
|
||||
_FORCE_INLINE_ bool is_editor_hint() const { return editor_hint; }
|
||||
|
||||
_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) { project_manager_hint = p_enabled; }
|
||||
_FORCE_INLINE_ bool is_project_manager_hint() const { return project_manager_hint; }
|
||||
|
||||
_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; }
|
||||
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return extension_reloading; }
|
||||
|
||||
_FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) { recovery_mode_hint = p_enabled; }
|
||||
_FORCE_INLINE_ bool is_recovery_mode_hint() const { return recovery_mode_hint; }
|
||||
#else
|
||||
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
|
||||
_FORCE_INLINE_ bool is_editor_hint() const { return false; }
|
||||
|
||||
_FORCE_INLINE_ void set_project_manager_hint(bool p_enabled) {}
|
||||
_FORCE_INLINE_ bool is_project_manager_hint() const { return false; }
|
||||
|
||||
_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
|
||||
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; }
|
||||
|
||||
_FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) {}
|
||||
_FORCE_INLINE_ bool is_recovery_mode_hint() const { return false; }
|
||||
#endif
|
||||
|
||||
Dictionary get_version_info() const;
|
||||
Dictionary get_author_info() const;
|
||||
TypedArray<Dictionary> get_copyright_info() const;
|
||||
Dictionary get_donor_info() const;
|
||||
Dictionary get_license_info() const;
|
||||
String get_license_text() const;
|
||||
|
||||
void set_write_movie_path(const String &p_path);
|
||||
String get_write_movie_path() const;
|
||||
|
||||
String get_architecture_name() const;
|
||||
|
||||
void set_shader_cache_path(const String &p_path);
|
||||
String get_shader_cache_path() const;
|
||||
|
||||
bool is_abort_on_gpu_errors_enabled() const;
|
||||
bool is_validation_layers_enabled() const;
|
||||
bool is_generate_spirv_debug_info_enabled() const;
|
||||
bool is_extra_gpu_memory_tracking_enabled() const;
|
||||
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
|
||||
bool is_accurate_breadcrumbs_enabled() const;
|
||||
#endif
|
||||
int32_t get_gpu_index() const;
|
||||
|
||||
void increment_frames_drawn();
|
||||
bool notify_frame_server_synced();
|
||||
|
||||
void set_freeze_time_scale(bool p_frozen);
|
||||
void set_embedded_in_editor(bool p_enabled);
|
||||
bool is_embedded_in_editor() const;
|
||||
|
||||
Engine();
|
||||
virtual ~Engine();
|
||||
};
|
||||
|
||||
#endif // ENGINE_H
|
File diff suppressed because it is too large
Load diff
|
@ -1,247 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* project_settings.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef PROJECT_SETTINGS_H
|
||||
#define PROJECT_SETTINGS_H
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
template <typename T>
|
||||
class TypedArray;
|
||||
|
||||
class ProjectSettings : public Object {
|
||||
GDCLASS(ProjectSettings, Object);
|
||||
_THREAD_SAFE_CLASS_
|
||||
friend class TestProjectSettingsInternalsAccessor;
|
||||
|
||||
bool is_changed = false;
|
||||
|
||||
public:
|
||||
typedef HashMap<String, Variant> CustomMap;
|
||||
static const String PROJECT_DATA_DIR_NAME_SUFFIX;
|
||||
|
||||
// Properties that are not for built in values begin from this value, so builtin ones are displayed first.
|
||||
constexpr static const int32_t NO_BUILTIN_ORDER_BASE = 1 << 16;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
const static PackedStringArray get_required_features();
|
||||
const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
struct AutoloadInfo {
|
||||
StringName name;
|
||||
String path;
|
||||
bool is_singleton = false;
|
||||
};
|
||||
|
||||
protected:
|
||||
struct VariantContainer {
|
||||
int order = 0;
|
||||
bool persist = false;
|
||||
bool basic = false;
|
||||
bool internal = false;
|
||||
Variant variant;
|
||||
Variant initial;
|
||||
bool hide_from_editor = false;
|
||||
bool restart_if_changed = false;
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
bool ignore_value_in_docs = false;
|
||||
#endif
|
||||
|
||||
VariantContainer() {}
|
||||
|
||||
VariantContainer(const Variant &p_variant, int p_order, bool p_persist = false) :
|
||||
order(p_order),
|
||||
persist(p_persist),
|
||||
variant(p_variant) {
|
||||
}
|
||||
};
|
||||
|
||||
int last_order = NO_BUILTIN_ORDER_BASE;
|
||||
int last_builtin_order = 0;
|
||||
uint64_t last_save_time = 0;
|
||||
|
||||
RBMap<StringName, VariantContainer> props; // NOTE: Key order is used e.g. in the save_custom method.
|
||||
String resource_path;
|
||||
HashMap<StringName, PropertyInfo> custom_prop_info;
|
||||
bool using_datapack = false;
|
||||
bool project_loaded = false;
|
||||
List<String> input_presets;
|
||||
|
||||
HashSet<String> custom_features;
|
||||
HashMap<StringName, LocalVector<Pair<StringName, StringName>>> feature_overrides;
|
||||
|
||||
LocalVector<String> hidden_prefixes;
|
||||
HashMap<StringName, AutoloadInfo> autoloads;
|
||||
HashMap<StringName, String> global_groups;
|
||||
HashMap<StringName, HashSet<StringName>> scene_groups_cache;
|
||||
|
||||
Array global_class_list;
|
||||
bool is_global_class_list_loaded = false;
|
||||
|
||||
String project_data_dir_name;
|
||||
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
bool _property_can_revert(const StringName &p_name) const;
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
|
||||
|
||||
void _queue_changed();
|
||||
void _emit_changed();
|
||||
|
||||
static ProjectSettings *singleton;
|
||||
|
||||
Error _load_settings_text(const String &p_path);
|
||||
Error _load_settings_binary(const String &p_path);
|
||||
Error _load_settings_text_or_binary(const String &p_text_path, const String &p_bin_path);
|
||||
|
||||
Error _save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
|
||||
Error _save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
|
||||
|
||||
Error _save_custom_bnd(const String &p_file);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
const static PackedStringArray _get_supported_features();
|
||||
const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
void _convert_to_last_version(int p_from_version);
|
||||
|
||||
bool load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset);
|
||||
bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0, bool p_main_pack = false);
|
||||
|
||||
void _add_property_info_bind(const Dictionary &p_info);
|
||||
|
||||
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
|
||||
|
||||
void _add_builtin_input_map();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static const int CONFIG_VERSION = 5;
|
||||
|
||||
void set_setting(const String &p_setting, const Variant &p_value);
|
||||
Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
|
||||
TypedArray<Dictionary> get_global_class_list();
|
||||
void refresh_global_class_list();
|
||||
void store_global_class_list(const Array &p_classes);
|
||||
String get_global_class_list_path() const;
|
||||
|
||||
bool has_setting(const String &p_var) const;
|
||||
String localize_path(const String &p_path) const;
|
||||
String globalize_path(const String &p_path) const;
|
||||
|
||||
void set_initial_value(const String &p_name, const Variant &p_value);
|
||||
void set_as_basic(const String &p_name, bool p_basic);
|
||||
void set_as_internal(const String &p_name, bool p_internal);
|
||||
void set_restart_if_changed(const String &p_name, bool p_restart);
|
||||
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
|
||||
bool get_ignore_value_in_docs(const String &p_name) const;
|
||||
void add_hidden_prefix(const String &p_prefix);
|
||||
|
||||
String get_project_data_dir_name() const;
|
||||
String get_project_data_path() const;
|
||||
String get_resource_path() const;
|
||||
String get_imported_files_path() const;
|
||||
|
||||
static ProjectSettings *get_singleton();
|
||||
|
||||
void clear(const String &p_name);
|
||||
int get_order(const String &p_name) const;
|
||||
void set_order(const String &p_name, int p_order);
|
||||
void set_builtin_order(const String &p_name);
|
||||
bool is_builtin_setting(const String &p_name) const;
|
||||
|
||||
Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
|
||||
|
||||
Error load_custom(const String &p_path);
|
||||
Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true);
|
||||
Error save();
|
||||
void set_custom_property_info(const PropertyInfo &p_info);
|
||||
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
|
||||
uint64_t get_last_saved_time() { return last_save_time; }
|
||||
|
||||
List<String> get_input_presets() const { return input_presets; }
|
||||
|
||||
Variant get_setting_with_override(const StringName &p_name) const;
|
||||
|
||||
bool is_using_datapack() const;
|
||||
bool is_project_loaded() const;
|
||||
|
||||
bool has_custom_feature(const String &p_feature) const;
|
||||
|
||||
const HashMap<StringName, AutoloadInfo> &get_autoload_list() const;
|
||||
void add_autoload(const AutoloadInfo &p_autoload);
|
||||
void remove_autoload(const StringName &p_autoload);
|
||||
bool has_autoload(const StringName &p_autoload) const;
|
||||
AutoloadInfo get_autoload(const StringName &p_name) const;
|
||||
|
||||
const HashMap<StringName, String> &get_global_groups_list() const;
|
||||
void add_global_group(const StringName &p_name, const String &p_description);
|
||||
void remove_global_group(const StringName &p_name);
|
||||
bool has_global_group(const StringName &p_name) const;
|
||||
|
||||
const HashMap<StringName, HashSet<StringName>> &get_scene_groups_cache() const;
|
||||
void add_scene_groups_cache(const StringName &p_path, const HashSet<StringName> &p_cache);
|
||||
void remove_scene_groups_cache(const StringName &p_path);
|
||||
void save_scene_groups_cache();
|
||||
String get_scene_groups_cache_path() const;
|
||||
void load_scene_groups_cache();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
ProjectSettings();
|
||||
ProjectSettings(const String &p_path);
|
||||
~ProjectSettings();
|
||||
};
|
||||
|
||||
// Not a macro any longer.
|
||||
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
|
||||
Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
|
||||
|
||||
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
|
||||
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
|
||||
#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
|
||||
#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
|
||||
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
|
||||
|
||||
#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
|
||||
#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
|
||||
#define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true)
|
||||
#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
|
||||
|
||||
#define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true)
|
||||
|
||||
#endif // PROJECT_SETTINGS_H
|
|
@ -1,62 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_bind.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
namespace core_bind {
|
||||
|
||||
// Semaphore
|
||||
|
||||
void Semaphore::_post_bind_compat_93605() {
|
||||
post(1);
|
||||
}
|
||||
|
||||
void Semaphore::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("post"), &Semaphore::_post_bind_compat_93605);
|
||||
}
|
||||
|
||||
// OS
|
||||
|
||||
String OS::_read_string_from_stdin_bind_compat_91201() {
|
||||
return read_string_from_stdin(1024);
|
||||
}
|
||||
|
||||
Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
|
||||
return execute_with_pipe(p_path, p_arguments, true);
|
||||
}
|
||||
|
||||
void OS::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
|
||||
}
|
||||
|
||||
} // namespace core_bind
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
File diff suppressed because it is too large
Load diff
|
@ -1,674 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_bind.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CORE_BIND_H
|
||||
#define CORE_BIND_H
|
||||
|
||||
#include "core/debugger/engine_profiler.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
class MainLoop;
|
||||
template <typename T>
|
||||
class TypedArray;
|
||||
|
||||
namespace core_bind {
|
||||
|
||||
class ResourceLoader : public Object {
|
||||
GDCLASS(ResourceLoader, Object);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static ResourceLoader *singleton;
|
||||
|
||||
public:
|
||||
enum ThreadLoadStatus {
|
||||
THREAD_LOAD_INVALID_RESOURCE,
|
||||
THREAD_LOAD_IN_PROGRESS,
|
||||
THREAD_LOAD_FAILED,
|
||||
THREAD_LOAD_LOADED
|
||||
};
|
||||
|
||||
enum CacheMode {
|
||||
CACHE_MODE_IGNORE,
|
||||
CACHE_MODE_REUSE,
|
||||
CACHE_MODE_REPLACE,
|
||||
CACHE_MODE_IGNORE_DEEP,
|
||||
CACHE_MODE_REPLACE_DEEP,
|
||||
};
|
||||
|
||||
static ResourceLoader *get_singleton() { return singleton; }
|
||||
|
||||
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, CacheMode p_cache_mode = CACHE_MODE_REUSE);
|
||||
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = ClassDB::default_array_arg);
|
||||
Ref<Resource> load_threaded_get(const String &p_path);
|
||||
|
||||
Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
|
||||
Vector<String> get_recognized_extensions_for_type(const String &p_type);
|
||||
void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front);
|
||||
void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
|
||||
void set_abort_on_missing_resources(bool p_abort);
|
||||
PackedStringArray get_dependencies(const String &p_path);
|
||||
bool has_cached(const String &p_path);
|
||||
Ref<Resource> get_cached_ref(const String &p_path);
|
||||
bool exists(const String &p_path, const String &p_type_hint = "");
|
||||
ResourceUID::ID get_resource_uid(const String &p_path);
|
||||
|
||||
Vector<String> list_directory(const String &p_directory);
|
||||
|
||||
ResourceLoader() { singleton = this; }
|
||||
};
|
||||
|
||||
class ResourceSaver : public Object {
|
||||
GDCLASS(ResourceSaver, Object);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static ResourceSaver *singleton;
|
||||
|
||||
public:
|
||||
enum SaverFlags {
|
||||
FLAG_NONE = 0,
|
||||
FLAG_RELATIVE_PATHS = 1,
|
||||
FLAG_BUNDLE_RESOURCES = 2,
|
||||
FLAG_CHANGE_PATH = 4,
|
||||
FLAG_OMIT_EDITOR_PROPERTIES = 8,
|
||||
FLAG_SAVE_BIG_ENDIAN = 16,
|
||||
FLAG_COMPRESS = 32,
|
||||
FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
|
||||
};
|
||||
|
||||
static ResourceSaver *get_singleton() { return singleton; }
|
||||
|
||||
Error save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags);
|
||||
Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
|
||||
void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
|
||||
void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
|
||||
|
||||
ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false);
|
||||
|
||||
ResourceSaver() { singleton = this; }
|
||||
};
|
||||
|
||||
class OS : public Object {
|
||||
GDCLASS(OS, Object);
|
||||
|
||||
mutable HashMap<String, bool> feature_cache;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static OS *singleton;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments);
|
||||
|
||||
String _read_string_from_stdin_bind_compat_91201();
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
enum RenderingDriver {
|
||||
RENDERING_DRIVER_VULKAN,
|
||||
RENDERING_DRIVER_OPENGL3,
|
||||
RENDERING_DRIVER_D3D12,
|
||||
RENDERING_DRIVER_METAL,
|
||||
};
|
||||
|
||||
PackedByteArray get_entropy(int p_bytes);
|
||||
String get_system_ca_certificates();
|
||||
|
||||
enum StdHandleType {
|
||||
STD_HANDLE_INVALID,
|
||||
STD_HANDLE_CONSOLE,
|
||||
STD_HANDLE_FILE,
|
||||
STD_HANDLE_PIPE,
|
||||
STD_HANDLE_UNKNOWN,
|
||||
};
|
||||
|
||||
virtual PackedStringArray get_connected_midi_inputs();
|
||||
virtual void open_midi_inputs();
|
||||
virtual void close_midi_inputs();
|
||||
|
||||
void set_low_processor_usage_mode(bool p_enabled);
|
||||
bool is_in_low_processor_usage_mode() const;
|
||||
|
||||
void set_low_processor_usage_mode_sleep_usec(int p_usec);
|
||||
int get_low_processor_usage_mode_sleep_usec() const;
|
||||
|
||||
void set_delta_smoothing(bool p_enabled);
|
||||
bool is_delta_smoothing_enabled() const;
|
||||
|
||||
void alert(const String &p_alert, const String &p_title = "ALERT!");
|
||||
void crash(const String &p_message);
|
||||
|
||||
Vector<String> get_system_fonts() const;
|
||||
String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
|
||||
Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
|
||||
String get_executable_path() const;
|
||||
|
||||
String read_string_from_stdin(int64_t p_buffer_size = 1024);
|
||||
PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024);
|
||||
StdHandleType get_stdin_type() const;
|
||||
StdHandleType get_stdout_type() const;
|
||||
StdHandleType get_stderr_type() const;
|
||||
|
||||
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false);
|
||||
Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true);
|
||||
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
|
||||
int create_instance(const Vector<String> &p_arguments);
|
||||
Error kill(int p_pid);
|
||||
Error shell_open(const String &p_uri);
|
||||
Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);
|
||||
|
||||
bool is_process_running(int p_pid) const;
|
||||
int get_process_exit_code(int p_pid) const;
|
||||
int get_process_id() const;
|
||||
|
||||
void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
|
||||
bool is_restart_on_exit_set() const;
|
||||
Vector<String> get_restart_on_exit_arguments() const;
|
||||
|
||||
bool has_environment(const String &p_var) const;
|
||||
String get_environment(const String &p_var) const;
|
||||
void set_environment(const String &p_var, const String &p_value) const;
|
||||
void unset_environment(const String &p_var) const;
|
||||
|
||||
String get_name() const;
|
||||
String get_distribution_name() const;
|
||||
String get_version() const;
|
||||
String get_version_alias() const;
|
||||
Vector<String> get_cmdline_args();
|
||||
Vector<String> get_cmdline_user_args();
|
||||
|
||||
Vector<String> get_video_adapter_driver_info() const;
|
||||
|
||||
String get_locale() const;
|
||||
String get_locale_language() const;
|
||||
|
||||
String get_model_name() const;
|
||||
|
||||
bool is_debug_build() const;
|
||||
|
||||
String get_unique_id() const;
|
||||
|
||||
String get_keycode_string(Key p_code) const;
|
||||
bool is_keycode_unicode(char32_t p_unicode) const;
|
||||
Key find_keycode_from_string(const String &p_code) const;
|
||||
|
||||
void set_use_file_access_save_and_swap(bool p_enable);
|
||||
|
||||
uint64_t get_static_memory_usage() const;
|
||||
uint64_t get_static_memory_peak_usage() const;
|
||||
Dictionary get_memory_info() const;
|
||||
|
||||
void delay_usec(int p_usec) const;
|
||||
void delay_msec(int p_msec) const;
|
||||
uint64_t get_ticks_msec() const;
|
||||
uint64_t get_ticks_usec() const;
|
||||
|
||||
bool is_userfs_persistent() const;
|
||||
|
||||
bool is_stdout_verbose() const;
|
||||
|
||||
int get_processor_count() const;
|
||||
String get_processor_name() const;
|
||||
|
||||
enum SystemDir {
|
||||
SYSTEM_DIR_DESKTOP,
|
||||
SYSTEM_DIR_DCIM,
|
||||
SYSTEM_DIR_DOCUMENTS,
|
||||
SYSTEM_DIR_DOWNLOADS,
|
||||
SYSTEM_DIR_MOVIES,
|
||||
SYSTEM_DIR_MUSIC,
|
||||
SYSTEM_DIR_PICTURES,
|
||||
SYSTEM_DIR_RINGTONES,
|
||||
};
|
||||
|
||||
String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const;
|
||||
|
||||
Error move_to_trash(const String &p_path) const;
|
||||
String get_user_data_dir() const;
|
||||
String get_config_dir() const;
|
||||
String get_data_dir() const;
|
||||
String get_cache_dir() const;
|
||||
String get_temp_dir() const;
|
||||
|
||||
Error set_thread_name(const String &p_name);
|
||||
::Thread::ID get_thread_caller_id() const;
|
||||
::Thread::ID get_main_thread_id() const;
|
||||
|
||||
bool has_feature(const String &p_feature) const;
|
||||
bool is_sandboxed() const;
|
||||
|
||||
bool request_permission(const String &p_name);
|
||||
bool request_permissions();
|
||||
Vector<String> get_granted_permissions() const;
|
||||
void revoke_granted_permissions();
|
||||
|
||||
static OS *get_singleton() { return singleton; }
|
||||
|
||||
OS() { singleton = this; }
|
||||
};
|
||||
|
||||
class Geometry2D : public Object {
|
||||
GDCLASS(Geometry2D, Object);
|
||||
|
||||
static Geometry2D *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Geometry2D *get_singleton();
|
||||
Variant segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b);
|
||||
Variant line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b);
|
||||
Vector<Vector2> get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2);
|
||||
Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
|
||||
Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b);
|
||||
bool point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const;
|
||||
|
||||
bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius);
|
||||
real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius);
|
||||
|
||||
bool is_polygon_clockwise(const Vector<Vector2> &p_polygon);
|
||||
bool is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon);
|
||||
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
|
||||
Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
|
||||
Vector<Point2> convex_hull(const Vector<Point2> &p_points);
|
||||
TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
|
||||
|
||||
enum PolyBooleanOperation {
|
||||
OPERATION_UNION,
|
||||
OPERATION_DIFFERENCE,
|
||||
OPERATION_INTERSECTION,
|
||||
OPERATION_XOR
|
||||
};
|
||||
// 2D polygon boolean operations.
|
||||
TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
|
||||
TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
|
||||
TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
|
||||
TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
|
||||
|
||||
// 2D polyline vs polygon operations.
|
||||
TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
|
||||
TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
|
||||
|
||||
// 2D offset polygons/polylines.
|
||||
enum PolyJoinType {
|
||||
JOIN_SQUARE,
|
||||
JOIN_ROUND,
|
||||
JOIN_MITER
|
||||
};
|
||||
enum PolyEndType {
|
||||
END_POLYGON,
|
||||
END_JOINED,
|
||||
END_BUTT,
|
||||
END_SQUARE,
|
||||
END_ROUND
|
||||
};
|
||||
TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
|
||||
TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
|
||||
|
||||
Dictionary make_atlas(const Vector<Size2> &p_rects);
|
||||
|
||||
TypedArray<Point2i> bresenham_line(const Point2i &p_from, const Point2i &p_to);
|
||||
|
||||
Geometry2D() { singleton = this; }
|
||||
};
|
||||
|
||||
class Geometry3D : public Object {
|
||||
GDCLASS(Geometry3D, Object);
|
||||
|
||||
static Geometry3D *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Geometry3D *get_singleton();
|
||||
Vector<Vector3> compute_convex_mesh_points(const TypedArray<Plane> &p_planes);
|
||||
TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
|
||||
TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
|
||||
TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
|
||||
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
|
||||
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
|
||||
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
|
||||
Vector3 get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
|
||||
Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
|
||||
Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
|
||||
|
||||
Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
|
||||
Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
|
||||
Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes);
|
||||
|
||||
Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
|
||||
Vector<int32_t> tetrahedralize_delaunay(const Vector<Vector3> &p_points);
|
||||
|
||||
Geometry3D() { singleton = this; }
|
||||
};
|
||||
|
||||
class Marshalls : public Object {
|
||||
GDCLASS(Marshalls, Object);
|
||||
|
||||
static Marshalls *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Marshalls *get_singleton();
|
||||
|
||||
String variant_to_base64(const Variant &p_var, bool p_full_objects = false);
|
||||
Variant base64_to_variant(const String &p_str, bool p_allow_objects = false);
|
||||
|
||||
String raw_to_base64(const Vector<uint8_t> &p_arr);
|
||||
Vector<uint8_t> base64_to_raw(const String &p_str);
|
||||
|
||||
String utf8_to_base64(const String &p_str);
|
||||
String base64_to_utf8(const String &p_str);
|
||||
|
||||
Marshalls() { singleton = this; }
|
||||
~Marshalls() { singleton = nullptr; }
|
||||
};
|
||||
|
||||
class Mutex : public RefCounted {
|
||||
GDCLASS(Mutex, RefCounted);
|
||||
::Mutex mutex;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
};
|
||||
|
||||
class Semaphore : public RefCounted {
|
||||
GDCLASS(Semaphore, RefCounted);
|
||||
::Semaphore semaphore;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _post_bind_compat_93605();
|
||||
static void _bind_compatibility_methods();
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
public:
|
||||
void wait();
|
||||
bool try_wait();
|
||||
void post(int p_count = 1);
|
||||
};
|
||||
|
||||
class Thread : public RefCounted {
|
||||
GDCLASS(Thread, RefCounted);
|
||||
|
||||
protected:
|
||||
Variant ret;
|
||||
SafeFlag running;
|
||||
Callable target_callable;
|
||||
::Thread thread;
|
||||
static void _bind_methods();
|
||||
static void _start_func(void *ud);
|
||||
|
||||
public:
|
||||
enum Priority {
|
||||
PRIORITY_LOW,
|
||||
PRIORITY_NORMAL,
|
||||
PRIORITY_HIGH,
|
||||
PRIORITY_MAX
|
||||
};
|
||||
|
||||
Error start(const Callable &p_callable, Priority p_priority = PRIORITY_NORMAL);
|
||||
String get_id() const;
|
||||
bool is_started() const;
|
||||
bool is_alive() const;
|
||||
Variant wait_to_finish();
|
||||
|
||||
static void set_thread_safety_checks_enabled(bool p_enabled);
|
||||
};
|
||||
|
||||
namespace special {
|
||||
|
||||
class ClassDB : public Object {
|
||||
GDCLASS(ClassDB, Object);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
enum APIType {
|
||||
API_CORE,
|
||||
API_EDITOR,
|
||||
API_EXTENSION,
|
||||
API_EDITOR_EXTENSION,
|
||||
API_NONE,
|
||||
};
|
||||
|
||||
PackedStringArray get_class_list() const;
|
||||
PackedStringArray get_inheriters_from_class(const StringName &p_class) const;
|
||||
StringName get_parent_class(const StringName &p_class) const;
|
||||
bool class_exists(const StringName &p_class) const;
|
||||
bool is_parent_class(const StringName &p_class, const StringName &p_inherits) const;
|
||||
bool can_instantiate(const StringName &p_class) const;
|
||||
Variant instantiate(const StringName &p_class) const;
|
||||
|
||||
APIType class_get_api_type(const StringName &p_class) const;
|
||||
bool class_has_signal(const StringName &p_class, const StringName &p_signal) const;
|
||||
Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const;
|
||||
TypedArray<Dictionary> class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
|
||||
TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
StringName class_get_property_getter(const StringName &p_class, const StringName &p_property);
|
||||
StringName class_get_property_setter(const StringName &p_class, const StringName &p_property);
|
||||
Variant class_get_property(Object *p_object, const StringName &p_property) const;
|
||||
Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
|
||||
|
||||
Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const;
|
||||
|
||||
bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
|
||||
|
||||
int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
|
||||
|
||||
TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
Variant class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error);
|
||||
|
||||
PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
|
||||
int64_t class_get_integer_constant(const StringName &p_class, const StringName &p_name) const;
|
||||
|
||||
bool class_has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
|
||||
PackedStringArray class_get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
|
||||
PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
|
||||
StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
|
||||
|
||||
bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
|
||||
|
||||
bool is_class_enabled(const StringName &p_class) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
ClassDB() {}
|
||||
~ClassDB() {}
|
||||
};
|
||||
|
||||
} // namespace special
|
||||
|
||||
class Engine : public Object {
|
||||
GDCLASS(Engine, Object);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static Engine *singleton;
|
||||
|
||||
public:
|
||||
static Engine *get_singleton() { return singleton; }
|
||||
void set_physics_ticks_per_second(int p_ips);
|
||||
int get_physics_ticks_per_second() const;
|
||||
|
||||
void set_max_physics_steps_per_frame(int p_max_physics_steps);
|
||||
int get_max_physics_steps_per_frame() const;
|
||||
|
||||
void set_physics_jitter_fix(double p_threshold);
|
||||
double get_physics_jitter_fix() const;
|
||||
double get_physics_interpolation_fraction() const;
|
||||
|
||||
void set_max_fps(int p_fps);
|
||||
int get_max_fps() const;
|
||||
|
||||
double get_frames_per_second() const;
|
||||
uint64_t get_physics_frames() const;
|
||||
uint64_t get_process_frames() const;
|
||||
|
||||
int get_frames_drawn();
|
||||
|
||||
void set_time_scale(double p_scale);
|
||||
double get_time_scale();
|
||||
|
||||
MainLoop *get_main_loop() const;
|
||||
|
||||
Dictionary get_version_info() const;
|
||||
Dictionary get_author_info() const;
|
||||
TypedArray<Dictionary> get_copyright_info() const;
|
||||
Dictionary get_donor_info() const;
|
||||
Dictionary get_license_info() const;
|
||||
String get_license_text() const;
|
||||
|
||||
String get_architecture_name() const;
|
||||
|
||||
bool is_in_physics_frame() const;
|
||||
|
||||
bool has_singleton(const StringName &p_name) const;
|
||||
Object *get_singleton_object(const StringName &p_name) const;
|
||||
void register_singleton(const StringName &p_name, Object *p_object);
|
||||
void unregister_singleton(const StringName &p_name);
|
||||
Vector<String> get_singleton_list() const;
|
||||
|
||||
Error register_script_language(ScriptLanguage *p_language);
|
||||
Error unregister_script_language(const ScriptLanguage *p_language);
|
||||
int get_script_language_count();
|
||||
ScriptLanguage *get_script_language(int p_index) const;
|
||||
|
||||
void set_editor_hint(bool p_enabled);
|
||||
bool is_editor_hint() const;
|
||||
|
||||
bool is_embedded_in_editor() const;
|
||||
|
||||
// `set_write_movie_path()` is not exposed to the scripting API as changing it at run-time has no effect.
|
||||
String get_write_movie_path() const;
|
||||
|
||||
void set_print_to_stdout(bool p_enabled);
|
||||
bool is_printing_to_stdout() const;
|
||||
|
||||
void set_print_error_messages(bool p_enabled);
|
||||
bool is_printing_error_messages() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
Engine() { singleton = this; }
|
||||
};
|
||||
|
||||
class EngineDebugger : public Object {
|
||||
GDCLASS(EngineDebugger, Object);
|
||||
|
||||
HashMap<StringName, Callable> captures;
|
||||
HashMap<StringName, Ref<EngineProfiler>> profilers;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static EngineDebugger *singleton;
|
||||
|
||||
public:
|
||||
static EngineDebugger *get_singleton() { return singleton; }
|
||||
|
||||
bool is_active();
|
||||
|
||||
void register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler);
|
||||
void unregister_profiler(const StringName &p_name);
|
||||
bool is_profiling(const StringName &p_name);
|
||||
bool has_profiler(const StringName &p_name);
|
||||
void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
|
||||
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
|
||||
|
||||
void register_message_capture(const StringName &p_name, const Callable &p_callable);
|
||||
void unregister_message_capture(const StringName &p_name);
|
||||
bool has_capture(const StringName &p_name);
|
||||
|
||||
void send_message(const String &p_msg, const Array &p_data);
|
||||
void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
|
||||
void script_debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
|
||||
|
||||
static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
|
||||
|
||||
void line_poll();
|
||||
|
||||
void set_lines_left(int p_lines);
|
||||
int get_lines_left() const;
|
||||
|
||||
void set_depth(int p_depth);
|
||||
int get_depth() const;
|
||||
|
||||
bool is_breakpoint(int p_line, const StringName &p_source) const;
|
||||
bool is_skipping_breakpoints() const;
|
||||
void insert_breakpoint(int p_line, const StringName &p_source);
|
||||
void remove_breakpoint(int p_line, const StringName &p_source);
|
||||
void clear_breakpoints();
|
||||
|
||||
EngineDebugger() { singleton = this; }
|
||||
~EngineDebugger();
|
||||
};
|
||||
|
||||
} // namespace core_bind
|
||||
|
||||
VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus);
|
||||
VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
|
||||
|
||||
VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
|
||||
|
||||
VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
|
||||
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
|
||||
VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);
|
||||
|
||||
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
|
||||
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
|
||||
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
|
||||
|
||||
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
|
||||
|
||||
VARIANT_ENUM_CAST(core_bind::special::ClassDB::APIType);
|
||||
|
||||
#endif // CORE_BIND_H
|
|
@ -1,315 +0,0 @@
|
|||
"""Functions used to generate source files during build time"""
|
||||
|
||||
import zlib
|
||||
|
||||
|
||||
def escape_string(s):
|
||||
def charcode_to_c_escapes(c):
|
||||
rev_result = []
|
||||
while c >= 256:
|
||||
c, low = (c // 256, c % 256)
|
||||
rev_result.append("\\%03o" % low)
|
||||
rev_result.append("\\%03o" % c)
|
||||
return "".join(reversed(rev_result))
|
||||
|
||||
result = ""
|
||||
if isinstance(s, str):
|
||||
s = s.encode("utf-8")
|
||||
for c in s:
|
||||
if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
|
||||
result += charcode_to_c_escapes(c)
|
||||
else:
|
||||
result += chr(c)
|
||||
return result
|
||||
|
||||
|
||||
def make_certs_header(target, source, env):
|
||||
src = str(source[0])
|
||||
dst = str(target[0])
|
||||
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
buf = f.read()
|
||||
decomp_size = len(buf)
|
||||
|
||||
# Use maximum zlib compression level to further reduce file size
|
||||
# (at the cost of initial build times).
|
||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
||||
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
|
||||
g.write("#define CERTS_COMPRESSED_GEN_H\n")
|
||||
|
||||
# System certs path. Editor will use them if defined. (for package maintainers)
|
||||
path = env["system_certs_path"]
|
||||
g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
|
||||
if env["builtin_certs"]:
|
||||
# Defined here and not in env so changing it does not trigger a full rebuild.
|
||||
g.write("#define BUILTIN_CERTS_ENABLED\n")
|
||||
g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
|
||||
g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
|
||||
g.write("static const unsigned char _certs_compressed[] = {\n")
|
||||
for i in range(len(buf)):
|
||||
g.write("\t" + str(buf[i]) + ",\n")
|
||||
g.write("};\n")
|
||||
g.write("#endif // CERTS_COMPRESSED_GEN_H")
|
||||
|
||||
|
||||
def make_authors_header(target, source, env):
|
||||
sections = [
|
||||
"Project Founders",
|
||||
"Lead Developer",
|
||||
"Project Manager",
|
||||
"Developers",
|
||||
]
|
||||
sections_id = [
|
||||
"AUTHORS_FOUNDERS",
|
||||
"AUTHORS_LEAD_DEVELOPERS",
|
||||
"AUTHORS_PROJECT_MANAGERS",
|
||||
"AUTHORS_DEVELOPERS",
|
||||
]
|
||||
|
||||
src = str(source[0])
|
||||
dst = str(target[0])
|
||||
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef AUTHORS_GEN_H\n")
|
||||
g.write("#define AUTHORS_GEN_H\n")
|
||||
|
||||
reading = False
|
||||
|
||||
def close_section():
|
||||
g.write("\t0\n")
|
||||
g.write("};\n")
|
||||
|
||||
for line in f:
|
||||
if reading:
|
||||
if line.startswith(" "):
|
||||
g.write('\t"' + escape_string(line.strip()) + '",\n')
|
||||
continue
|
||||
if line.startswith("## "):
|
||||
if reading:
|
||||
close_section()
|
||||
reading = False
|
||||
for section, section_id in zip(sections, sections_id):
|
||||
if line.strip().endswith(section):
|
||||
current_section = escape_string(section_id)
|
||||
reading = True
|
||||
g.write("const char *const " + current_section + "[] = {\n")
|
||||
break
|
||||
|
||||
if reading:
|
||||
close_section()
|
||||
|
||||
g.write("#endif // AUTHORS_GEN_H\n")
|
||||
|
||||
|
||||
def make_donors_header(target, source, env):
|
||||
sections = [
|
||||
"Patrons",
|
||||
"Platinum sponsors",
|
||||
"Gold sponsors",
|
||||
"Silver sponsors",
|
||||
"Diamond members",
|
||||
"Titanium members",
|
||||
"Platinum members",
|
||||
"Gold members",
|
||||
]
|
||||
sections_id = [
|
||||
"DONORS_PATRONS",
|
||||
"DONORS_SPONSORS_PLATINUM",
|
||||
"DONORS_SPONSORS_GOLD",
|
||||
"DONORS_SPONSORS_SILVER",
|
||||
"DONORS_MEMBERS_DIAMOND",
|
||||
"DONORS_MEMBERS_TITANIUM",
|
||||
"DONORS_MEMBERS_PLATINUM",
|
||||
"DONORS_MEMBERS_GOLD",
|
||||
]
|
||||
|
||||
src = str(source[0])
|
||||
dst = str(target[0])
|
||||
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef DONORS_GEN_H\n")
|
||||
g.write("#define DONORS_GEN_H\n")
|
||||
|
||||
reading = False
|
||||
|
||||
def close_section():
|
||||
g.write("\t0\n")
|
||||
g.write("};\n")
|
||||
|
||||
for line in f:
|
||||
if reading >= 0:
|
||||
if line.startswith(" "):
|
||||
g.write('\t"' + escape_string(line.strip()) + '",\n')
|
||||
continue
|
||||
if line.startswith("## "):
|
||||
if reading:
|
||||
close_section()
|
||||
reading = False
|
||||
for section, section_id in zip(sections, sections_id):
|
||||
if line.strip().endswith(section):
|
||||
current_section = escape_string(section_id)
|
||||
reading = True
|
||||
g.write("const char *const " + current_section + "[] = {\n")
|
||||
break
|
||||
|
||||
if reading:
|
||||
close_section()
|
||||
|
||||
g.write("#endif // DONORS_GEN_H\n")
|
||||
|
||||
|
||||
def make_license_header(target, source, env):
|
||||
src_copyright = str(source[0])
|
||||
src_license = str(source[1])
|
||||
dst = str(target[0])
|
||||
|
||||
class LicenseReader:
|
||||
def __init__(self, license_file):
|
||||
self._license_file = license_file
|
||||
self.line_num = 0
|
||||
self.current = self.next_line()
|
||||
|
||||
def next_line(self):
|
||||
line = self._license_file.readline()
|
||||
self.line_num += 1
|
||||
while line.startswith("#"):
|
||||
line = self._license_file.readline()
|
||||
self.line_num += 1
|
||||
self.current = line
|
||||
return line
|
||||
|
||||
def next_tag(self):
|
||||
if ":" not in self.current:
|
||||
return ("", [])
|
||||
tag, line = self.current.split(":", 1)
|
||||
lines = [line.strip()]
|
||||
while self.next_line() and self.current.startswith(" "):
|
||||
lines.append(self.current.strip())
|
||||
return (tag, lines)
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
projects: dict = OrderedDict()
|
||||
license_list = []
|
||||
|
||||
with open(src_copyright, "r", encoding="utf-8") as copyright_file:
|
||||
reader = LicenseReader(copyright_file)
|
||||
part = {}
|
||||
while reader.current:
|
||||
tag, content = reader.next_tag()
|
||||
if tag in ("Files", "Copyright", "License"):
|
||||
part[tag] = content[:]
|
||||
elif tag == "Comment" and part:
|
||||
# attach non-empty part to named project
|
||||
projects[content[0]] = projects.get(content[0], []) + [part]
|
||||
|
||||
if not tag or not reader.current:
|
||||
# end of a paragraph start a new part
|
||||
if "License" in part and "Files" not in part:
|
||||
# no Files tag in this one, so assume standalone license
|
||||
license_list.append(part["License"])
|
||||
part = {}
|
||||
reader.next_line()
|
||||
|
||||
data_list: list = []
|
||||
for project in iter(projects.values()):
|
||||
for part in project:
|
||||
part["file_index"] = len(data_list)
|
||||
data_list += part["Files"]
|
||||
part["copyright_index"] = len(data_list)
|
||||
data_list += part["Copyright"]
|
||||
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
f.write("#ifndef LICENSE_GEN_H\n")
|
||||
f.write("#define LICENSE_GEN_H\n")
|
||||
f.write("const char *const GODOT_LICENSE_TEXT =")
|
||||
|
||||
with open(src_license, "r", encoding="utf-8") as license_file:
|
||||
for line in license_file:
|
||||
escaped_string = escape_string(line.strip())
|
||||
f.write('\n\t\t"' + escaped_string + '\\n"')
|
||||
f.write(";\n\n")
|
||||
|
||||
f.write(
|
||||
"struct ComponentCopyrightPart {\n"
|
||||
"\tconst char *license;\n"
|
||||
"\tconst char *const *files;\n"
|
||||
"\tconst char *const *copyright_statements;\n"
|
||||
"\tint file_count;\n"
|
||||
"\tint copyright_count;\n"
|
||||
"};\n\n"
|
||||
)
|
||||
|
||||
f.write(
|
||||
"struct ComponentCopyright {\n"
|
||||
"\tconst char *name;\n"
|
||||
"\tconst ComponentCopyrightPart *parts;\n"
|
||||
"\tint part_count;\n"
|
||||
"};\n\n"
|
||||
)
|
||||
|
||||
f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
|
||||
for line in data_list:
|
||||
f.write('\t"' + escape_string(line) + '",\n')
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
|
||||
part_index = 0
|
||||
part_indexes = {}
|
||||
for project_name, project in iter(projects.items()):
|
||||
part_indexes[project_name] = part_index
|
||||
for part in project:
|
||||
f.write(
|
||||
'\t{ "'
|
||||
+ escape_string(part["License"][0])
|
||||
+ '", '
|
||||
+ "©RIGHT_INFO_DATA["
|
||||
+ str(part["file_index"])
|
||||
+ "], "
|
||||
+ "©RIGHT_INFO_DATA["
|
||||
+ str(part["copyright_index"])
|
||||
+ "], "
|
||||
+ str(len(part["Files"]))
|
||||
+ ", "
|
||||
+ str(len(part["Copyright"]))
|
||||
+ " },\n"
|
||||
)
|
||||
part_index += 1
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
|
||||
|
||||
f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n")
|
||||
for project_name, project in iter(projects.items()):
|
||||
f.write(
|
||||
'\t{ "'
|
||||
+ escape_string(project_name)
|
||||
+ '", '
|
||||
+ "©RIGHT_PROJECT_PARTS["
|
||||
+ str(part_indexes[project_name])
|
||||
+ "], "
|
||||
+ str(len(project))
|
||||
+ " },\n"
|
||||
)
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
|
||||
|
||||
f.write("const char *const LICENSE_NAMES[] = {\n")
|
||||
for license in license_list:
|
||||
f.write('\t"' + escape_string(license[0]) + '",\n')
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("const char *const LICENSE_BODIES[] = {\n\n")
|
||||
for license in license_list:
|
||||
for line in license[1:]:
|
||||
if line == ".":
|
||||
f.write('\t"\\n"\n')
|
||||
else:
|
||||
f.write('\t"' + escape_string(line) + '\\n"\n')
|
||||
f.write('\t"",\n\n')
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("#endif // LICENSE_GEN_H\n")
|
|
@ -1,862 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_constants.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "core_constants.h"
|
||||
|
||||
#include "core/input/input_event.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
struct _CoreConstant {
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
bool ignore_value_in_docs = false;
|
||||
bool is_bitfield = false;
|
||||
#endif
|
||||
StringName enum_name;
|
||||
const char *name = nullptr;
|
||||
int64_t value = 0;
|
||||
|
||||
_CoreConstant() {}
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value, bool p_ignore_value_in_docs = false, bool p_is_bitfield = false) :
|
||||
ignore_value_in_docs(p_ignore_value_in_docs),
|
||||
is_bitfield(p_is_bitfield),
|
||||
enum_name(p_enum_name),
|
||||
name(p_name),
|
||||
value(p_value) {
|
||||
}
|
||||
#else
|
||||
_CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value) :
|
||||
enum_name(p_enum_name),
|
||||
name(p_name),
|
||||
value(p_value) {
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static Vector<_CoreConstant> _global_constants;
|
||||
static HashMap<StringName, int> _global_constants_map;
|
||||
static HashMap<StringName, Vector<_CoreConstant>> _global_enums;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
||||
#define BIND_CORE_CONSTANT(m_constant) \
|
||||
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1;
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, false, true)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
// This just binds enum classes as if they were regular enum constants.
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, false, true)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member, false, true)); \
|
||||
_global_constants_map[#m_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
|
||||
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
|
||||
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant, true)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1;
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant, true)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant, true)); \
|
||||
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BIND_CORE_CONSTANT(m_constant) \
|
||||
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1;
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_FLAG(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
// This just binds enum classes as if they were regular enum constants.
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_CLASS_FLAG(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_name); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(m_enum, m_name, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_bitfield_name(m_enum::m_member, #m_name); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_name, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); \
|
||||
_global_constants_map[#m_prefix "_" #m_member] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
|
||||
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
|
||||
_global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1;
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, #m_constant, m_constant)); \
|
||||
_global_constants_map[#m_constant] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
|
||||
{ \
|
||||
StringName enum_name = __constant_get_enum_name(m_constant, #m_constant); \
|
||||
_global_constants.push_back(_CoreConstant(enum_name, m_custom_name, m_constant)); \
|
||||
_global_constants_map[m_custom_name] = _global_constants.size() - 1; \
|
||||
_global_enums[enum_name].push_back((_global_constants.ptr())[_global_constants.size() - 1]); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void register_global_constants() {
|
||||
BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
|
||||
BIND_CORE_ENUM_CONSTANT(SIDE_TOP);
|
||||
BIND_CORE_ENUM_CONSTANT(SIDE_RIGHT);
|
||||
BIND_CORE_ENUM_CONSTANT(SIDE_BOTTOM);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_LEFT);
|
||||
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_RIGHT);
|
||||
BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
|
||||
BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(VERTICAL);
|
||||
BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(CLOCKWISE);
|
||||
BIND_CORE_ENUM_CONSTANT(COUNTERCLOCKWISE);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_LEFT);
|
||||
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_CENTER);
|
||||
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
BIND_CORE_ENUM_CONSTANT(HORIZONTAL_ALIGNMENT_FILL);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_TOP);
|
||||
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_CENTER);
|
||||
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_BOTTOM);
|
||||
BIND_CORE_ENUM_CONSTANT(VERTICAL_ALIGNMENT_FILL);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP_TO);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER_TO);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BASELINE_TO);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM_TO);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_TOP);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_CENTER);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BASELINE);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_BOTTOM);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
|
||||
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XYZ);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XZY);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YXZ);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YZX);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZXY);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZYX);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TAB);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKTAB);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSPACE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ENTER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ENTER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, INSERT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_DELETE, KEY_DELETE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAUSE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PRINT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SYSREQ);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CLEAR);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOME);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, END);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, RIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEUP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PAGEDOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SHIFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CTRL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, META);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ALT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CAPSLOCK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMLOCK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SCROLLLOCK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F2);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F3);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F4);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F5);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F6);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F7);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F8);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F9);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F10);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F11);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F12);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F13);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F14);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F15);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F16);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F17);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F18);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F19);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F20);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F21);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F22);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F23);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F24);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F25);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F26);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F27);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F28);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F29);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F30);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F31);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F32);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F33);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F34);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F35);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_MULTIPLY);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_DIVIDE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_SUBTRACT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_PERIOD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_ADD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_0);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_2);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_3);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_4);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_5);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_6);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_7);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_8);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_9);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MENU);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HELP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FORWARD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STOP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, REFRESH);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEDOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEMUTE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEUP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPLAY);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIASTOP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPREVIOUS);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIANEXT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIARECORD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HOMEPAGE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FAVORITES);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEARCH);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STANDBY);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OPENURL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMAIL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHMEDIA);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH0);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH2);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH3);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH4);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH5);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH6);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH7);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH8);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCH9);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHA);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHB);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHC);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHF);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNKNOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPACE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EXCLAM);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTEDBL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NUMBERSIGN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DOLLAR);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERCENT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AMPERSAND);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, APOSTROPHE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENLEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARENRIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASTERISK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PLUS);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COMMA);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MINUS);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERIOD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SLASH);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_0, KEY_0);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_1, KEY_1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_2, KEY_2);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_3, KEY_3);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_4, KEY_4);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_5, KEY_5);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_6, KEY_6);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_7, KEY_7);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_8, KEY_8);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_9, KEY_9);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COLON);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SEMICOLON);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LESS);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EQUAL);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GREATER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUESTION);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, A);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, B);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, C);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, D);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, E);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, G);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, H);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, I);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, J);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, K);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, L);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, M);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, N);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, O);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, P);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Q);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, R);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, S);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, T);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, U);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, V);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, W);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, X);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Y);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, Z);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETLEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACKSLASH);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACKETRIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIICIRCUM);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNDERSCORE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUOTELEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACELEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BAR);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACERIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIITILDE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YEN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SECTION);
|
||||
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CMD_OR_CTRL);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, SHIFT);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, ALT);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, META);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, CTRL);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, KPAD);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, UNSPECIFIED);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, RIGHT);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, MIDDLE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_UP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_DOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, WHEEL_RIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON1, MB_XBUTTON1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(MouseButton, MOUSE_BUTTON_XBUTTON2, MB_XBUTTON2);
|
||||
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, LEFT);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, RIGHT);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MIDDLE);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON1);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(MouseButtonMask, MOUSE_BUTTON_MASK, MB_XBUTTON2);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, INVALID);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, A);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, B);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, X);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, Y);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, BACK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, GUIDE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, START);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_STICK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_STICK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, LEFT_SHOULDER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, RIGHT_SHOULDER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_UP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_DOWN);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, DPAD_RIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MISC1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE1);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE2);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE3);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, PADDLE4);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, TOUCHPAD);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, SDL_MAX);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyButton, JOY_BUTTON, MAX);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, INVALID);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_X);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, LEFT_Y);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_X);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, RIGHT_Y);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, TRIGGER_RIGHT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, SDL_MAX);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, MAX);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NONE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_OFF);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_ON);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, AFTERTOUCH);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTROL_CHANGE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PROGRAM_CHANGE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CHANNEL_PRESSURE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, PITCH_BEND);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_EXCLUSIVE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, QUARTER_FRAME);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_POSITION_POINTER);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SONG_SELECT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TUNE_REQUEST);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, TIMING_CLOCK);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, START);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, CONTINUE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, STOP);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, ACTIVE_SENSING);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, SYSTEM_RESET);
|
||||
|
||||
// error list
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(OK); // (0)
|
||||
BIND_CORE_ENUM_CONSTANT(FAILED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_UNAVAILABLE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_UNCONFIGURED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_UNAUTHORIZED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_PARAMETER_RANGE_ERROR); // (5)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_OUT_OF_MEMORY);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_NOT_FOUND);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_DRIVE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_PATH);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_NO_PERMISSION); // (10)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_ALREADY_IN_USE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_OPEN);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_WRITE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_READ);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_UNRECOGNIZED); // (15)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_CORRUPT);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_MISSING_DEPENDENCIES);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_FILE_EOF);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_OPEN);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_CREATE); // (20)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_QUERY_FAILED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_IN_USE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_LOCKED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_TIMEOUT);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_CONNECT); // (25)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_RESOLVE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CONNECTION_ERROR);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_ACQUIRE_RESOURCE);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CANT_FORK);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DATA); // (30)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_PARAMETER);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_EXISTS);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_DOES_NOT_EXIST);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_READ);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_WRITE); // (35)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_COMPILATION_FAILED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_METHOD_NOT_FOUND);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_LINK_FAILED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_SCRIPT_FAILED);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_CYCLIC_LINK); // (40)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DECLARATION);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_DUPLICATE_SYMBOL);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_PARSE_ERROR);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_BUSY);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_SKIP); // (45)
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_HELP);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_BUG);
|
||||
BIND_CORE_ENUM_CONSTANT(ERR_PRINTER_ON_FIRE);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LINK);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_NAVIGATION);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_NAVIGATION);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_AVOIDANCE);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_FILE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_SAVE_FILE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DICTIONARY_TYPE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ONESHOT);
|
||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
|
||||
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORAGE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_INTERNAL);
|
||||
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKABLE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CHECKED);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_GROUP);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CATEGORY);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SUBGROUP);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_BITFIELD);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_INSTANCE_STATE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESTART_IF_CHANGED);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_STORE_IF_NULL);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_CLASS_IS_ENUM);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ARRAY);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_ALWAYS_DUPLICATE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NEVER_DUPLICATE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_HIGH_END_GFX);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_KEYING_INCREMENTS);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFERRED_SET_RESOURCE);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_BASIC_SETTING);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_READ_ONLY);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SECRET);
|
||||
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFAULT);
|
||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_EDITOR);
|
||||
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_NORMAL);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_EDITOR);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_CONST);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VARARG);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_STATIC);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_OBJECT_CORE);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAG_VIRTUAL_REQUIRED);
|
||||
BIND_CORE_BITFIELD_FLAG(METHOD_FLAGS_DEFAULT);
|
||||
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT", Variant::FLOAT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING", Variant::STRING);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2", Variant::VECTOR2);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2I", Variant::VECTOR2I);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2", Variant::RECT2);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2I", Variant::RECT2I);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3", Variant::VECTOR3);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4", Variant::VECTOR4);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR4I", Variant::VECTOR4I);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PROJECTION", Variant::PROJECTION);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::RID);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_BYTE_ARRAY", Variant::PACKED_BYTE_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT32_ARRAY", Variant::PACKED_INT32_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_INT64_ARRAY", Variant::PACKED_INT64_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT32_ARRAY", Variant::PACKED_FLOAT32_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_FLOAT64_ARRAY", Variant::PACKED_FLOAT64_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_STRING_ARRAY", Variant::PACKED_STRING_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR2_ARRAY", Variant::PACKED_VECTOR2_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR3_ARRAY", Variant::PACKED_VECTOR3_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_COLOR_ARRAY", Variant::PACKED_COLOR_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PACKED_VECTOR4_ARRAY", Variant::PACKED_VECTOR4_ARRAY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
|
||||
|
||||
//comparison
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
|
||||
//mathematic
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POWER", Variant::OP_POWER);
|
||||
//bitwise
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
|
||||
//logic
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
|
||||
//containment
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
|
||||
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
|
||||
}
|
||||
|
||||
void unregister_global_constants() {
|
||||
_global_constants.clear();
|
||||
_global_constants_map.clear();
|
||||
_global_enums.clear();
|
||||
}
|
||||
|
||||
int CoreConstants::get_global_constant_count() {
|
||||
return _global_constants.size();
|
||||
}
|
||||
|
||||
StringName CoreConstants::get_global_constant_enum(int p_idx) {
|
||||
return _global_constants[p_idx].enum_name;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
bool CoreConstants::is_global_constant_bitfield(int p_idx) {
|
||||
return _global_constants[p_idx].is_bitfield;
|
||||
}
|
||||
|
||||
bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
|
||||
return _global_constants[p_idx].ignore_value_in_docs;
|
||||
}
|
||||
#else
|
||||
bool CoreConstants::is_global_constant_bitfield(int p_idx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *CoreConstants::get_global_constant_name(int p_idx) {
|
||||
return _global_constants[p_idx].name;
|
||||
}
|
||||
|
||||
int64_t CoreConstants::get_global_constant_value(int p_idx) {
|
||||
return _global_constants[p_idx].value;
|
||||
}
|
||||
|
||||
bool CoreConstants::is_global_constant(const StringName &p_name) {
|
||||
return _global_constants_map.has(p_name);
|
||||
}
|
||||
|
||||
int CoreConstants::get_global_constant_index(const StringName &p_name) {
|
||||
ERR_FAIL_COND_V_MSG(!_global_constants_map.has(p_name), -1, "Trying to get index of non-existing constant.");
|
||||
return _global_constants_map[p_name];
|
||||
}
|
||||
|
||||
bool CoreConstants::is_global_enum(const StringName &p_enum) {
|
||||
return _global_enums.has(p_enum);
|
||||
}
|
||||
|
||||
void CoreConstants::get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values) {
|
||||
ERR_FAIL_NULL_MSG(p_values, "Trying to get enum values with null map.");
|
||||
ERR_FAIL_COND_MSG(!_global_enums.has(p_enum), "Trying to get values of non-existing enum.");
|
||||
for (const _CoreConstant &constant : _global_enums[p_enum]) {
|
||||
(*p_values)[constant.name] = constant.value;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_constants.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CORE_CONSTANTS_H
|
||||
#define CORE_CONSTANTS_H
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
|
||||
class CoreConstants {
|
||||
public:
|
||||
static int get_global_constant_count();
|
||||
static StringName get_global_constant_enum(int p_idx);
|
||||
static bool is_global_constant_bitfield(int p_idx);
|
||||
static bool get_ignore_value_in_docs(int p_idx);
|
||||
static const char *get_global_constant_name(int p_idx);
|
||||
static int64_t get_global_constant_value(int p_idx);
|
||||
static bool is_global_constant(const StringName &p_name);
|
||||
static int get_global_constant_index(const StringName &p_name);
|
||||
static bool is_global_enum(const StringName &p_enum);
|
||||
static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values);
|
||||
};
|
||||
|
||||
#endif // CORE_CONSTANTS_H
|
|
@ -1,35 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_globals.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "core_globals.h"
|
||||
|
||||
bool CoreGlobals::leak_reporting_enabled = true;
|
||||
bool CoreGlobals::print_line_enabled = true;
|
||||
bool CoreGlobals::print_error_enabled = true;
|
|
@ -1,44 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_globals.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CORE_GLOBALS_H
|
||||
#define CORE_GLOBALS_H
|
||||
|
||||
// Home for state needed from global functions
|
||||
// that cannot be stored in Engine or OS due to e.g. circular includes
|
||||
|
||||
class CoreGlobals {
|
||||
public:
|
||||
static bool leak_reporting_enabled;
|
||||
static bool print_line_enabled;
|
||||
static bool print_error_enabled;
|
||||
};
|
||||
|
||||
#endif // CORE_GLOBALS_H
|
|
@ -1,91 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* core_string_names.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CORE_STRING_NAMES_H
|
||||
#define CORE_STRING_NAMES_H
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
|
||||
class CoreStringNames {
|
||||
inline static CoreStringNames *singleton = nullptr;
|
||||
|
||||
public:
|
||||
static void create() { singleton = memnew(CoreStringNames); }
|
||||
static void free() {
|
||||
memdelete(singleton);
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; }
|
||||
|
||||
const StringName free_ = StaticCString::create("free"); // free would conflict with C++ keyword.
|
||||
const StringName changed = StaticCString::create("changed");
|
||||
const StringName script = StaticCString::create("script");
|
||||
const StringName script_changed = StaticCString::create("script_changed");
|
||||
const StringName _iter_init = StaticCString::create("_iter_init");
|
||||
const StringName _iter_next = StaticCString::create("_iter_next");
|
||||
const StringName _iter_get = StaticCString::create("_iter_get");
|
||||
const StringName get_rid = StaticCString::create("get_rid");
|
||||
const StringName _to_string = StaticCString::create("_to_string");
|
||||
const StringName _custom_features = StaticCString::create("_custom_features");
|
||||
|
||||
const StringName x = StaticCString::create("x");
|
||||
const StringName y = StaticCString::create("y");
|
||||
const StringName z = StaticCString::create("z");
|
||||
const StringName w = StaticCString::create("w");
|
||||
const StringName r = StaticCString::create("r");
|
||||
const StringName g = StaticCString::create("g");
|
||||
const StringName b = StaticCString::create("b");
|
||||
const StringName a = StaticCString::create("a");
|
||||
const StringName position = StaticCString::create("position");
|
||||
const StringName size = StaticCString::create("size");
|
||||
const StringName end = StaticCString::create("end");
|
||||
const StringName basis = StaticCString::create("basis");
|
||||
const StringName origin = StaticCString::create("origin");
|
||||
const StringName normal = StaticCString::create("normal");
|
||||
const StringName d = StaticCString::create("d");
|
||||
const StringName h = StaticCString::create("h");
|
||||
const StringName s = StaticCString::create("s");
|
||||
const StringName v = StaticCString::create("v");
|
||||
const StringName r8 = StaticCString::create("r8");
|
||||
const StringName g8 = StaticCString::create("g8");
|
||||
const StringName b8 = StaticCString::create("b8");
|
||||
const StringName a8 = StaticCString::create("a8");
|
||||
|
||||
const StringName call = StaticCString::create("call");
|
||||
const StringName call_deferred = StaticCString::create("call_deferred");
|
||||
const StringName bind = StaticCString::create("bind");
|
||||
const StringName notification = StaticCString::create("notification");
|
||||
const StringName property_list_changed = StaticCString::create("property_list_changed");
|
||||
};
|
||||
|
||||
#define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name
|
||||
|
||||
#endif // CORE_STRING_NAMES_H
|
|
@ -1,65 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_crypto = env.Clone()
|
||||
|
||||
is_builtin = env["builtin_mbedtls"]
|
||||
has_module = env["module_mbedtls_enabled"]
|
||||
thirdparty_obj = []
|
||||
|
||||
if is_builtin or not has_module:
|
||||
# Use our headers for builtin or if the module is not going to be compiled.
|
||||
# We decided not to depend on system mbedtls just for these few files that can
|
||||
# be easily extracted.
|
||||
env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
|
||||
|
||||
# MbedTLS core functions (for CryptoCore).
|
||||
# If the mbedtls module is compiled we don't need to add the .c files with our
|
||||
# custom config since they will be built by the module itself.
|
||||
# Only if the module is not enabled, we must compile here the required sources
|
||||
# to make a "light" build with only the necessary mbedtls files.
|
||||
if not has_module:
|
||||
# Minimal mbedTLS config file
|
||||
config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
|
||||
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
|
||||
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
|
||||
# Build minimal mbedTLS library (MD5/SHA/Base64/AES).
|
||||
env_thirdparty = env_crypto.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
|
||||
thirdparty_mbedtls_sources = [
|
||||
"aes.c",
|
||||
"base64.c",
|
||||
"constant_time.c",
|
||||
"ctr_drbg.c",
|
||||
"entropy.c",
|
||||
"md.c",
|
||||
"md5.c",
|
||||
"sha1.c",
|
||||
"sha256.c",
|
||||
"godot_core_mbedtls_platform.c",
|
||||
]
|
||||
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
|
||||
# Needed to force rebuilding the library when the configuration file is updated.
|
||||
env_thirdparty.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_core_mbedtls_config.h")
|
||||
env.core_sources += thirdparty_obj
|
||||
elif is_builtin:
|
||||
# Module mbedTLS config file
|
||||
config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
|
||||
config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
|
||||
env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
|
||||
# Needed to force rebuilding the core files when the configuration file is updated.
|
||||
thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
|
||||
|
||||
# Godot source files
|
||||
|
||||
core_obj = []
|
||||
|
||||
env_crypto.add_source_files(core_obj, "*.cpp")
|
||||
env.core_sources += core_obj
|
||||
|
||||
# Needed to force rebuilding the core files when the thirdparty library is updated.
|
||||
env.Depends(core_obj, thirdparty_obj)
|
|
@ -1,115 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* aes_context.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "core/crypto/aes_context.h"
|
||||
|
||||
Error AESContext::start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv) {
|
||||
ERR_FAIL_COND_V_MSG(mode != MODE_MAX, ERR_ALREADY_IN_USE, "AESContext already started. Call 'finish' before starting a new one.");
|
||||
ERR_FAIL_COND_V_MSG(p_mode < 0 || p_mode >= MODE_MAX, ERR_INVALID_PARAMETER, "Invalid mode requested.");
|
||||
// Key check.
|
||||
int key_bits = p_key.size() << 3;
|
||||
ERR_FAIL_COND_V_MSG(key_bits != 128 && key_bits != 256, ERR_INVALID_PARAMETER, "AES key must be either 16 or 32 bytes");
|
||||
// Initialization vector.
|
||||
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_CBC_DECRYPT) {
|
||||
ERR_FAIL_COND_V_MSG(p_iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes.");
|
||||
iv.resize(0);
|
||||
iv.append_array(p_iv);
|
||||
}
|
||||
// Encryption/decryption key.
|
||||
if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_ECB_ENCRYPT) {
|
||||
ctx.set_encode_key(p_key.ptr(), key_bits);
|
||||
} else {
|
||||
ctx.set_decode_key(p_key.ptr(), key_bits);
|
||||
}
|
||||
mode = p_mode;
|
||||
return OK;
|
||||
}
|
||||
|
||||
PackedByteArray AESContext::update(const PackedByteArray &p_src) {
|
||||
ERR_FAIL_COND_V_MSG(mode < 0 || mode >= MODE_MAX, PackedByteArray(), "AESContext not started. Call 'start' before calling 'update'.");
|
||||
int len = p_src.size();
|
||||
ERR_FAIL_COND_V_MSG(len % 16, PackedByteArray(), "The number of bytes to be encrypted must be multiple of 16. Add padding if needed");
|
||||
PackedByteArray out;
|
||||
out.resize(len);
|
||||
const uint8_t *src_ptr = p_src.ptr();
|
||||
uint8_t *out_ptr = out.ptrw();
|
||||
switch (mode) {
|
||||
case MODE_ECB_ENCRYPT: {
|
||||
for (int i = 0; i < len; i += 16) {
|
||||
Error err = ctx.encrypt_ecb(src_ptr + i, out_ptr + i);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
}
|
||||
} break;
|
||||
case MODE_ECB_DECRYPT: {
|
||||
for (int i = 0; i < len; i += 16) {
|
||||
Error err = ctx.decrypt_ecb(src_ptr + i, out_ptr + i);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
}
|
||||
} break;
|
||||
case MODE_CBC_ENCRYPT: {
|
||||
Error err = ctx.encrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
} break;
|
||||
case MODE_CBC_DECRYPT: {
|
||||
Error err = ctx.decrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw());
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
} break;
|
||||
default:
|
||||
ERR_FAIL_V_MSG(PackedByteArray(), "Bug!");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
PackedByteArray AESContext::get_iv_state() {
|
||||
ERR_FAIL_COND_V_MSG(mode != MODE_CBC_ENCRYPT && mode != MODE_CBC_DECRYPT, PackedByteArray(), "Calling 'get_iv_state' only makes sense when the context is started in CBC mode.");
|
||||
PackedByteArray out;
|
||||
out.append_array(iv);
|
||||
return out;
|
||||
}
|
||||
|
||||
void AESContext::finish() {
|
||||
mode = MODE_MAX;
|
||||
iv.resize(0);
|
||||
}
|
||||
|
||||
void AESContext::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("start", "mode", "key", "iv"), &AESContext::start, DEFVAL(PackedByteArray()));
|
||||
ClassDB::bind_method(D_METHOD("update", "src"), &AESContext::update);
|
||||
ClassDB::bind_method(D_METHOD("get_iv_state"), &AESContext::get_iv_state);
|
||||
ClassDB::bind_method(D_METHOD("finish"), &AESContext::finish);
|
||||
BIND_ENUM_CONSTANT(MODE_ECB_ENCRYPT);
|
||||
BIND_ENUM_CONSTANT(MODE_ECB_DECRYPT);
|
||||
BIND_ENUM_CONSTANT(MODE_CBC_ENCRYPT);
|
||||
BIND_ENUM_CONSTANT(MODE_CBC_DECRYPT);
|
||||
BIND_ENUM_CONSTANT(MODE_MAX);
|
||||
}
|
||||
|
||||
AESContext::AESContext() {
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* aes_context.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef AES_CONTEXT_H
|
||||
#define AES_CONTEXT_H
|
||||
|
||||
#include "core/crypto/crypto_core.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class AESContext : public RefCounted {
|
||||
GDCLASS(AESContext, RefCounted);
|
||||
|
||||
public:
|
||||
enum Mode : int32_t {
|
||||
MODE_ECB_ENCRYPT,
|
||||
MODE_ECB_DECRYPT,
|
||||
MODE_CBC_ENCRYPT,
|
||||
MODE_CBC_DECRYPT,
|
||||
MODE_MAX
|
||||
};
|
||||
|
||||
private:
|
||||
Mode mode = MODE_MAX;
|
||||
CryptoCore::AESContext ctx;
|
||||
PackedByteArray iv;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
Error start(Mode p_mode, const PackedByteArray &p_key, const PackedByteArray &p_iv = PackedByteArray());
|
||||
PackedByteArray update(const PackedByteArray &p_src);
|
||||
PackedByteArray get_iv_state();
|
||||
void finish();
|
||||
|
||||
AESContext();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(AESContext::Mode);
|
||||
|
||||
#endif // AES_CONTEXT_H
|
|
@ -1,259 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
/// Resources
|
||||
|
||||
CryptoKey *(*CryptoKey::_create)(bool p_notify_postinitialize) = nullptr;
|
||||
CryptoKey *CryptoKey::create(bool p_notify_postinitialize) {
|
||||
if (_create) {
|
||||
return _create(p_notify_postinitialize);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CryptoKey::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("save", "path", "public_only"), &CryptoKey::save, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("load", "path", "public_only"), &CryptoKey::load, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("is_public_only"), &CryptoKey::is_public_only);
|
||||
ClassDB::bind_method(D_METHOD("save_to_string", "public_only"), &CryptoKey::save_to_string, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false));
|
||||
}
|
||||
|
||||
X509Certificate *(*X509Certificate::_create)(bool p_notify_postinitialize) = nullptr;
|
||||
X509Certificate *X509Certificate::create(bool p_notify_postinitialize) {
|
||||
if (_create) {
|
||||
return _create(p_notify_postinitialize);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void X509Certificate::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("save", "path"), &X509Certificate::save);
|
||||
ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load);
|
||||
ClassDB::bind_method(D_METHOD("save_to_string"), &X509Certificate::save_to_string);
|
||||
ClassDB::bind_method(D_METHOD("load_from_string", "string"), &X509Certificate::load_from_string);
|
||||
}
|
||||
|
||||
/// TLSOptions
|
||||
|
||||
Ref<TLSOptions> TLSOptions::client(Ref<X509Certificate> p_trusted_chain, const String &p_common_name_override) {
|
||||
Ref<TLSOptions> opts;
|
||||
opts.instantiate();
|
||||
opts->mode = MODE_CLIENT;
|
||||
opts->trusted_ca_chain = p_trusted_chain;
|
||||
opts->common_name = p_common_name_override;
|
||||
return opts;
|
||||
}
|
||||
|
||||
Ref<TLSOptions> TLSOptions::client_unsafe(Ref<X509Certificate> p_trusted_chain) {
|
||||
Ref<TLSOptions> opts;
|
||||
opts.instantiate();
|
||||
opts->mode = MODE_CLIENT_UNSAFE;
|
||||
opts->trusted_ca_chain = p_trusted_chain;
|
||||
return opts;
|
||||
}
|
||||
|
||||
Ref<TLSOptions> TLSOptions::server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate) {
|
||||
Ref<TLSOptions> opts;
|
||||
opts.instantiate();
|
||||
opts->mode = MODE_SERVER;
|
||||
opts->own_certificate = p_own_certificate;
|
||||
opts->private_key = p_own_key;
|
||||
return opts;
|
||||
}
|
||||
|
||||
void TLSOptions::_bind_methods() {
|
||||
ClassDB::bind_static_method("TLSOptions", D_METHOD("client", "trusted_chain", "common_name_override"), &TLSOptions::client, DEFVAL(Ref<X509Certificate>()), DEFVAL(String()));
|
||||
ClassDB::bind_static_method("TLSOptions", D_METHOD("client_unsafe", "trusted_chain"), &TLSOptions::client_unsafe, DEFVAL(Ref<X509Certificate>()));
|
||||
ClassDB::bind_static_method("TLSOptions", D_METHOD("server", "key", "certificate"), &TLSOptions::server);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_server"), &TLSOptions::is_server);
|
||||
ClassDB::bind_method(D_METHOD("is_unsafe_client"), &TLSOptions::is_unsafe_client);
|
||||
ClassDB::bind_method(D_METHOD("get_common_name_override"), &TLSOptions::get_common_name_override);
|
||||
ClassDB::bind_method(D_METHOD("get_trusted_ca_chain"), &TLSOptions::get_trusted_ca_chain);
|
||||
ClassDB::bind_method(D_METHOD("get_private_key"), &TLSOptions::get_private_key);
|
||||
ClassDB::bind_method(D_METHOD("get_own_certificate"), &TLSOptions::get_own_certificate);
|
||||
}
|
||||
|
||||
/// HMACContext
|
||||
|
||||
void HMACContext::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("start", "hash_type", "key"), &HMACContext::start);
|
||||
ClassDB::bind_method(D_METHOD("update", "data"), &HMACContext::update);
|
||||
ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
|
||||
}
|
||||
|
||||
HMACContext *(*HMACContext::_create)(bool p_notify_postinitialize) = nullptr;
|
||||
HMACContext *HMACContext::create(bool p_notify_postinitialize) {
|
||||
if (_create) {
|
||||
return _create(p_notify_postinitialize);
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
|
||||
}
|
||||
|
||||
/// Crypto
|
||||
|
||||
void (*Crypto::_load_default_certificates)(const String &p_path) = nullptr;
|
||||
Crypto *(*Crypto::_create)(bool p_notify_postinitialize) = nullptr;
|
||||
Crypto *Crypto::create(bool p_notify_postinitialize) {
|
||||
if (_create) {
|
||||
return _create(p_notify_postinitialize);
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled.");
|
||||
}
|
||||
|
||||
void Crypto::load_default_certificates(const String &p_path) {
|
||||
if (_load_default_certificates) {
|
||||
_load_default_certificates(p_path);
|
||||
}
|
||||
}
|
||||
|
||||
PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg) {
|
||||
Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
|
||||
ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available without mbedtls module.");
|
||||
Error err = ctx->start(p_hash_type, p_key);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
err = ctx->update(p_msg);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
return ctx->finish();
|
||||
}
|
||||
|
||||
// Compares two HMACS for equality without leaking timing information in order to prevent timing attacks.
|
||||
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
bool Crypto::constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received) {
|
||||
const uint8_t *t = p_trusted.ptr();
|
||||
const uint8_t *r = p_received.ptr();
|
||||
int tlen = p_trusted.size();
|
||||
int rlen = p_received.size();
|
||||
// If the lengths are different then nothing else matters.
|
||||
if (tlen != rlen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t v = 0;
|
||||
for (int i = 0; i < tlen; i++) {
|
||||
v |= t[i] ^ r[i];
|
||||
}
|
||||
return v == 0;
|
||||
}
|
||||
|
||||
void Crypto::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes);
|
||||
ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa);
|
||||
ClassDB::bind_method(D_METHOD("generate_self_signed_certificate", "key", "issuer_name", "not_before", "not_after"), &Crypto::generate_self_signed_certificate, DEFVAL("CN=myserver,O=myorganisation,C=IT"), DEFVAL("20140101000000"), DEFVAL("20340101000000"));
|
||||
ClassDB::bind_method(D_METHOD("sign", "hash_type", "hash", "key"), &Crypto::sign);
|
||||
ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify);
|
||||
ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt);
|
||||
ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt);
|
||||
ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest);
|
||||
ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare);
|
||||
}
|
||||
|
||||
/// Resource loader/saver
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
X509Certificate *cert = X509Certificate::create();
|
||||
if (cert) {
|
||||
cert->load(p_path);
|
||||
}
|
||||
return cert;
|
||||
} else if (el == "key") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, false);
|
||||
}
|
||||
return key;
|
||||
} else if (el == "pub") {
|
||||
CryptoKey *key = CryptoKey::create();
|
||||
if (key) {
|
||||
key->load(p_path, true);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("crt");
|
||||
p_extensions->push_back("key");
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
|
||||
return p_type == "X509Certificate" || p_type == "CryptoKey";
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "crt") {
|
||||
return "X509Certificate";
|
||||
} else if (el == "key" || el == "pub") {
|
||||
return "CryptoKey";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverCrypto::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Error err;
|
||||
Ref<X509Certificate> cert = p_resource;
|
||||
Ref<CryptoKey> key = p_resource;
|
||||
if (cert.is_valid()) {
|
||||
err = cert->save(p_path);
|
||||
} else if (key.is_valid()) {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
err = key->save(p_path, el == "pub");
|
||||
} else {
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
}
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path));
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
|
||||
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
|
||||
if (cert) {
|
||||
p_extensions->push_back("crt");
|
||||
}
|
||||
if (key) {
|
||||
if (!key->is_public_only()) {
|
||||
p_extensions->push_back("key");
|
||||
}
|
||||
p_extensions->push_back("pub");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
|
||||
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CRYPTO_H
|
||||
#define CRYPTO_H
|
||||
|
||||
#include "core/crypto/hashing_context.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class CryptoKey : public Resource {
|
||||
GDCLASS(CryptoKey, Resource);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static CryptoKey *(*_create)(bool p_notify_postinitialize);
|
||||
|
||||
public:
|
||||
static CryptoKey *create(bool p_notify_postinitialize = true);
|
||||
virtual Error load(const String &p_path, bool p_public_only = false) = 0;
|
||||
virtual Error save(const String &p_path, bool p_public_only = false) = 0;
|
||||
virtual String save_to_string(bool p_public_only = false) = 0;
|
||||
virtual Error load_from_string(const String &p_string_key, bool p_public_only = false) = 0;
|
||||
virtual bool is_public_only() const = 0;
|
||||
};
|
||||
|
||||
class X509Certificate : public Resource {
|
||||
GDCLASS(X509Certificate, Resource);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static X509Certificate *(*_create)(bool p_notify_postinitialize);
|
||||
|
||||
public:
|
||||
static X509Certificate *create(bool p_notify_postinitialize = true);
|
||||
virtual Error load(const String &p_path) = 0;
|
||||
virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
|
||||
virtual Error save(const String &p_path) = 0;
|
||||
virtual String save_to_string() = 0;
|
||||
virtual Error load_from_string(const String &string) = 0;
|
||||
};
|
||||
|
||||
class TLSOptions : public RefCounted {
|
||||
GDCLASS(TLSOptions, RefCounted);
|
||||
|
||||
private:
|
||||
enum Mode {
|
||||
MODE_CLIENT = 0,
|
||||
MODE_CLIENT_UNSAFE = 1,
|
||||
MODE_SERVER = 2,
|
||||
};
|
||||
|
||||
Mode mode = MODE_CLIENT;
|
||||
String common_name;
|
||||
Ref<X509Certificate> trusted_ca_chain;
|
||||
Ref<X509Certificate> own_certificate;
|
||||
Ref<CryptoKey> private_key;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<TLSOptions> client(Ref<X509Certificate> p_trusted_chain = Ref<X509Certificate>(), const String &p_common_name_override = String());
|
||||
static Ref<TLSOptions> client_unsafe(Ref<X509Certificate> p_trusted_chain);
|
||||
static Ref<TLSOptions> server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate);
|
||||
|
||||
String get_common_name_override() const { return common_name; }
|
||||
Ref<X509Certificate> get_trusted_ca_chain() const { return trusted_ca_chain; }
|
||||
Ref<X509Certificate> get_own_certificate() const { return own_certificate; }
|
||||
Ref<CryptoKey> get_private_key() const { return private_key; }
|
||||
bool is_server() const { return mode == MODE_SERVER; }
|
||||
bool is_unsafe_client() const { return mode == MODE_CLIENT_UNSAFE; }
|
||||
};
|
||||
|
||||
class HMACContext : public RefCounted {
|
||||
GDCLASS(HMACContext, RefCounted);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static HMACContext *(*_create)(bool p_notify_postinitialize);
|
||||
|
||||
public:
|
||||
static HMACContext *create(bool p_notify_postinitialize = true);
|
||||
|
||||
virtual Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) = 0;
|
||||
virtual Error update(const PackedByteArray &p_data) = 0;
|
||||
virtual PackedByteArray finish() = 0;
|
||||
|
||||
HMACContext() {}
|
||||
virtual ~HMACContext() {}
|
||||
};
|
||||
|
||||
class Crypto : public RefCounted {
|
||||
GDCLASS(Crypto, RefCounted);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static Crypto *(*_create)(bool p_notify_postinitialize);
|
||||
static void (*_load_default_certificates)(const String &p_path);
|
||||
|
||||
public:
|
||||
static Crypto *create(bool p_notify_postinitialize = true);
|
||||
static void load_default_certificates(const String &p_path);
|
||||
|
||||
virtual PackedByteArray generate_random_bytes(int p_bytes) = 0;
|
||||
virtual Ref<CryptoKey> generate_rsa(int p_bytes) = 0;
|
||||
virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) = 0;
|
||||
|
||||
virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) = 0;
|
||||
virtual bool verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) = 0;
|
||||
virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) = 0;
|
||||
virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) = 0;
|
||||
|
||||
PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg);
|
||||
|
||||
// Compares two PackedByteArrays for equality without leaking timing information in order to prevent timing attacks.
|
||||
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
bool constant_time_compare(const PackedByteArray &p_trusted, const PackedByteArray &p_received);
|
||||
|
||||
Crypto() {}
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
|
||||
// Treat certificates as text files, do not generate a `*.{crt,key,pub}.uid` file.
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override { return ResourceUID::INVALID_ID; }
|
||||
virtual bool has_custom_uid_support() const override { return true; }
|
||||
};
|
||||
|
||||
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
||||
#endif // CRYPTO_H
|
|
@ -1,251 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto_core.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "crypto_core.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/md5.h>
|
||||
#include <mbedtls/sha1.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#if MBEDTLS_VERSION_MAJOR >= 3
|
||||
#include <mbedtls/compat-2.x.h>
|
||||
#endif
|
||||
|
||||
// RandomGenerator
|
||||
CryptoCore::RandomGenerator::RandomGenerator() {
|
||||
entropy = memalloc(sizeof(mbedtls_entropy_context));
|
||||
mbedtls_entropy_init((mbedtls_entropy_context *)entropy);
|
||||
mbedtls_entropy_add_source((mbedtls_entropy_context *)entropy, &CryptoCore::RandomGenerator::_entropy_poll, nullptr, 256, MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
ctx = memalloc(sizeof(mbedtls_ctr_drbg_context));
|
||||
mbedtls_ctr_drbg_init((mbedtls_ctr_drbg_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::RandomGenerator::~RandomGenerator() {
|
||||
mbedtls_ctr_drbg_free((mbedtls_ctr_drbg_context *)ctx);
|
||||
memfree(ctx);
|
||||
mbedtls_entropy_free((mbedtls_entropy_context *)entropy);
|
||||
memfree(entropy);
|
||||
}
|
||||
|
||||
int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len) {
|
||||
*r_len = 0;
|
||||
Error err = OS::get_singleton()->get_entropy(r_buffer, p_len);
|
||||
ERR_FAIL_COND_V(err, MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
|
||||
*r_len = p_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Error CryptoCore::RandomGenerator::init() {
|
||||
int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
|
||||
if (ret) {
|
||||
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
|
||||
ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
|
||||
int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
|
||||
ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret));
|
||||
return OK;
|
||||
}
|
||||
|
||||
// MD5
|
||||
CryptoCore::MD5Context::MD5Context() {
|
||||
ctx = memalloc(sizeof(mbedtls_md5_context));
|
||||
mbedtls_md5_init((mbedtls_md5_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::MD5Context::~MD5Context() {
|
||||
mbedtls_md5_free((mbedtls_md5_context *)ctx);
|
||||
memfree((mbedtls_md5_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::start() {
|
||||
int ret = mbedtls_md5_starts_ret((mbedtls_md5_context *)ctx);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = mbedtls_md5_update_ret((mbedtls_md5_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::MD5Context::finish(unsigned char r_hash[16]) {
|
||||
int ret = mbedtls_md5_finish_ret((mbedtls_md5_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// SHA1
|
||||
CryptoCore::SHA1Context::SHA1Context() {
|
||||
ctx = memalloc(sizeof(mbedtls_sha1_context));
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::SHA1Context::~SHA1Context() {
|
||||
mbedtls_sha1_free((mbedtls_sha1_context *)ctx);
|
||||
memfree((mbedtls_sha1_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::start() {
|
||||
int ret = mbedtls_sha1_starts_ret((mbedtls_sha1_context *)ctx);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = mbedtls_sha1_update_ret((mbedtls_sha1_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA1Context::finish(unsigned char r_hash[20]) {
|
||||
int ret = mbedtls_sha1_finish_ret((mbedtls_sha1_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// SHA256
|
||||
CryptoCore::SHA256Context::SHA256Context() {
|
||||
ctx = memalloc(sizeof(mbedtls_sha256_context));
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::SHA256Context::~SHA256Context() {
|
||||
mbedtls_sha256_free((mbedtls_sha256_context *)ctx);
|
||||
memfree((mbedtls_sha256_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::start() {
|
||||
int ret = mbedtls_sha256_starts_ret((mbedtls_sha256_context *)ctx, 0);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::update(const uint8_t *p_src, size_t p_len) {
|
||||
int ret = mbedtls_sha256_update_ret((mbedtls_sha256_context *)ctx, p_src, p_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::SHA256Context::finish(unsigned char r_hash[32]) {
|
||||
int ret = mbedtls_sha256_finish_ret((mbedtls_sha256_context *)ctx, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// AES256
|
||||
CryptoCore::AESContext::AESContext() {
|
||||
ctx = memalloc(sizeof(mbedtls_aes_context));
|
||||
mbedtls_aes_init((mbedtls_aes_context *)ctx);
|
||||
}
|
||||
|
||||
CryptoCore::AESContext::~AESContext() {
|
||||
mbedtls_aes_free((mbedtls_aes_context *)ctx);
|
||||
memfree((mbedtls_aes_context *)ctx);
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::set_encode_key(const uint8_t *p_key, size_t p_bits) {
|
||||
int ret = mbedtls_aes_setkey_enc((mbedtls_aes_context *)ctx, p_key, p_bits);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::set_decode_key(const uint8_t *p_key, size_t p_bits) {
|
||||
int ret = mbedtls_aes_setkey_dec((mbedtls_aes_context *)ctx, p_key, p_bits);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
|
||||
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
|
||||
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
|
||||
int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, r_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
|
||||
size_t iv_off = 0; // Ignore and assume 16-byte alignment.
|
||||
int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
// CryptoCore
|
||||
String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
|
||||
int b64len = p_src_len / 3 * 4 + 4 + 1;
|
||||
Vector<uint8_t> b64buff;
|
||||
b64buff.resize(b64len);
|
||||
uint8_t *w64 = b64buff.ptrw();
|
||||
size_t strlen = 0;
|
||||
int ret = b64_encode(&w64[0], b64len, &strlen, p_src, p_src_len);
|
||||
w64[strlen] = 0;
|
||||
return ret ? String() : (const char *)&w64[0];
|
||||
}
|
||||
|
||||
Error CryptoCore::b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) {
|
||||
int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) {
|
||||
int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]) {
|
||||
int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]) {
|
||||
int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error CryptoCore::sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]) {
|
||||
int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0);
|
||||
return ret ? FAILED : OK;
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* crypto_core.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CRYPTO_CORE_H
|
||||
#define CRYPTO_CORE_H
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class CryptoCore {
|
||||
public:
|
||||
class RandomGenerator {
|
||||
private:
|
||||
void *entropy = nullptr;
|
||||
void *ctx = nullptr;
|
||||
|
||||
static int _entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len);
|
||||
|
||||
public:
|
||||
RandomGenerator();
|
||||
~RandomGenerator();
|
||||
|
||||
Error init();
|
||||
Error get_random_bytes(uint8_t *r_buffer, size_t p_bytes);
|
||||
};
|
||||
|
||||
class MD5Context {
|
||||
private:
|
||||
void *ctx = nullptr;
|
||||
|
||||
public:
|
||||
MD5Context();
|
||||
~MD5Context();
|
||||
|
||||
Error start();
|
||||
Error update(const uint8_t *p_src, size_t p_len);
|
||||
Error finish(unsigned char r_hash[16]);
|
||||
};
|
||||
|
||||
class SHA1Context {
|
||||
private:
|
||||
void *ctx = nullptr;
|
||||
|
||||
public:
|
||||
SHA1Context();
|
||||
~SHA1Context();
|
||||
|
||||
Error start();
|
||||
Error update(const uint8_t *p_src, size_t p_len);
|
||||
Error finish(unsigned char r_hash[20]);
|
||||
};
|
||||
|
||||
class SHA256Context {
|
||||
private:
|
||||
void *ctx = nullptr;
|
||||
|
||||
public:
|
||||
SHA256Context();
|
||||
~SHA256Context();
|
||||
|
||||
Error start();
|
||||
Error update(const uint8_t *p_src, size_t p_len);
|
||||
Error finish(unsigned char r_hash[32]);
|
||||
};
|
||||
|
||||
class AESContext {
|
||||
private:
|
||||
void *ctx = nullptr;
|
||||
|
||||
public:
|
||||
AESContext();
|
||||
~AESContext();
|
||||
|
||||
Error set_encode_key(const uint8_t *p_key, size_t p_bits);
|
||||
Error set_decode_key(const uint8_t *p_key, size_t p_bits);
|
||||
Error encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
|
||||
Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
|
||||
Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
|
||||
};
|
||||
|
||||
static String b64_encode_str(const uint8_t *p_src, int p_src_len);
|
||||
static Error b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len);
|
||||
static Error b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len);
|
||||
|
||||
static Error md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]);
|
||||
static Error sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]);
|
||||
static Error sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]);
|
||||
};
|
||||
|
||||
#endif // CRYPTO_CORE_H
|
|
@ -1,134 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* hashing_context.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "hashing_context.h"
|
||||
|
||||
#include "core/crypto/crypto_core.h"
|
||||
|
||||
Error HashingContext::start(HashType p_type) {
|
||||
ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
|
||||
_create_ctx(p_type);
|
||||
ERR_FAIL_NULL_V(ctx, ERR_UNAVAILABLE);
|
||||
switch (type) {
|
||||
case HASH_MD5:
|
||||
return ((CryptoCore::MD5Context *)ctx)->start();
|
||||
case HASH_SHA1:
|
||||
return ((CryptoCore::SHA1Context *)ctx)->start();
|
||||
case HASH_SHA256:
|
||||
return ((CryptoCore::SHA256Context *)ctx)->start();
|
||||
}
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
Error HashingContext::update(const PackedByteArray &p_chunk) {
|
||||
ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
|
||||
size_t len = p_chunk.size();
|
||||
ERR_FAIL_COND_V(len == 0, FAILED);
|
||||
const uint8_t *r = p_chunk.ptr();
|
||||
switch (type) {
|
||||
case HASH_MD5:
|
||||
return ((CryptoCore::MD5Context *)ctx)->update(&r[0], len);
|
||||
case HASH_SHA1:
|
||||
return ((CryptoCore::SHA1Context *)ctx)->update(&r[0], len);
|
||||
case HASH_SHA256:
|
||||
return ((CryptoCore::SHA256Context *)ctx)->update(&r[0], len);
|
||||
}
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
PackedByteArray HashingContext::finish() {
|
||||
ERR_FAIL_NULL_V(ctx, PackedByteArray());
|
||||
PackedByteArray out;
|
||||
Error err = FAILED;
|
||||
switch (type) {
|
||||
case HASH_MD5:
|
||||
out.resize(16);
|
||||
err = ((CryptoCore::MD5Context *)ctx)->finish(out.ptrw());
|
||||
break;
|
||||
case HASH_SHA1:
|
||||
out.resize(20);
|
||||
err = ((CryptoCore::SHA1Context *)ctx)->finish(out.ptrw());
|
||||
break;
|
||||
case HASH_SHA256:
|
||||
out.resize(32);
|
||||
err = ((CryptoCore::SHA256Context *)ctx)->finish(out.ptrw());
|
||||
break;
|
||||
}
|
||||
_delete_ctx();
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
return out;
|
||||
}
|
||||
|
||||
void HashingContext::_create_ctx(HashType p_type) {
|
||||
type = p_type;
|
||||
switch (type) {
|
||||
case HASH_MD5:
|
||||
ctx = memnew(CryptoCore::MD5Context);
|
||||
break;
|
||||
case HASH_SHA1:
|
||||
ctx = memnew(CryptoCore::SHA1Context);
|
||||
break;
|
||||
case HASH_SHA256:
|
||||
ctx = memnew(CryptoCore::SHA256Context);
|
||||
break;
|
||||
default:
|
||||
ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HashingContext::_delete_ctx() {
|
||||
switch (type) {
|
||||
case HASH_MD5:
|
||||
memdelete((CryptoCore::MD5Context *)ctx);
|
||||
break;
|
||||
case HASH_SHA1:
|
||||
memdelete((CryptoCore::SHA1Context *)ctx);
|
||||
break;
|
||||
case HASH_SHA256:
|
||||
memdelete((CryptoCore::SHA256Context *)ctx);
|
||||
break;
|
||||
}
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
void HashingContext::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("start", "type"), &HashingContext::start);
|
||||
ClassDB::bind_method(D_METHOD("update", "chunk"), &HashingContext::update);
|
||||
ClassDB::bind_method(D_METHOD("finish"), &HashingContext::finish);
|
||||
BIND_ENUM_CONSTANT(HASH_MD5);
|
||||
BIND_ENUM_CONSTANT(HASH_SHA1);
|
||||
BIND_ENUM_CONSTANT(HASH_SHA256);
|
||||
}
|
||||
|
||||
HashingContext::~HashingContext() {
|
||||
if (ctx != nullptr) {
|
||||
_delete_ctx();
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* hashing_context.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef HASHING_CONTEXT_H
|
||||
#define HASHING_CONTEXT_H
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class HashingContext : public RefCounted {
|
||||
GDCLASS(HashingContext, RefCounted);
|
||||
|
||||
public:
|
||||
enum HashType : int32_t {
|
||||
HASH_MD5,
|
||||
HASH_SHA1,
|
||||
HASH_SHA256
|
||||
};
|
||||
|
||||
private:
|
||||
void *ctx = nullptr;
|
||||
HashType type = HASH_MD5;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _create_ctx(HashType p_type);
|
||||
void _delete_ctx();
|
||||
|
||||
public:
|
||||
Error start(HashType p_type);
|
||||
Error update(const PackedByteArray &p_chunk);
|
||||
PackedByteArray finish();
|
||||
|
||||
HashingContext() {}
|
||||
~HashingContext();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(HashingContext::HashType);
|
||||
|
||||
#endif // HASHING_CONTEXT_H
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
|
@ -1,183 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* debugger_marshalls.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "debugger_marshalls.h"
|
||||
|
||||
#include "core/io/marshalls.h"
|
||||
|
||||
#define CHECK_SIZE(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() < (uint32_t)(expected), false, String("Malformed ") + what + " message from script debugger, message too short. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
|
||||
#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size()))
|
||||
|
||||
Array DebuggerMarshalls::ScriptStackDump::serialize() {
|
||||
Array arr;
|
||||
arr.push_back(frames.size() * 3);
|
||||
for (const ScriptLanguage::StackInfo &frame : frames) {
|
||||
arr.push_back(frame.file);
|
||||
arr.push_back(frame.line);
|
||||
arr.push_back(frame.func);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool DebuggerMarshalls::ScriptStackDump::deserialize(const Array &p_arr) {
|
||||
CHECK_SIZE(p_arr, 1, "ScriptStackDump");
|
||||
uint32_t size = p_arr[0];
|
||||
CHECK_SIZE(p_arr, size, "ScriptStackDump");
|
||||
int idx = 1;
|
||||
for (uint32_t i = 0; i < size / 3; i++) {
|
||||
ScriptLanguage::StackInfo sf;
|
||||
sf.file = p_arr[idx];
|
||||
sf.line = p_arr[idx + 1];
|
||||
sf.func = p_arr[idx + 2];
|
||||
frames.push_back(sf);
|
||||
idx += 3;
|
||||
}
|
||||
CHECK_END(p_arr, idx, "ScriptStackDump");
|
||||
return true;
|
||||
}
|
||||
|
||||
Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
|
||||
Array arr;
|
||||
arr.push_back(name);
|
||||
arr.push_back(type);
|
||||
arr.push_back(value.get_type());
|
||||
|
||||
Variant var = value;
|
||||
if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
|
||||
var = Variant();
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
Error err = encode_variant(var, nullptr, len, false);
|
||||
if (err != OK) {
|
||||
ERR_PRINT("Failed to encode variant.");
|
||||
}
|
||||
|
||||
if (len > max_size) {
|
||||
arr.push_back(Variant());
|
||||
} else {
|
||||
arr.push_back(var);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
|
||||
CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
|
||||
name = p_arr[0];
|
||||
type = p_arr[1];
|
||||
var_type = p_arr[2];
|
||||
value = p_arr[3];
|
||||
CHECK_END(p_arr, 4, "ScriptStackVariable");
|
||||
return true;
|
||||
}
|
||||
|
||||
Array DebuggerMarshalls::OutputError::serialize() {
|
||||
Array arr;
|
||||
arr.push_back(hr);
|
||||
arr.push_back(min);
|
||||
arr.push_back(sec);
|
||||
arr.push_back(msec);
|
||||
arr.push_back(source_file);
|
||||
arr.push_back(source_func);
|
||||
arr.push_back(source_line);
|
||||
arr.push_back(error);
|
||||
arr.push_back(error_descr);
|
||||
arr.push_back(warning);
|
||||
unsigned int size = callstack.size();
|
||||
const ScriptLanguage::StackInfo *r = callstack.ptr();
|
||||
arr.push_back(size * 3);
|
||||
for (int i = 0; i < callstack.size(); i++) {
|
||||
arr.push_back(r[i].file);
|
||||
arr.push_back(r[i].func);
|
||||
arr.push_back(r[i].line);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool DebuggerMarshalls::OutputError::deserialize(const Array &p_arr) {
|
||||
CHECK_SIZE(p_arr, 11, "OutputError");
|
||||
hr = p_arr[0];
|
||||
min = p_arr[1];
|
||||
sec = p_arr[2];
|
||||
msec = p_arr[3];
|
||||
source_file = p_arr[4];
|
||||
source_func = p_arr[5];
|
||||
source_line = p_arr[6];
|
||||
error = p_arr[7];
|
||||
error_descr = p_arr[8];
|
||||
warning = p_arr[9];
|
||||
unsigned int stack_size = p_arr[10];
|
||||
CHECK_SIZE(p_arr, stack_size, "OutputError");
|
||||
int idx = 11;
|
||||
callstack.resize(stack_size / 3);
|
||||
ScriptLanguage::StackInfo *w = callstack.ptrw();
|
||||
for (unsigned int i = 0; i < stack_size / 3; i++) {
|
||||
w[i].file = p_arr[idx];
|
||||
w[i].func = p_arr[idx + 1];
|
||||
w[i].line = p_arr[idx + 2];
|
||||
idx += 3;
|
||||
}
|
||||
CHECK_END(p_arr, idx, "OutputError");
|
||||
return true;
|
||||
}
|
||||
|
||||
Array DebuggerMarshalls::serialize_key_shortcut(const Ref<Shortcut> &p_shortcut) {
|
||||
ERR_FAIL_COND_V(p_shortcut.is_null(), Array());
|
||||
Array keys;
|
||||
for (const Ref<InputEvent> ev : p_shortcut->get_events()) {
|
||||
const Ref<InputEventKey> kev = ev;
|
||||
ERR_CONTINUE(kev.is_null());
|
||||
if (kev->get_physical_keycode() != Key::NONE) {
|
||||
keys.push_back(true);
|
||||
keys.push_back(kev->get_physical_keycode_with_modifiers());
|
||||
} else {
|
||||
keys.push_back(false);
|
||||
keys.push_back(kev->get_keycode_with_modifiers());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
Ref<Shortcut> DebuggerMarshalls::deserialize_key_shortcut(const Array &p_keys) {
|
||||
Array key_events;
|
||||
ERR_FAIL_COND_V(p_keys.size() % 2 != 0, Ref<Shortcut>());
|
||||
for (int i = 0; i < p_keys.size(); i += 2) {
|
||||
ERR_CONTINUE(p_keys[i].get_type() != Variant::BOOL);
|
||||
ERR_CONTINUE(p_keys[i + 1].get_type() != Variant::INT);
|
||||
key_events.push_back(InputEventKey::create_reference((Key)p_keys[i + 1].operator int(), p_keys[i].operator bool()));
|
||||
}
|
||||
if (key_events.is_empty()) {
|
||||
return Ref<Shortcut>();
|
||||
}
|
||||
Ref<Shortcut> shortcut;
|
||||
shortcut.instantiate();
|
||||
shortcut->set_events(key_events);
|
||||
return shortcut;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* debugger_marshalls.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUGGER_MARSHALLS_H
|
||||
#define DEBUGGER_MARSHALLS_H
|
||||
|
||||
#include "core/input/shortcut.h"
|
||||
#include "core/object/script_language.h"
|
||||
|
||||
struct DebuggerMarshalls {
|
||||
struct ScriptStackVariable {
|
||||
String name;
|
||||
Variant value;
|
||||
int type = -1;
|
||||
int var_type = -1;
|
||||
|
||||
Array serialize(int max_size = 1 << 20); // 1 MiB default.
|
||||
bool deserialize(const Array &p_arr);
|
||||
};
|
||||
|
||||
struct ScriptStackDump {
|
||||
List<ScriptLanguage::StackInfo> frames;
|
||||
ScriptStackDump() {}
|
||||
|
||||
Array serialize();
|
||||
bool deserialize(const Array &p_arr);
|
||||
};
|
||||
|
||||
struct OutputError {
|
||||
int hr = -1;
|
||||
int min = -1;
|
||||
int sec = -1;
|
||||
int msec = -1;
|
||||
String source_file;
|
||||
String source_func;
|
||||
int source_line = -1;
|
||||
String error;
|
||||
String error_descr;
|
||||
bool warning = false;
|
||||
Vector<ScriptLanguage::StackInfo> callstack;
|
||||
|
||||
Array serialize();
|
||||
bool deserialize(const Array &p_arr);
|
||||
};
|
||||
|
||||
static Array serialize_key_shortcut(const Ref<Shortcut> &p_shortcut);
|
||||
static Ref<Shortcut> deserialize_key_shortcut(const Array &p_keys);
|
||||
};
|
||||
|
||||
#endif // DEBUGGER_MARSHALLS_H
|
|
@ -1,203 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine_debugger.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "engine_debugger.h"
|
||||
|
||||
#include "core/debugger/local_debugger.h"
|
||||
#include "core/debugger/remote_debugger.h"
|
||||
#include "core/debugger/remote_debugger_peer.h"
|
||||
#include "core/debugger/script_debugger.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
EngineDebugger *EngineDebugger::singleton = nullptr;
|
||||
ScriptDebugger *EngineDebugger::script_debugger = nullptr;
|
||||
|
||||
HashMap<StringName, EngineDebugger::Profiler> EngineDebugger::profilers;
|
||||
HashMap<StringName, EngineDebugger::Capture> EngineDebugger::captures;
|
||||
HashMap<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols;
|
||||
|
||||
void (*EngineDebugger::allow_focus_steal_fn)();
|
||||
|
||||
void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
|
||||
ERR_FAIL_COND_MSG(profilers.has(p_name), vformat("Profiler already registered: '%s'.", p_name));
|
||||
profilers.insert(p_name, p_func);
|
||||
}
|
||||
|
||||
void EngineDebugger::unregister_profiler(const StringName &p_name) {
|
||||
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name));
|
||||
Profiler &p = profilers[p_name];
|
||||
if (p.active && p.toggle) {
|
||||
p.toggle(p.data, false, Array());
|
||||
p.active = false;
|
||||
}
|
||||
profilers.erase(p_name);
|
||||
}
|
||||
|
||||
void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) {
|
||||
ERR_FAIL_COND_MSG(captures.has(p_name), vformat("Capture already registered: '%s'.", p_name));
|
||||
captures.insert(p_name, p_func);
|
||||
}
|
||||
|
||||
void EngineDebugger::unregister_message_capture(const StringName &p_name) {
|
||||
ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name));
|
||||
captures.erase(p_name);
|
||||
}
|
||||
|
||||
void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
|
||||
ERR_FAIL_COND_MSG(protocols.has(p_protocol), vformat("Protocol handler already registered: '%s'.", p_protocol));
|
||||
protocols.insert(p_protocol, p_func);
|
||||
}
|
||||
|
||||
void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
|
||||
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't change profiler state, no profiler: '%s'.", p_name));
|
||||
Profiler &p = profilers[p_name];
|
||||
if (p.toggle) {
|
||||
p.toggle(p.data, p_enabled, p_opts);
|
||||
}
|
||||
p.active = p_enabled;
|
||||
}
|
||||
|
||||
void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
|
||||
ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't add frame data, no profiler: '%s'.", p_name));
|
||||
Profiler &p = profilers[p_name];
|
||||
if (p.add) {
|
||||
p.add(p.data, p_data);
|
||||
}
|
||||
}
|
||||
|
||||
bool EngineDebugger::is_profiling(const StringName &p_name) {
|
||||
return profilers.has(p_name) && profilers[p_name].active;
|
||||
}
|
||||
|
||||
bool EngineDebugger::has_profiler(const StringName &p_name) {
|
||||
return profilers.has(p_name);
|
||||
}
|
||||
|
||||
bool EngineDebugger::has_capture(const StringName &p_name) {
|
||||
return captures.has(p_name);
|
||||
}
|
||||
|
||||
Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) {
|
||||
r_captured = false;
|
||||
ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, vformat("Capture not registered: '%s'.", p_name));
|
||||
const Capture &cap = captures[p_name];
|
||||
return cap.capture(cap.data, p_msg, p_args, r_captured);
|
||||
}
|
||||
|
||||
void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time) {
|
||||
frame_time = USEC_TO_SEC(p_frame_ticks);
|
||||
process_time = USEC_TO_SEC(p_process_ticks);
|
||||
physics_time = USEC_TO_SEC(p_physics_ticks);
|
||||
physics_frame_time = p_physics_frame_time;
|
||||
// Notify tick to running profilers
|
||||
for (KeyValue<StringName, Profiler> &E : profilers) {
|
||||
Profiler &p = E.value;
|
||||
if (!p.active || !p.tick) {
|
||||
continue;
|
||||
}
|
||||
p.tick(p.data, frame_time, process_time, physics_time, physics_frame_time);
|
||||
}
|
||||
singleton->poll_events(true);
|
||||
}
|
||||
|
||||
void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) {
|
||||
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
|
||||
if (p_uri.is_empty()) {
|
||||
return;
|
||||
}
|
||||
if (p_uri == "local://") {
|
||||
singleton = memnew(LocalDebugger);
|
||||
script_debugger = memnew(ScriptDebugger);
|
||||
// Tell the OS that we want to handle termination signals.
|
||||
OS::get_singleton()->initialize_debugging();
|
||||
} else if (p_uri.contains("://")) {
|
||||
const String proto = p_uri.substr(0, p_uri.find("://") + 3);
|
||||
if (!protocols.has(proto)) {
|
||||
return;
|
||||
}
|
||||
RemoteDebuggerPeer *peer = protocols[proto](p_uri);
|
||||
if (!peer) {
|
||||
return;
|
||||
}
|
||||
singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
|
||||
script_debugger = memnew(ScriptDebugger);
|
||||
// Notify editor of our pid (to allow focus stealing).
|
||||
Array msg;
|
||||
msg.push_back(OS::get_singleton()->get_process_id());
|
||||
singleton->send_message("set_pid", msg);
|
||||
}
|
||||
if (!singleton) {
|
||||
return;
|
||||
}
|
||||
|
||||
// There is a debugger, parse breakpoints.
|
||||
ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger();
|
||||
singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints);
|
||||
|
||||
for (int i = 0; i < p_breakpoints.size(); i++) {
|
||||
const String &bp = p_breakpoints[i];
|
||||
int sp = bp.rfind_char(':');
|
||||
ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
|
||||
|
||||
singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));
|
||||
}
|
||||
|
||||
allow_focus_steal_fn = p_allow_focus_steal_fn;
|
||||
}
|
||||
|
||||
void EngineDebugger::deinitialize() {
|
||||
if (singleton) {
|
||||
// Stop all profilers
|
||||
for (const KeyValue<StringName, Profiler> &E : profilers) {
|
||||
if (E.value.active) {
|
||||
singleton->profiler_enable(E.key, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any remaining message
|
||||
singleton->poll_events(false);
|
||||
|
||||
memdelete(singleton);
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
// Clear profilers/captures/protocol handlers.
|
||||
profilers.clear();
|
||||
captures.clear();
|
||||
protocols.clear();
|
||||
}
|
||||
|
||||
EngineDebugger::~EngineDebugger() {
|
||||
if (script_debugger) {
|
||||
memdelete(script_debugger);
|
||||
}
|
||||
script_debugger = nullptr;
|
||||
singleton = nullptr;
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine_debugger.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENGINE_DEBUGGER_H
|
||||
#define ENGINE_DEBUGGER_H
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/variant/array.h"
|
||||
|
||||
class RemoteDebuggerPeer;
|
||||
class ScriptDebugger;
|
||||
|
||||
class EngineDebugger {
|
||||
public:
|
||||
typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts);
|
||||
typedef void (*ProfilingTick)(void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
|
||||
typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr);
|
||||
|
||||
typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
|
||||
|
||||
typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri);
|
||||
|
||||
class Profiler {
|
||||
friend class EngineDebugger;
|
||||
|
||||
ProfilingToggle toggle = nullptr;
|
||||
ProfilingAdd add = nullptr;
|
||||
ProfilingTick tick = nullptr;
|
||||
void *data = nullptr;
|
||||
bool active = false;
|
||||
|
||||
public:
|
||||
Profiler() {}
|
||||
Profiler(void *p_data, ProfilingToggle p_toggle, ProfilingAdd p_add, ProfilingTick p_tick) {
|
||||
data = p_data;
|
||||
toggle = p_toggle;
|
||||
add = p_add;
|
||||
tick = p_tick;
|
||||
}
|
||||
};
|
||||
|
||||
class Capture {
|
||||
friend class EngineDebugger;
|
||||
|
||||
CaptureFunc capture = nullptr;
|
||||
void *data = nullptr;
|
||||
|
||||
public:
|
||||
Capture() {}
|
||||
Capture(void *p_data, CaptureFunc p_capture) {
|
||||
data = p_data;
|
||||
capture = p_capture;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
double frame_time = 0.0;
|
||||
double process_time = 0.0;
|
||||
double physics_time = 0.0;
|
||||
double physics_frame_time = 0.0;
|
||||
|
||||
uint32_t poll_every = 0;
|
||||
|
||||
protected:
|
||||
static EngineDebugger *singleton;
|
||||
static ScriptDebugger *script_debugger;
|
||||
|
||||
static HashMap<StringName, Profiler> profilers;
|
||||
static HashMap<StringName, Capture> captures;
|
||||
static HashMap<String, CreatePeerFunc> protocols;
|
||||
|
||||
static void (*allow_focus_steal_fn)();
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
|
||||
_FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
|
||||
|
||||
_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; }
|
||||
|
||||
static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)());
|
||||
static void deinitialize();
|
||||
static void register_profiler(const StringName &p_name, const Profiler &p_profiler);
|
||||
static void unregister_profiler(const StringName &p_name);
|
||||
static bool is_profiling(const StringName &p_name);
|
||||
static bool has_profiler(const StringName &p_name);
|
||||
static void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
|
||||
|
||||
static void register_message_capture(const StringName &p_name, Capture p_func);
|
||||
static void unregister_message_capture(const StringName &p_name);
|
||||
static bool has_capture(const StringName &p_name);
|
||||
|
||||
static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func);
|
||||
|
||||
void iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time);
|
||||
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
|
||||
Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured);
|
||||
|
||||
void line_poll() {
|
||||
// The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught.
|
||||
if (unlikely(poll_every % 2048) == 0) {
|
||||
poll_events(false);
|
||||
}
|
||||
poll_every++;
|
||||
}
|
||||
|
||||
virtual void poll_events(bool p_is_idle) {}
|
||||
virtual void send_message(const String &p_msg, const Array &p_data) = 0;
|
||||
virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) = 0;
|
||||
virtual void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false) = 0;
|
||||
|
||||
virtual ~EngineDebugger();
|
||||
};
|
||||
|
||||
#endif // ENGINE_DEBUGGER_H
|
|
@ -1,82 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine_profiler.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "engine_profiler.h"
|
||||
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
|
||||
void EngineProfiler::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_toggle, "enable", "options");
|
||||
GDVIRTUAL_BIND(_add_frame, "data");
|
||||
GDVIRTUAL_BIND(_tick, "frame_time", "process_time", "physics_time", "physics_frame_time");
|
||||
}
|
||||
|
||||
void EngineProfiler::toggle(bool p_enable, const Array &p_array) {
|
||||
GDVIRTUAL_CALL(_toggle, p_enable, p_array);
|
||||
}
|
||||
|
||||
void EngineProfiler::add(const Array &p_data) {
|
||||
GDVIRTUAL_CALL(_add_frame, p_data);
|
||||
}
|
||||
|
||||
void EngineProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
|
||||
GDVIRTUAL_CALL(_tick, p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
|
||||
}
|
||||
|
||||
Error EngineProfiler::bind(const String &p_name) {
|
||||
ERR_FAIL_COND_V(is_bound(), ERR_ALREADY_IN_USE);
|
||||
EngineDebugger::Profiler prof(
|
||||
this,
|
||||
[](void *p_user, bool p_enable, const Array &p_opts) {
|
||||
static_cast<EngineProfiler *>(p_user)->toggle(p_enable, p_opts);
|
||||
},
|
||||
[](void *p_user, const Array &p_data) {
|
||||
static_cast<EngineProfiler *>(p_user)->add(p_data);
|
||||
},
|
||||
[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
|
||||
static_cast<EngineProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
|
||||
});
|
||||
registration = p_name;
|
||||
EngineDebugger::register_profiler(p_name, prof);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error EngineProfiler::unbind() {
|
||||
ERR_FAIL_COND_V(!is_bound(), ERR_UNCONFIGURED);
|
||||
EngineDebugger::unregister_profiler(registration);
|
||||
registration.clear();
|
||||
return OK;
|
||||
}
|
||||
|
||||
EngineProfiler::~EngineProfiler() {
|
||||
if (is_bound()) {
|
||||
unbind();
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* engine_profiler.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENGINE_PROFILER_H
|
||||
#define ENGINE_PROFILER_H
|
||||
|
||||
#include "core/object/gdvirtual.gen.inc"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class EngineProfiler : public RefCounted {
|
||||
GDCLASS(EngineProfiler, RefCounted);
|
||||
|
||||
private:
|
||||
String registration;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void toggle(bool p_enable, const Array &p_opts);
|
||||
virtual void add(const Array &p_data);
|
||||
virtual void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
|
||||
|
||||
Error bind(const String &p_name);
|
||||
Error unbind();
|
||||
bool is_bound() const { return registration.length() > 0; }
|
||||
|
||||
GDVIRTUAL2(_toggle, bool, Array);
|
||||
GDVIRTUAL1(_add_frame, Array);
|
||||
GDVIRTUAL4(_tick, double, double, double, double);
|
||||
|
||||
EngineProfiler() {}
|
||||
virtual ~EngineProfiler();
|
||||
};
|
||||
|
||||
#endif // ENGINE_PROFILER_H
|
|
@ -1,390 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* local_debugger.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "local_debugger.h"
|
||||
|
||||
#include "core/debugger/script_debugger.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
struct LocalDebugger::ScriptsProfiler {
|
||||
struct ProfileInfoSort {
|
||||
bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const {
|
||||
return A.total_time > B.total_time;
|
||||
}
|
||||
};
|
||||
|
||||
double frame_time = 0;
|
||||
uint64_t idle_accum = 0;
|
||||
Vector<ScriptLanguage::ProfilingInfo> pinfo;
|
||||
|
||||
void toggle(bool p_enable, const Array &p_opts) {
|
||||
if (p_enable) {
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptServer::get_language(i)->profiling_start();
|
||||
}
|
||||
|
||||
print_line("BEGIN PROFILING");
|
||||
pinfo.resize(32768);
|
||||
} else {
|
||||
_print_frame_data(true);
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptServer::get_language(i)->profiling_stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
|
||||
frame_time = p_frame_time;
|
||||
_print_frame_data(false);
|
||||
}
|
||||
|
||||
void _print_frame_data(bool p_accumulated) {
|
||||
uint64_t diff = OS::get_singleton()->get_ticks_usec() - idle_accum;
|
||||
|
||||
if (!p_accumulated && diff < 1000000) { //show every one second
|
||||
return;
|
||||
}
|
||||
|
||||
idle_accum = OS::get_singleton()->get_ticks_usec();
|
||||
|
||||
int ofs = 0;
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
if (p_accumulated) {
|
||||
ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo.write[ofs], pinfo.size() - ofs);
|
||||
} else {
|
||||
ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo.write[ofs], pinfo.size() - ofs);
|
||||
}
|
||||
}
|
||||
|
||||
SortArray<ScriptLanguage::ProfilingInfo, ProfileInfoSort> sort;
|
||||
sort.sort(pinfo.ptrw(), ofs);
|
||||
|
||||
// compute total script frame time
|
||||
uint64_t script_time_us = 0;
|
||||
for (int i = 0; i < ofs; i++) {
|
||||
script_time_us += pinfo[i].self_time;
|
||||
}
|
||||
double script_time = USEC_TO_SEC(script_time_us);
|
||||
double total_time = p_accumulated ? script_time : frame_time;
|
||||
|
||||
if (!p_accumulated) {
|
||||
print_line("FRAME: total: " + rtos(total_time) + " script: " + rtos(script_time) + "/" + itos(script_time * 100 / total_time) + " %");
|
||||
} else {
|
||||
print_line("ACCUMULATED: total: " + rtos(total_time));
|
||||
}
|
||||
|
||||
for (int i = 0; i < ofs; i++) {
|
||||
print_line(itos(i) + ":" + pinfo[i].signature);
|
||||
double tt = USEC_TO_SEC(pinfo[i].total_time);
|
||||
double st = USEC_TO_SEC(pinfo[i].self_time);
|
||||
print_line("\ttotal: " + rtos(tt) + "/" + itos(tt * 100 / total_time) + " % \tself: " + rtos(st) + "/" + itos(st * 100 / total_time) + " % tcalls: " + itos(pinfo[i].call_count));
|
||||
}
|
||||
}
|
||||
|
||||
ScriptsProfiler() {
|
||||
idle_accum = OS::get_singleton()->get_ticks_usec();
|
||||
}
|
||||
};
|
||||
|
||||
void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
|
||||
ScriptLanguage *script_lang = script_debugger->get_break_language();
|
||||
|
||||
if (!target_function.is_empty()) {
|
||||
String current_function = script_lang->debug_get_stack_level_function(0);
|
||||
if (current_function != target_function) {
|
||||
script_debugger->set_depth(0);
|
||||
script_debugger->set_lines_left(1);
|
||||
return;
|
||||
}
|
||||
target_function = "";
|
||||
}
|
||||
|
||||
print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
|
||||
print_line("*Frame " + itos(0) + " - " + script_lang->debug_get_stack_level_source(0) + ":" + itos(script_lang->debug_get_stack_level_line(0)) + " in function '" + script_lang->debug_get_stack_level_function(0) + "'");
|
||||
print_line("Enter \"help\" for assistance.");
|
||||
int current_frame = 0;
|
||||
int total_frames = script_lang->debug_get_stack_level_count();
|
||||
while (true) {
|
||||
OS::get_singleton()->print("debug> ");
|
||||
String line = OS::get_singleton()->get_stdin_string().strip_edges();
|
||||
|
||||
// Cache options
|
||||
String variable_prefix = options["variable_prefix"];
|
||||
|
||||
if (line.is_empty() && !feof(stdin)) {
|
||||
print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
|
||||
print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
|
||||
print_line("Enter \"help\" for assistance.");
|
||||
} else if (line == "c" || line == "continue") {
|
||||
break;
|
||||
} else if (line == "bt" || line == "breakpoint") {
|
||||
for (int i = 0; i < total_frames; i++) {
|
||||
String cfi = (current_frame == i) ? "*" : " "; //current frame indicator
|
||||
print_line(cfi + "Frame " + itos(i) + " - " + script_lang->debug_get_stack_level_source(i) + ":" + itos(script_lang->debug_get_stack_level_line(i)) + " in function '" + script_lang->debug_get_stack_level_function(i) + "'");
|
||||
}
|
||||
|
||||
} else if (line.begins_with("fr") || line.begins_with("frame")) {
|
||||
if (line.get_slice_count(" ") == 1) {
|
||||
print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
|
||||
} else {
|
||||
int frame = line.get_slicec(' ', 1).to_int();
|
||||
if (frame < 0 || frame >= total_frames) {
|
||||
print_line("Error: Invalid frame.");
|
||||
} else {
|
||||
current_frame = frame;
|
||||
print_line("*Frame " + itos(frame) + " - " + script_lang->debug_get_stack_level_source(frame) + ":" + itos(script_lang->debug_get_stack_level_line(frame)) + " in function '" + script_lang->debug_get_stack_level_function(frame) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (line.begins_with("set")) {
|
||||
if (line.get_slice_count(" ") == 1) {
|
||||
for (const KeyValue<String, String> &E : options) {
|
||||
print_line("\t" + E.key + "=" + E.value);
|
||||
}
|
||||
|
||||
} else {
|
||||
String key_value = line.get_slicec(' ', 1);
|
||||
int value_pos = key_value.find_char('=');
|
||||
|
||||
if (value_pos < 0) {
|
||||
print_line("Error: Invalid set format. Use: set key=value");
|
||||
} else {
|
||||
String key = key_value.left(value_pos);
|
||||
|
||||
if (!options.has(key)) {
|
||||
print_line("Error: Unknown option " + key);
|
||||
} else {
|
||||
// Allow explicit tab character
|
||||
String value = key_value.substr(value_pos + 1).replace("\\t", "\t");
|
||||
|
||||
options[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (line == "lv" || line == "locals") {
|
||||
List<String> locals;
|
||||
List<Variant> values;
|
||||
script_lang->debug_get_stack_level_locals(current_frame, &locals, &values);
|
||||
print_variables(locals, values, variable_prefix);
|
||||
|
||||
} else if (line == "gv" || line == "globals") {
|
||||
List<String> globals;
|
||||
List<Variant> values;
|
||||
script_lang->debug_get_globals(&globals, &values);
|
||||
print_variables(globals, values, variable_prefix);
|
||||
|
||||
} else if (line == "mv" || line == "members") {
|
||||
List<String> members;
|
||||
List<Variant> values;
|
||||
script_lang->debug_get_stack_level_members(current_frame, &members, &values);
|
||||
print_variables(members, values, variable_prefix);
|
||||
|
||||
} else if (line.begins_with("p") || line.begins_with("print")) {
|
||||
if (line.find_char(' ') < 0) {
|
||||
print_line("Usage: print <expression>");
|
||||
} else {
|
||||
String expr = line.split(" ", true, 1)[1];
|
||||
String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
|
||||
print_line(res);
|
||||
}
|
||||
|
||||
} else if (line == "s" || line == "step") {
|
||||
script_debugger->set_depth(-1);
|
||||
script_debugger->set_lines_left(1);
|
||||
break;
|
||||
} else if (line == "n" || line == "next") {
|
||||
script_debugger->set_depth(0);
|
||||
script_debugger->set_lines_left(1);
|
||||
break;
|
||||
} else if (line == "fin" || line == "finish") {
|
||||
String current_function = script_lang->debug_get_stack_level_function(0);
|
||||
|
||||
for (int i = 0; i < total_frames; i++) {
|
||||
target_function = script_lang->debug_get_stack_level_function(i);
|
||||
if (target_function != current_function) {
|
||||
script_debugger->set_depth(0);
|
||||
script_debugger->set_lines_left(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print_line("Error: Reached last frame.");
|
||||
target_function = "";
|
||||
|
||||
} else if (line.begins_with("br") || line.begins_with("break")) {
|
||||
if (line.get_slice_count(" ") <= 1) {
|
||||
const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
|
||||
if (breakpoints.size() == 0) {
|
||||
print_line("No Breakpoints.");
|
||||
continue;
|
||||
}
|
||||
|
||||
print_line("Breakpoint(s): " + itos(breakpoints.size()));
|
||||
for (const KeyValue<int, HashSet<StringName>> &E : breakpoints) {
|
||||
print_line("\t" + String(*E.value.begin()) + ":" + itos(E.key));
|
||||
}
|
||||
|
||||
} else {
|
||||
Pair<String, int> breakpoint = to_breakpoint(line);
|
||||
|
||||
String source = breakpoint.first;
|
||||
int linenr = breakpoint.second;
|
||||
|
||||
if (source.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
script_debugger->insert_breakpoint(linenr, source);
|
||||
|
||||
print_line("Added breakpoint at " + source + ":" + itos(linenr));
|
||||
}
|
||||
|
||||
} else if (line == "q" || line == "quit" ||
|
||||
(line.is_empty() && feof(stdin))) {
|
||||
// Do not stop again on quit
|
||||
script_debugger->clear_breakpoints();
|
||||
script_debugger->set_depth(-1);
|
||||
script_debugger->set_lines_left(-1);
|
||||
|
||||
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
|
||||
if (main_loop->get_class() == "SceneTree") {
|
||||
main_loop->call("quit");
|
||||
}
|
||||
break;
|
||||
} else if (line.begins_with("delete")) {
|
||||
if (line.get_slice_count(" ") <= 1) {
|
||||
script_debugger->clear_breakpoints();
|
||||
} else {
|
||||
Pair<String, int> breakpoint = to_breakpoint(line);
|
||||
|
||||
String source = breakpoint.first;
|
||||
int linenr = breakpoint.second;
|
||||
|
||||
if (source.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
script_debugger->remove_breakpoint(linenr, source);
|
||||
|
||||
print_line("Removed breakpoint at " + source + ":" + itos(linenr));
|
||||
}
|
||||
|
||||
} else if (line == "h" || line == "help") {
|
||||
print_line("Built-In Debugger command list:\n");
|
||||
print_line("\tc,continue\t\t Continue execution.");
|
||||
print_line("\tbt,backtrace\t\t Show stack trace (frames).");
|
||||
print_line("\tfr,frame <frame>:\t Change current frame.");
|
||||
print_line("\tlv,locals\t\t Show local variables for current frame.");
|
||||
print_line("\tmv,members\t\t Show member variables for \"this\" in frame.");
|
||||
print_line("\tgv,globals\t\t Show global variables.");
|
||||
print_line("\tp,print <expr>\t\t Execute and print variable in expression.");
|
||||
print_line("\ts,step\t\t\t Step to next line.");
|
||||
print_line("\tn,next\t\t\t Next line.");
|
||||
print_line("\tfin,finish\t\t Step out of current frame.");
|
||||
print_line("\tbr,break [source:line]\t List all breakpoints or place a breakpoint.");
|
||||
print_line("\tdelete [source:line]:\t Delete one/all breakpoints.");
|
||||
print_line("\tset [key=value]:\t List all options, or set one.");
|
||||
print_line("\tq,quit\t\t\t Quit application.");
|
||||
} else {
|
||||
print_line("Error: Invalid command, enter \"help\" for assistance.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LocalDebugger::print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix) {
|
||||
String value;
|
||||
Vector<String> value_lines;
|
||||
const List<Variant>::Element *V = values.front();
|
||||
for (const String &E : names) {
|
||||
value = String(V->get());
|
||||
|
||||
if (variable_prefix.is_empty()) {
|
||||
print_line(E + ": " + String(V->get()));
|
||||
} else {
|
||||
print_line(E + ":");
|
||||
value_lines = value.split("\n");
|
||||
for (int i = 0; i < value_lines.size(); ++i) {
|
||||
print_line(variable_prefix + value_lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
V = V->next();
|
||||
}
|
||||
}
|
||||
|
||||
Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
|
||||
String breakpoint_part = p_line.get_slicec(' ', 1);
|
||||
Pair<String, int> breakpoint;
|
||||
|
||||
int last_colon = breakpoint_part.rfind_char(':');
|
||||
if (last_colon < 0) {
|
||||
print_line("Error: Invalid breakpoint format. Expected [source:line]");
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
breakpoint.first = script_debugger->breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges());
|
||||
breakpoint.second = breakpoint_part.substr(last_colon).strip_edges().to_int();
|
||||
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
void LocalDebugger::send_message(const String &p_message, const Array &p_args) {
|
||||
// This needs to be cleaned up entirely.
|
||||
// print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args)));
|
||||
}
|
||||
|
||||
void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'");
|
||||
}
|
||||
|
||||
LocalDebugger::LocalDebugger() {
|
||||
options["variable_prefix"] = "";
|
||||
|
||||
// Bind scripts profiler.
|
||||
scripts_profiler = memnew(ScriptsProfiler);
|
||||
Profiler scr_prof(
|
||||
scripts_profiler,
|
||||
[](void *p_user, bool p_enable, const Array &p_opts) {
|
||||
static_cast<ScriptsProfiler *>(p_user)->toggle(p_enable, p_opts);
|
||||
},
|
||||
nullptr,
|
||||
[](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
|
||||
static_cast<ScriptsProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
|
||||
});
|
||||
register_profiler("scripts", scr_prof);
|
||||
}
|
||||
|
||||
LocalDebugger::~LocalDebugger() {
|
||||
unregister_profiler("scripts");
|
||||
if (scripts_profiler) {
|
||||
memdelete(scripts_profiler);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* local_debugger.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef LOCAL_DEBUGGER_H
|
||||
#define LOCAL_DEBUGGER_H
|
||||
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/templates/list.h"
|
||||
|
||||
class LocalDebugger : public EngineDebugger {
|
||||
private:
|
||||
struct ScriptsProfiler;
|
||||
|
||||
ScriptsProfiler *scripts_profiler = nullptr;
|
||||
|
||||
String target_function;
|
||||
HashMap<String, String> options;
|
||||
|
||||
Pair<String, int> to_breakpoint(const String &p_line);
|
||||
void print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix);
|
||||
|
||||
public:
|
||||
void debug(bool p_can_continue, bool p_is_error_breakpoint);
|
||||
void send_message(const String &p_message, const Array &p_args);
|
||||
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
|
||||
|
||||
LocalDebugger();
|
||||
~LocalDebugger();
|
||||
};
|
||||
|
||||
#endif // LOCAL_DEBUGGER_H
|
|
@ -1,736 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* remote_debugger.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "remote_debugger.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/debugger/engine_profiler.h"
|
||||
#include "core/debugger/script_debugger.h"
|
||||
#include "core/input/input.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/math/expression.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/os/os.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
|
||||
Object *performance = nullptr;
|
||||
int last_perf_time = 0;
|
||||
uint64_t last_monitor_modification_time = 0;
|
||||
|
||||
public:
|
||||
void toggle(bool p_enable, const Array &p_opts) {}
|
||||
void add(const Array &p_data) {}
|
||||
void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
|
||||
if (!performance) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t pt = OS::get_singleton()->get_ticks_msec();
|
||||
if (pt - last_perf_time < 1000) {
|
||||
return;
|
||||
}
|
||||
last_perf_time = pt;
|
||||
|
||||
Array custom_monitor_names = performance->call("get_custom_monitor_names");
|
||||
|
||||
uint64_t monitor_modification_time = performance->call("get_monitor_modification_time");
|
||||
if (monitor_modification_time > last_monitor_modification_time) {
|
||||
last_monitor_modification_time = monitor_modification_time;
|
||||
EngineDebugger::get_singleton()->send_message("performance:profile_names", custom_monitor_names);
|
||||
}
|
||||
|
||||
int max = performance->get("MONITOR_MAX");
|
||||
Array arr;
|
||||
arr.resize(max + custom_monitor_names.size());
|
||||
for (int i = 0; i < max; i++) {
|
||||
arr[i] = performance->call("get_monitor", i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < custom_monitor_names.size(); i++) {
|
||||
Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]);
|
||||
if (!monitor_value.is_num()) {
|
||||
ERR_PRINT(vformat("Value of custom monitor '%s' is not a number.", String(custom_monitor_names[i])));
|
||||
arr[i + max] = Variant();
|
||||
} else {
|
||||
arr[i + max] = monitor_value;
|
||||
}
|
||||
}
|
||||
|
||||
EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr);
|
||||
}
|
||||
|
||||
explicit PerformanceProfiler(Object *p_performance) {
|
||||
performance = p_performance;
|
||||
}
|
||||
};
|
||||
|
||||
Error RemoteDebugger::_put_msg(const String &p_message, const Array &p_data) {
|
||||
Array msg;
|
||||
msg.push_back(p_message);
|
||||
msg.push_back(Thread::get_caller_id());
|
||||
msg.push_back(p_data);
|
||||
Error err = peer->put_message(msg);
|
||||
if (err != OK) {
|
||||
n_messages_dropped++;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
if (p_type == ERR_HANDLER_SCRIPT) {
|
||||
return; //ignore script errors, those go through debugger
|
||||
}
|
||||
|
||||
RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
|
||||
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive errors during flush.
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<ScriptLanguage::StackInfo> si;
|
||||
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
si = ScriptServer::get_language(i)->debug_get_current_stack_info();
|
||||
if (si.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// send_error will lock internally.
|
||||
rd->script_debugger->send_error(String::utf8(p_func), String::utf8(p_file), p_line, String::utf8(p_err), String::utf8(p_descr), p_editor_notify, p_type, si);
|
||||
}
|
||||
|
||||
void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich) {
|
||||
RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
|
||||
|
||||
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush.
|
||||
return;
|
||||
}
|
||||
|
||||
String s = p_string;
|
||||
int allowed_chars = MIN(MAX(rd->max_chars_per_second - rd->char_count, 0), s.length());
|
||||
|
||||
if (allowed_chars == 0 && s.length() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowed_chars < s.length()) {
|
||||
s = s.substr(0, allowed_chars);
|
||||
}
|
||||
|
||||
MutexLock lock(rd->mutex);
|
||||
|
||||
rd->char_count += allowed_chars;
|
||||
bool overflowed = rd->char_count >= rd->max_chars_per_second;
|
||||
if (rd->is_peer_connected()) {
|
||||
if (overflowed) {
|
||||
s += "[...]";
|
||||
}
|
||||
|
||||
OutputString output_string;
|
||||
output_string.message = s;
|
||||
if (p_error) {
|
||||
output_string.type = MESSAGE_TYPE_ERROR;
|
||||
} else if (p_rich) {
|
||||
output_string.type = MESSAGE_TYPE_LOG_RICH;
|
||||
} else {
|
||||
output_string.type = MESSAGE_TYPE_LOG;
|
||||
}
|
||||
rd->output_strings.push_back(output_string);
|
||||
|
||||
if (overflowed) {
|
||||
output_string.message = "[output overflow, print less text!]";
|
||||
output_string.type = MESSAGE_TYPE_ERROR;
|
||||
rd->output_strings.push_back(output_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoteDebugger::ErrorMessage RemoteDebugger::_create_overflow_error(const String &p_what, const String &p_descr) {
|
||||
ErrorMessage oe;
|
||||
oe.error = p_what;
|
||||
oe.error_descr = p_descr;
|
||||
oe.warning = false;
|
||||
uint64_t time = OS::get_singleton()->get_ticks_msec();
|
||||
oe.hr = time / 3600000;
|
||||
oe.min = (time / 60000) % 60;
|
||||
oe.sec = (time / 1000) % 60;
|
||||
oe.msec = time % 1000;
|
||||
return oe;
|
||||
}
|
||||
|
||||
void RemoteDebugger::flush_output() {
|
||||
MutexLock lock(mutex);
|
||||
flush_thread = Thread::get_caller_id();
|
||||
flushing = true;
|
||||
if (!is_peer_connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n_messages_dropped > 0) {
|
||||
ErrorMessage err_msg = _create_overflow_error("TOO_MANY_MESSAGES", "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped. Profiling might misbheave, try raising 'network/limits/debugger/max_queued_messages' in project setting.");
|
||||
if (_put_msg("error", err_msg.serialize()) == OK) {
|
||||
n_messages_dropped = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (output_strings.size()) {
|
||||
// Join output strings so we generate less messages.
|
||||
Vector<String> joined_log_strings;
|
||||
Vector<String> strings;
|
||||
Vector<int> types;
|
||||
for (const OutputString &output_string : output_strings) {
|
||||
if (output_string.type == MESSAGE_TYPE_ERROR) {
|
||||
if (!joined_log_strings.is_empty()) {
|
||||
strings.push_back(String("\n").join(joined_log_strings));
|
||||
types.push_back(MESSAGE_TYPE_LOG);
|
||||
joined_log_strings.clear();
|
||||
}
|
||||
strings.push_back(output_string.message);
|
||||
types.push_back(MESSAGE_TYPE_ERROR);
|
||||
} else if (output_string.type == MESSAGE_TYPE_LOG_RICH) {
|
||||
if (!joined_log_strings.is_empty()) {
|
||||
strings.push_back(String("\n").join(joined_log_strings));
|
||||
types.push_back(MESSAGE_TYPE_LOG_RICH);
|
||||
joined_log_strings.clear();
|
||||
}
|
||||
strings.push_back(output_string.message);
|
||||
types.push_back(MESSAGE_TYPE_LOG_RICH);
|
||||
} else {
|
||||
joined_log_strings.push_back(output_string.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!joined_log_strings.is_empty()) {
|
||||
strings.push_back(String("\n").join(joined_log_strings));
|
||||
types.push_back(MESSAGE_TYPE_LOG);
|
||||
}
|
||||
|
||||
Array arr;
|
||||
arr.push_back(strings);
|
||||
arr.push_back(types);
|
||||
_put_msg("output", arr);
|
||||
output_strings.clear();
|
||||
}
|
||||
|
||||
while (errors.size()) {
|
||||
ErrorMessage oe = errors.front()->get();
|
||||
_put_msg("error", oe.serialize());
|
||||
errors.pop_front();
|
||||
}
|
||||
|
||||
// Update limits
|
||||
uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000;
|
||||
|
||||
if (ticks - last_reset > 1000) {
|
||||
last_reset = ticks;
|
||||
char_count = 0;
|
||||
err_count = 0;
|
||||
n_errors_dropped = 0;
|
||||
warn_count = 0;
|
||||
n_warnings_dropped = 0;
|
||||
}
|
||||
flushing = false;
|
||||
}
|
||||
|
||||
void RemoteDebugger::send_message(const String &p_message, const Array &p_args) {
|
||||
MutexLock lock(mutex);
|
||||
if (is_peer_connected()) {
|
||||
_put_msg(p_message, p_args);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
ErrorMessage oe;
|
||||
oe.error = p_err;
|
||||
oe.error_descr = p_descr;
|
||||
oe.source_file = p_file;
|
||||
oe.source_line = p_line;
|
||||
oe.source_func = p_func;
|
||||
oe.warning = p_type == ERR_HANDLER_WARNING;
|
||||
uint64_t time = OS::get_singleton()->get_ticks_msec();
|
||||
oe.hr = time / 3600000;
|
||||
oe.min = (time / 60000) % 60;
|
||||
oe.sec = (time / 1000) % 60;
|
||||
oe.msec = time % 1000;
|
||||
oe.callstack.append_array(script_debugger->get_error_stack_info());
|
||||
|
||||
if (flushing && Thread::get_caller_id() == flush_thread) { // Can't handle recursive errors during flush.
|
||||
return;
|
||||
}
|
||||
|
||||
MutexLock lock(mutex);
|
||||
|
||||
if (oe.warning) {
|
||||
warn_count++;
|
||||
} else {
|
||||
err_count++;
|
||||
}
|
||||
|
||||
if (is_peer_connected()) {
|
||||
if (oe.warning) {
|
||||
if (warn_count > max_warnings_per_second) {
|
||||
n_warnings_dropped++;
|
||||
if (n_warnings_dropped == 1) {
|
||||
// Only print one message about dropping per second
|
||||
ErrorMessage overflow = _create_overflow_error("TOO_MANY_WARNINGS", "Too many warnings! Ignoring warnings for up to 1 second.");
|
||||
errors.push_back(overflow);
|
||||
}
|
||||
} else {
|
||||
errors.push_back(oe);
|
||||
}
|
||||
} else {
|
||||
if (err_count > max_errors_per_second) {
|
||||
n_errors_dropped++;
|
||||
if (n_errors_dropped == 1) {
|
||||
// Only print one message about dropping per second
|
||||
ErrorMessage overflow = _create_overflow_error("TOO_MANY_ERRORS", "Too many errors! Ignoring errors for up to 1 second.");
|
||||
errors.push_back(overflow);
|
||||
}
|
||||
} else {
|
||||
errors.push_back(oe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type) {
|
||||
DebuggerMarshalls::ScriptStackVariable stvar;
|
||||
List<String>::Element *E = p_names.front();
|
||||
List<Variant>::Element *F = p_vals.front();
|
||||
while (E) {
|
||||
stvar.name = E->get();
|
||||
stvar.value = F->get();
|
||||
stvar.type = p_type;
|
||||
send_message("stack_frame_var", stvar.serialize());
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
}
|
||||
}
|
||||
|
||||
Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
|
||||
const int idx = p_msg.find_char(':');
|
||||
r_captured = false;
|
||||
if (idx < 0) { // No prefix, unknown message.
|
||||
return OK;
|
||||
}
|
||||
const String cap = p_msg.substr(0, idx);
|
||||
if (!has_capture(cap)) {
|
||||
return ERR_UNAVAILABLE; // Unknown message...
|
||||
}
|
||||
const String msg = p_msg.substr(idx + 1);
|
||||
return capture_parse(cap, msg, p_data, r_captured);
|
||||
}
|
||||
|
||||
void RemoteDebugger::_poll_messages() {
|
||||
MutexLock mutex_lock(mutex);
|
||||
|
||||
peer->poll();
|
||||
while (peer->has_message()) {
|
||||
Array cmd = peer->get_message();
|
||||
ERR_CONTINUE(cmd.size() != 3);
|
||||
ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
|
||||
ERR_CONTINUE(cmd[1].get_type() != Variant::INT);
|
||||
ERR_CONTINUE(cmd[2].get_type() != Variant::ARRAY);
|
||||
|
||||
Thread::ID thread = cmd[1];
|
||||
|
||||
if (!messages.has(thread)) {
|
||||
continue; // This thread is not around to receive the messages
|
||||
}
|
||||
|
||||
Message msg;
|
||||
msg.message = cmd[0];
|
||||
msg.data = cmd[2];
|
||||
messages[thread].push_back(msg);
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteDebugger::_has_messages() {
|
||||
MutexLock mutex_lock(mutex);
|
||||
return messages.has(Thread::get_caller_id()) && !messages[Thread::get_caller_id()].is_empty();
|
||||
}
|
||||
|
||||
Array RemoteDebugger::_get_message() {
|
||||
MutexLock mutex_lock(mutex);
|
||||
ERR_FAIL_COND_V(!messages.has(Thread::get_caller_id()), Array());
|
||||
List<Message> &message_list = messages[Thread::get_caller_id()];
|
||||
ERR_FAIL_COND_V(message_list.is_empty(), Array());
|
||||
|
||||
Array msg;
|
||||
msg.resize(2);
|
||||
msg[0] = message_list.front()->get().message;
|
||||
msg[1] = message_list.front()->get().data;
|
||||
message_list.pop_front();
|
||||
return msg;
|
||||
}
|
||||
|
||||
void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
|
||||
//this function is called when there is a debugger break (bug on script)
|
||||
//or when execution is paused from editor
|
||||
|
||||
{
|
||||
MutexLock lock(mutex);
|
||||
// Tests that require mutex.
|
||||
if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
|
||||
|
||||
if (!peer->can_block()) {
|
||||
return; // Peer does not support blocking IO. We could at least send the error though.
|
||||
}
|
||||
}
|
||||
|
||||
ScriptLanguage *script_lang = script_debugger->get_break_language();
|
||||
const String error_str = script_lang ? script_lang->debug_get_error() : "";
|
||||
Array msg;
|
||||
msg.push_back(p_can_continue);
|
||||
msg.push_back(error_str);
|
||||
ERR_FAIL_NULL(script_lang);
|
||||
msg.push_back(script_lang->debug_get_stack_level_count() > 0);
|
||||
msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id()));
|
||||
if (allow_focus_steal_fn) {
|
||||
allow_focus_steal_fn();
|
||||
}
|
||||
send_message("debug_enter", msg);
|
||||
|
||||
Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
|
||||
|
||||
if (Thread::get_caller_id() == Thread::get_main_id()) {
|
||||
mouse_mode = Input::get_singleton()->get_mouse_mode();
|
||||
if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
|
||||
}
|
||||
} else {
|
||||
MutexLock mutex_lock(mutex);
|
||||
messages.insert(Thread::get_caller_id(), List<Message>());
|
||||
}
|
||||
|
||||
while (is_peer_connected()) {
|
||||
flush_output();
|
||||
|
||||
_poll_messages();
|
||||
|
||||
if (_has_messages()) {
|
||||
Array cmd = _get_message();
|
||||
|
||||
ERR_CONTINUE(cmd.size() != 2);
|
||||
ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
|
||||
ERR_CONTINUE(cmd[1].get_type() != Variant::ARRAY);
|
||||
|
||||
String command = cmd[0];
|
||||
Array data = cmd[1];
|
||||
|
||||
if (command == "step") {
|
||||
script_debugger->set_depth(-1);
|
||||
script_debugger->set_lines_left(1);
|
||||
break;
|
||||
|
||||
} else if (command == "next") {
|
||||
script_debugger->set_depth(0);
|
||||
script_debugger->set_lines_left(1);
|
||||
break;
|
||||
|
||||
} else if (command == "continue") {
|
||||
script_debugger->set_depth(-1);
|
||||
script_debugger->set_lines_left(-1);
|
||||
break;
|
||||
|
||||
} else if (command == "break") {
|
||||
ERR_PRINT("Got break when already broke!");
|
||||
break;
|
||||
|
||||
} else if (command == "get_stack_dump") {
|
||||
DebuggerMarshalls::ScriptStackDump dump;
|
||||
int slc = script_lang->debug_get_stack_level_count();
|
||||
for (int i = 0; i < slc; i++) {
|
||||
ScriptLanguage::StackInfo frame;
|
||||
frame.file = script_lang->debug_get_stack_level_source(i);
|
||||
frame.line = script_lang->debug_get_stack_level_line(i);
|
||||
frame.func = script_lang->debug_get_stack_level_function(i);
|
||||
dump.frames.push_back(frame);
|
||||
}
|
||||
send_message("stack_dump", dump.serialize());
|
||||
|
||||
} else if (command == "get_stack_frame_vars") {
|
||||
ERR_FAIL_COND(data.size() != 1);
|
||||
ERR_FAIL_NULL(script_lang);
|
||||
int lv = data[0];
|
||||
|
||||
List<String> members;
|
||||
List<Variant> member_vals;
|
||||
if (ScriptInstance *inst = script_lang->debug_get_stack_level_instance(lv)) {
|
||||
members.push_back("self");
|
||||
member_vals.push_back(inst->get_owner());
|
||||
}
|
||||
script_lang->debug_get_stack_level_members(lv, &members, &member_vals);
|
||||
ERR_FAIL_COND(members.size() != member_vals.size());
|
||||
|
||||
List<String> locals;
|
||||
List<Variant> local_vals;
|
||||
script_lang->debug_get_stack_level_locals(lv, &locals, &local_vals);
|
||||
ERR_FAIL_COND(locals.size() != local_vals.size());
|
||||
|
||||
List<String> globals;
|
||||
List<Variant> globals_vals;
|
||||
script_lang->debug_get_globals(&globals, &globals_vals);
|
||||
ERR_FAIL_COND(globals.size() != globals_vals.size());
|
||||
|
||||
Array var_size;
|
||||
var_size.push_back(local_vals.size() + member_vals.size() + globals_vals.size());
|
||||
send_message("stack_frame_vars", var_size);
|
||||
_send_stack_vars(locals, local_vals, 0);
|
||||
_send_stack_vars(members, member_vals, 1);
|
||||
_send_stack_vars(globals, globals_vals, 2);
|
||||
|
||||
} else if (command == "reload_scripts") {
|
||||
script_paths_to_reload = data;
|
||||
} else if (command == "reload_all_scripts") {
|
||||
reload_all_scripts = true;
|
||||
} else if (command == "breakpoint") {
|
||||
ERR_FAIL_COND(data.size() < 3);
|
||||
bool set = data[2];
|
||||
if (set) {
|
||||
script_debugger->insert_breakpoint(data[1], data[0]);
|
||||
} else {
|
||||
script_debugger->remove_breakpoint(data[1], data[0]);
|
||||
}
|
||||
|
||||
} else if (command == "set_skip_breakpoints") {
|
||||
ERR_FAIL_COND(data.is_empty());
|
||||
script_debugger->set_skip_breakpoints(data[0]);
|
||||
} else if (command == "evaluate") {
|
||||
String expression_str = data[0];
|
||||
int frame = data[1];
|
||||
|
||||
ScriptInstance *breaked_instance = script_debugger->get_break_language()->debug_get_stack_level_instance(frame);
|
||||
if (!breaked_instance) {
|
||||
break;
|
||||
}
|
||||
|
||||
List<String> locals;
|
||||
List<Variant> local_vals;
|
||||
|
||||
script_debugger->get_break_language()->debug_get_stack_level_locals(frame, &locals, &local_vals);
|
||||
ERR_FAIL_COND(locals.size() != local_vals.size());
|
||||
|
||||
PackedStringArray locals_vector;
|
||||
for (const String &S : locals) {
|
||||
locals_vector.append(S);
|
||||
}
|
||||
|
||||
Array local_vals_array;
|
||||
for (const Variant &V : local_vals) {
|
||||
local_vals_array.append(V);
|
||||
}
|
||||
|
||||
Expression expression;
|
||||
expression.parse(expression_str, locals_vector);
|
||||
const Variant return_val = expression.execute(local_vals_array, breaked_instance->get_owner());
|
||||
|
||||
DebuggerMarshalls::ScriptStackVariable stvar;
|
||||
stvar.name = expression_str;
|
||||
stvar.value = return_val;
|
||||
stvar.type = 3;
|
||||
|
||||
send_message("evaluation_return", stvar.serialize());
|
||||
} else {
|
||||
bool captured = false;
|
||||
ERR_CONTINUE(_try_capture(command, data, captured) != OK);
|
||||
if (!captured) {
|
||||
WARN_PRINT(vformat("Unknown message received from debugger: %s.", command));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OS::get_singleton()->delay_usec(10000);
|
||||
if (Thread::get_caller_id() == Thread::get_main_id()) {
|
||||
// If this is a busy loop on the main thread, events still need to be processed.
|
||||
DisplayServer::get_singleton()->force_process_and_drop_events();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_message("debug_exit", Array());
|
||||
|
||||
if (Thread::get_caller_id() == Thread::get_main_id()) {
|
||||
if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
|
||||
Input::get_singleton()->set_mouse_mode(mouse_mode);
|
||||
}
|
||||
} else {
|
||||
MutexLock mutex_lock(mutex);
|
||||
messages.erase(Thread::get_caller_id());
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebugger::poll_events(bool p_is_idle) {
|
||||
if (peer.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
flush_output();
|
||||
|
||||
_poll_messages();
|
||||
|
||||
while (_has_messages()) {
|
||||
Array arr = _get_message();
|
||||
|
||||
ERR_CONTINUE(arr.size() != 2);
|
||||
ERR_CONTINUE(arr[0].get_type() != Variant::STRING);
|
||||
ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
|
||||
|
||||
const String cmd = arr[0];
|
||||
const int idx = cmd.find_char(':');
|
||||
bool parsed = false;
|
||||
if (idx < 0) { // Not prefix, use scripts capture.
|
||||
capture_parse("core", cmd, arr[1], parsed);
|
||||
continue;
|
||||
}
|
||||
|
||||
const String cap = cmd.substr(0, idx);
|
||||
if (!has_capture(cap)) {
|
||||
continue; // Unknown message...
|
||||
}
|
||||
|
||||
const String msg = cmd.substr(idx + 1);
|
||||
capture_parse(cap, msg, arr[1], parsed);
|
||||
}
|
||||
|
||||
// Reload scripts during idle poll only.
|
||||
if (p_is_idle) {
|
||||
if (reload_all_scripts) {
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptServer::get_language(i)->reload_all_scripts();
|
||||
}
|
||||
reload_all_scripts = false;
|
||||
} else if (!script_paths_to_reload.is_empty()) {
|
||||
Array scripts_to_reload;
|
||||
for (int i = 0; i < script_paths_to_reload.size(); ++i) {
|
||||
String path = script_paths_to_reload[i];
|
||||
Error err = OK;
|
||||
Ref<Script> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
|
||||
ERR_CONTINUE_MSG(err != OK, vformat("Could not reload script '%s': %s", path, error_names[err]));
|
||||
ERR_CONTINUE_MSG(script.is_null(), vformat("Could not reload script '%s': Not a script!", path, error_names[err]));
|
||||
scripts_to_reload.push_back(script);
|
||||
}
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptServer::get_language(i)->reload_scripts(scripts_to_reload, true);
|
||||
}
|
||||
}
|
||||
script_paths_to_reload.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
|
||||
r_captured = true;
|
||||
if (p_cmd == "reload_scripts") {
|
||||
script_paths_to_reload = p_data;
|
||||
} else if (p_cmd == "reload_all_scripts") {
|
||||
reload_all_scripts = true;
|
||||
} else if (p_cmd == "breakpoint") {
|
||||
ERR_FAIL_COND_V(p_data.size() < 3, ERR_INVALID_DATA);
|
||||
bool set = p_data[2];
|
||||
if (set) {
|
||||
script_debugger->insert_breakpoint(p_data[1], p_data[0]);
|
||||
} else {
|
||||
script_debugger->remove_breakpoint(p_data[1], p_data[0]);
|
||||
}
|
||||
|
||||
} else if (p_cmd == "set_skip_breakpoints") {
|
||||
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
|
||||
script_debugger->set_skip_breakpoints(p_data[0]);
|
||||
} else if (p_cmd == "break") {
|
||||
script_debugger->debug(script_debugger->get_break_language());
|
||||
} else {
|
||||
r_captured = false;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured) {
|
||||
r_captured = false;
|
||||
ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA);
|
||||
ERR_FAIL_COND_V(p_data[0].get_type() != Variant::BOOL, ERR_INVALID_DATA);
|
||||
ERR_FAIL_COND_V(!has_profiler(p_cmd), ERR_UNAVAILABLE);
|
||||
Array opts;
|
||||
if (p_data.size() > 1) { // Optional profiler parameters.
|
||||
ERR_FAIL_COND_V(p_data[1].get_type() != Variant::ARRAY, ERR_INVALID_DATA);
|
||||
opts = p_data[1];
|
||||
}
|
||||
r_captured = true;
|
||||
profiler_enable(p_cmd, p_data[0], opts);
|
||||
return OK;
|
||||
}
|
||||
|
||||
RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
|
||||
peer = p_peer;
|
||||
max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second");
|
||||
max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second");
|
||||
max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second");
|
||||
|
||||
// Performance Profiler
|
||||
Object *perf = Engine::get_singleton()->get_singleton_object("Performance");
|
||||
if (perf) {
|
||||
performance_profiler.instantiate(perf);
|
||||
performance_profiler->bind("performance");
|
||||
profiler_enable("performance", true);
|
||||
}
|
||||
|
||||
// Core and profiler captures.
|
||||
Capture core_cap(this,
|
||||
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
|
||||
return static_cast<RemoteDebugger *>(p_user)->_core_capture(p_cmd, p_data, r_captured);
|
||||
});
|
||||
register_message_capture("core", core_cap);
|
||||
Capture profiler_cap(this,
|
||||
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
|
||||
return static_cast<RemoteDebugger *>(p_user)->_profiler_capture(p_cmd, p_data, r_captured);
|
||||
});
|
||||
register_message_capture("profiler", profiler_cap);
|
||||
|
||||
// Error handlers
|
||||
phl.printfunc = _print_handler;
|
||||
phl.userdata = this;
|
||||
add_print_handler(&phl);
|
||||
|
||||
eh.errfunc = _err_handler;
|
||||
eh.userdata = this;
|
||||
add_error_handler(&eh);
|
||||
|
||||
messages.insert(Thread::get_main_id(), List<Message>());
|
||||
}
|
||||
|
||||
RemoteDebugger::~RemoteDebugger() {
|
||||
remove_print_handler(&phl);
|
||||
remove_error_handler(&eh);
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* remote_debugger.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef REMOTE_DEBUGGER_H
|
||||
#define REMOTE_DEBUGGER_H
|
||||
|
||||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/debugger/remote_debugger_peer.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/variant/array.h"
|
||||
|
||||
class RemoteDebugger : public EngineDebugger {
|
||||
public:
|
||||
enum MessageType {
|
||||
MESSAGE_TYPE_LOG,
|
||||
MESSAGE_TYPE_ERROR,
|
||||
MESSAGE_TYPE_LOG_RICH,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef DebuggerMarshalls::OutputError ErrorMessage;
|
||||
|
||||
class PerformanceProfiler;
|
||||
|
||||
Ref<PerformanceProfiler> performance_profiler;
|
||||
|
||||
Ref<RemoteDebuggerPeer> peer;
|
||||
|
||||
struct OutputString {
|
||||
String message;
|
||||
MessageType type;
|
||||
};
|
||||
List<OutputString> output_strings;
|
||||
List<ErrorMessage> errors;
|
||||
|
||||
int n_messages_dropped = 0;
|
||||
int max_errors_per_second = 0;
|
||||
int max_chars_per_second = 0;
|
||||
int max_warnings_per_second = 0;
|
||||
int n_errors_dropped = 0;
|
||||
int n_warnings_dropped = 0;
|
||||
int char_count = 0;
|
||||
int err_count = 0;
|
||||
int warn_count = 0;
|
||||
int last_reset = 0;
|
||||
bool reload_all_scripts = false;
|
||||
Array script_paths_to_reload;
|
||||
|
||||
// Make handlers and send_message thread safe.
|
||||
Mutex mutex;
|
||||
bool flushing = false;
|
||||
Thread::ID flush_thread = 0;
|
||||
|
||||
struct Message {
|
||||
String message;
|
||||
Array data;
|
||||
};
|
||||
|
||||
HashMap<Thread::ID, List<Message>> messages;
|
||||
|
||||
void _poll_messages();
|
||||
bool _has_messages();
|
||||
Array _get_message();
|
||||
|
||||
PrintHandlerList phl;
|
||||
static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich);
|
||||
ErrorHandlerList eh;
|
||||
static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type);
|
||||
|
||||
ErrorMessage _create_overflow_error(const String &p_what, const String &p_descr);
|
||||
Error _put_msg(const String &p_message, const Array &p_data);
|
||||
|
||||
bool is_peer_connected() { return peer->is_peer_connected(); }
|
||||
void flush_output();
|
||||
|
||||
void _send_stack_vars(List<String> &p_names, List<Variant> &p_vals, int p_type);
|
||||
|
||||
Error _profiler_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
|
||||
Error _core_capture(const String &p_cmd, const Array &p_data, bool &r_captured);
|
||||
|
||||
template <typename T>
|
||||
void _bind_profiler(const String &p_name, T *p_prof);
|
||||
Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured);
|
||||
|
||||
public:
|
||||
// Overrides
|
||||
void poll_events(bool p_is_idle);
|
||||
void send_message(const String &p_message, const Array &p_args);
|
||||
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
|
||||
void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
|
||||
|
||||
explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
|
||||
~RemoteDebugger();
|
||||
};
|
||||
|
||||
#endif // REMOTE_DEBUGGER_H
|
|
@ -1,243 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* remote_debugger_peer.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "remote_debugger_peer.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
bool RemoteDebuggerPeerTCP::is_peer_connected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
bool RemoteDebuggerPeerTCP::has_message() {
|
||||
return in_queue.size() > 0;
|
||||
}
|
||||
|
||||
Array RemoteDebuggerPeerTCP::get_message() {
|
||||
MutexLock lock(mutex);
|
||||
ERR_FAIL_COND_V(!has_message(), Array());
|
||||
Array out = in_queue.front()->get();
|
||||
in_queue.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
Error RemoteDebuggerPeerTCP::put_message(const Array &p_arr) {
|
||||
MutexLock lock(mutex);
|
||||
if (out_queue.size() >= max_queued_messages) {
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
out_queue.push_back(p_arr);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int RemoteDebuggerPeerTCP::get_max_message_size() const {
|
||||
return 8 << 20; // 8 MiB
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::close() {
|
||||
running = false;
|
||||
if (thread.is_started()) {
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
tcp_client->disconnect_from_host();
|
||||
out_buf.clear();
|
||||
in_buf.clear();
|
||||
}
|
||||
|
||||
RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
|
||||
// This means remote debugger takes 16 MiB just because it exists...
|
||||
in_buf.resize((8 << 20) + 4); // 8 MiB should be way more than enough (need 4 extra bytes for encoding packet size).
|
||||
out_buf.resize(8 << 20); // 8 MiB should be way more than enough
|
||||
tcp_client = p_tcp;
|
||||
if (tcp_client.is_valid()) { // Attaching to an already connected stream.
|
||||
connected = true;
|
||||
running = true;
|
||||
thread.start(_thread_func, this);
|
||||
} else {
|
||||
tcp_client.instantiate();
|
||||
}
|
||||
}
|
||||
|
||||
RemoteDebuggerPeerTCP::~RemoteDebuggerPeerTCP() {
|
||||
close();
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::_write_out() {
|
||||
while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) {
|
||||
uint8_t *buf = out_buf.ptrw();
|
||||
if (out_left <= 0) {
|
||||
if (out_queue.size() == 0) {
|
||||
break; // Nothing left to send
|
||||
}
|
||||
mutex.lock();
|
||||
Variant var = out_queue.front()->get();
|
||||
out_queue.pop_front();
|
||||
mutex.unlock();
|
||||
int size = 0;
|
||||
Error err = encode_variant(var, nullptr, size);
|
||||
ERR_CONTINUE(err != OK || size > out_buf.size() - 4); // 4 bytes separator.
|
||||
encode_uint32(size, buf);
|
||||
encode_variant(var, buf + 4, size);
|
||||
out_left = size + 4;
|
||||
out_pos = 0;
|
||||
}
|
||||
int sent = 0;
|
||||
tcp_client->put_partial_data(buf + out_pos, out_left, sent);
|
||||
out_left -= sent;
|
||||
out_pos += sent;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::_read_in() {
|
||||
while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_IN) == OK) {
|
||||
uint8_t *buf = in_buf.ptrw();
|
||||
if (in_left <= 0) {
|
||||
if (in_queue.size() > max_queued_messages) {
|
||||
break; // Too many messages already in queue.
|
||||
}
|
||||
if (tcp_client->get_available_bytes() < 4) {
|
||||
break; // Need 4 more bytes.
|
||||
}
|
||||
uint32_t size = 0;
|
||||
int read = 0;
|
||||
Error err = tcp_client->get_partial_data((uint8_t *)&size, 4, read);
|
||||
ERR_CONTINUE(read != 4 || err != OK || size > (uint32_t)in_buf.size());
|
||||
in_left = size;
|
||||
in_pos = 0;
|
||||
}
|
||||
int read = 0;
|
||||
tcp_client->get_partial_data(buf + in_pos, in_left, read);
|
||||
in_left -= read;
|
||||
in_pos += read;
|
||||
if (in_left == 0) {
|
||||
Variant var;
|
||||
Error err = decode_variant(var, buf, in_pos, &read);
|
||||
ERR_CONTINUE(read != in_pos || err != OK);
|
||||
ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
|
||||
MutexLock lock(mutex);
|
||||
in_queue.push_back(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
|
||||
IPAddress ip;
|
||||
if (p_host.is_valid_ip_address()) {
|
||||
ip = p_host;
|
||||
} else {
|
||||
ip = IP::get_singleton()->resolve_hostname(p_host);
|
||||
}
|
||||
|
||||
int port = p_port;
|
||||
|
||||
const int tries = 6;
|
||||
const int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
|
||||
|
||||
tcp_client->connect_to_host(ip, port);
|
||||
|
||||
for (int i = 0; i < tries; i++) {
|
||||
tcp_client->poll();
|
||||
if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
|
||||
print_verbose("Remote Debugger: Connected!");
|
||||
break;
|
||||
} else {
|
||||
const int ms = waits[i];
|
||||
OS::get_singleton()->delay_usec(ms * 1000);
|
||||
print_verbose("Remote Debugger: Connection failed with status: '" + String::num_int64(tcp_client->get_status()) + "', retrying in " + String::num_int64(ms) + " msec.");
|
||||
}
|
||||
}
|
||||
|
||||
if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
|
||||
ERR_PRINT(vformat("Remote Debugger: Unable to connect. Status: %s.", String::num_int64(tcp_client->get_status())));
|
||||
return FAILED;
|
||||
}
|
||||
connected = true;
|
||||
running = true;
|
||||
thread.start(_thread_func, this);
|
||||
return OK;
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
|
||||
// Update in time for 144hz monitors
|
||||
const uint64_t min_tick = 6900;
|
||||
RemoteDebuggerPeerTCP *peer = static_cast<RemoteDebuggerPeerTCP *>(p_ud);
|
||||
while (peer->running && peer->is_peer_connected()) {
|
||||
uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
|
||||
peer->_poll();
|
||||
if (!peer->is_peer_connected()) {
|
||||
break;
|
||||
}
|
||||
ticks_usec = OS::get_singleton()->get_ticks_usec() - ticks_usec;
|
||||
if (ticks_usec < min_tick) {
|
||||
OS::get_singleton()->delay_usec(min_tick - ticks_usec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::poll() {
|
||||
// Nothing to do, polling is done in thread.
|
||||
}
|
||||
|
||||
void RemoteDebuggerPeerTCP::_poll() {
|
||||
tcp_client->poll();
|
||||
if (connected) {
|
||||
_write_out();
|
||||
_read_in();
|
||||
connected = tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
|
||||
ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
|
||||
|
||||
String debug_host = p_uri.replace("tcp://", "");
|
||||
uint16_t debug_port = 6007;
|
||||
|
||||
if (debug_host.contains_char(':')) {
|
||||
int sep_pos = debug_host.rfind_char(':');
|
||||
debug_port = debug_host.substr(sep_pos + 1).to_int();
|
||||
debug_host = debug_host.substr(0, sep_pos);
|
||||
}
|
||||
|
||||
RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP);
|
||||
Error err = peer->connect_to_host(debug_host, debug_port);
|
||||
if (err != OK) {
|
||||
memdelete(peer);
|
||||
return nullptr;
|
||||
}
|
||||
return peer;
|
||||
}
|
||||
|
||||
RemoteDebuggerPeer::RemoteDebuggerPeer() {
|
||||
max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* remote_debugger_peer.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef REMOTE_DEBUGGER_PEER_H
|
||||
#define REMOTE_DEBUGGER_PEER_H
|
||||
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
class RemoteDebuggerPeer : public RefCounted {
|
||||
protected:
|
||||
int max_queued_messages = 4096;
|
||||
|
||||
public:
|
||||
virtual bool is_peer_connected() = 0;
|
||||
virtual int get_max_message_size() const = 0;
|
||||
virtual bool has_message() = 0;
|
||||
virtual Error put_message(const Array &p_arr) = 0;
|
||||
virtual Array get_message() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void poll() = 0;
|
||||
virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug).
|
||||
|
||||
RemoteDebuggerPeer();
|
||||
};
|
||||
|
||||
class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
|
||||
private:
|
||||
Ref<StreamPeerTCP> tcp_client;
|
||||
Mutex mutex;
|
||||
Thread thread;
|
||||
List<Array> in_queue;
|
||||
List<Array> out_queue;
|
||||
int out_left = 0;
|
||||
int out_pos = 0;
|
||||
Vector<uint8_t> out_buf;
|
||||
int in_left = 0;
|
||||
int in_pos = 0;
|
||||
Vector<uint8_t> in_buf;
|
||||
bool connected = false;
|
||||
bool running = false;
|
||||
|
||||
static void _thread_func(void *p_ud);
|
||||
|
||||
void _poll();
|
||||
void _write_out();
|
||||
void _read_in();
|
||||
|
||||
public:
|
||||
static RemoteDebuggerPeer *create(const String &p_uri);
|
||||
|
||||
Error connect_to_host(const String &p_host, uint16_t p_port);
|
||||
|
||||
bool is_peer_connected() override;
|
||||
int get_max_message_size() const override;
|
||||
bool has_message() override;
|
||||
Error put_message(const Array &p_arr) override;
|
||||
Array get_message() override;
|
||||
void poll() override;
|
||||
void close() override;
|
||||
|
||||
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
|
||||
~RemoteDebuggerPeerTCP();
|
||||
};
|
||||
|
||||
#endif // REMOTE_DEBUGGER_PEER_H
|
|
@ -1,102 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* script_debugger.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "script_debugger.h"
|
||||
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
|
||||
thread_local int ScriptDebugger::lines_left = -1;
|
||||
thread_local int ScriptDebugger::depth = -1;
|
||||
thread_local ScriptLanguage *ScriptDebugger::break_lang = nullptr;
|
||||
thread_local Vector<ScriptDebugger::StackInfo> ScriptDebugger::error_stack_info;
|
||||
|
||||
void ScriptDebugger::set_lines_left(int p_left) {
|
||||
lines_left = p_left;
|
||||
}
|
||||
|
||||
void ScriptDebugger::set_depth(int p_depth) {
|
||||
depth = p_depth;
|
||||
}
|
||||
|
||||
void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
|
||||
if (!breakpoints.has(p_line)) {
|
||||
breakpoints[p_line] = HashSet<StringName>();
|
||||
}
|
||||
breakpoints[p_line].insert(p_source);
|
||||
}
|
||||
|
||||
void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
|
||||
if (!breakpoints.has(p_line)) {
|
||||
return;
|
||||
}
|
||||
|
||||
breakpoints[p_line].erase(p_source);
|
||||
if (breakpoints[p_line].size() == 0) {
|
||||
breakpoints.erase(p_line);
|
||||
}
|
||||
}
|
||||
|
||||
String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
|
||||
return p_source;
|
||||
}
|
||||
|
||||
void ScriptDebugger::clear_breakpoints() {
|
||||
breakpoints.clear();
|
||||
}
|
||||
|
||||
void ScriptDebugger::set_skip_breakpoints(bool p_skip_breakpoints) {
|
||||
skip_breakpoints = p_skip_breakpoints;
|
||||
}
|
||||
|
||||
bool ScriptDebugger::is_skipping_breakpoints() {
|
||||
return skip_breakpoints;
|
||||
}
|
||||
|
||||
void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
|
||||
ScriptLanguage *prev = break_lang;
|
||||
break_lang = p_lang;
|
||||
EngineDebugger::get_singleton()->debug(p_can_continue, p_is_error_breakpoint);
|
||||
break_lang = prev;
|
||||
}
|
||||
|
||||
void ScriptDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info) {
|
||||
// Store stack info, this is ugly, but allows us to separate EngineDebugger and ScriptDebugger. There might be a better way.
|
||||
error_stack_info.append_array(p_stack_info);
|
||||
EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type);
|
||||
error_stack_info.clear(); // Clear because this is thread local
|
||||
}
|
||||
|
||||
Vector<ScriptLanguage::StackInfo> ScriptDebugger::get_error_stack_info() const {
|
||||
return error_stack_info;
|
||||
}
|
||||
|
||||
ScriptLanguage *ScriptDebugger::get_break_language() const {
|
||||
return break_lang;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* script_debugger.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SCRIPT_DEBUGGER_H
|
||||
#define SCRIPT_DEBUGGER_H
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/hash_set.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
||||
class ScriptDebugger {
|
||||
typedef ScriptLanguage::StackInfo StackInfo;
|
||||
|
||||
bool skip_breakpoints = false;
|
||||
|
||||
HashMap<int, HashSet<StringName>> breakpoints;
|
||||
|
||||
static thread_local int lines_left;
|
||||
static thread_local int depth;
|
||||
static thread_local ScriptLanguage *break_lang;
|
||||
static thread_local Vector<StackInfo> error_stack_info;
|
||||
|
||||
public:
|
||||
void set_lines_left(int p_left);
|
||||
_ALWAYS_INLINE_ int get_lines_left() const {
|
||||
return lines_left;
|
||||
}
|
||||
|
||||
void set_depth(int p_depth);
|
||||
_ALWAYS_INLINE_ int get_depth() const {
|
||||
return depth;
|
||||
}
|
||||
|
||||
String breakpoint_find_source(const String &p_source) const;
|
||||
void set_break_language(ScriptLanguage *p_lang) { break_lang = p_lang; }
|
||||
ScriptLanguage *get_break_language() { return break_lang; }
|
||||
void set_skip_breakpoints(bool p_skip_breakpoints);
|
||||
bool is_skipping_breakpoints();
|
||||
void insert_breakpoint(int p_line, const StringName &p_source);
|
||||
void remove_breakpoint(int p_line, const StringName &p_source);
|
||||
_ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const {
|
||||
if (likely(!breakpoints.has(p_line))) {
|
||||
return false;
|
||||
}
|
||||
return breakpoints[p_line].has(p_source);
|
||||
}
|
||||
void clear_breakpoints();
|
||||
const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
|
||||
|
||||
void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
|
||||
ScriptLanguage *get_break_language() const;
|
||||
|
||||
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info);
|
||||
Vector<StackInfo> get_error_stack_info() const;
|
||||
ScriptDebugger() {}
|
||||
};
|
||||
|
||||
#endif // SCRIPT_DEBUGGER_H
|
|
@ -1,150 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* doc_data.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "doc_data.h"
|
||||
|
||||
String DocData::get_default_value_string(const Variant &p_value) {
|
||||
if (p_value.get_type() == Variant::ARRAY) {
|
||||
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
|
||||
} else if (p_value.get_type() == Variant::DICTIONARY) {
|
||||
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
|
||||
} else {
|
||||
return p_value.get_construct_string().replace("\n", " ");
|
||||
}
|
||||
}
|
||||
|
||||
void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
|
||||
if (p_retinfo.type == Variant::INT && p_retinfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
|
||||
p_method.return_type = p_retinfo.hint_string;
|
||||
if (p_method.return_type.is_empty()) {
|
||||
p_method.return_type = "void*";
|
||||
} else {
|
||||
p_method.return_type += "*";
|
||||
}
|
||||
} else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
|
||||
p_method.return_enum = p_retinfo.class_name;
|
||||
if (p_method.return_enum.begins_with("_")) { //proxy class
|
||||
p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
|
||||
}
|
||||
p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
|
||||
p_method.return_type = "int";
|
||||
} else if (p_retinfo.class_name != StringName()) {
|
||||
p_method.return_type = p_retinfo.class_name;
|
||||
} else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
|
||||
p_method.return_type = p_retinfo.hint_string + "[]";
|
||||
} else if (p_retinfo.type == Variant::DICTIONARY && p_retinfo.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
|
||||
p_method.return_type = "Dictionary[" + p_retinfo.hint_string.replace(";", ", ") + "]";
|
||||
} else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
p_method.return_type = p_retinfo.hint_string;
|
||||
} else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
|
||||
p_method.return_type = "Variant";
|
||||
} else if (p_retinfo.type == Variant::NIL) {
|
||||
p_method.return_type = "void";
|
||||
} else {
|
||||
p_method.return_type = Variant::get_type_name(p_retinfo.type);
|
||||
}
|
||||
}
|
||||
|
||||
void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) {
|
||||
p_argument.name = p_arginfo.name;
|
||||
|
||||
if (p_arginfo.type == Variant::INT && p_arginfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
|
||||
p_argument.type = p_arginfo.hint_string;
|
||||
if (p_argument.type.is_empty()) {
|
||||
p_argument.type = "void*";
|
||||
} else {
|
||||
p_argument.type += "*";
|
||||
}
|
||||
} else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
|
||||
p_argument.enumeration = p_arginfo.class_name;
|
||||
if (p_argument.enumeration.begins_with("_")) { //proxy class
|
||||
p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
|
||||
}
|
||||
p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
|
||||
p_argument.type = "int";
|
||||
} else if (p_arginfo.class_name != StringName()) {
|
||||
p_argument.type = p_arginfo.class_name;
|
||||
} else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
|
||||
p_argument.type = p_arginfo.hint_string + "[]";
|
||||
} else if (p_arginfo.type == Variant::DICTIONARY && p_arginfo.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
|
||||
p_argument.type = "Dictionary[" + p_arginfo.hint_string.replace(";", ", ") + "]";
|
||||
} else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
p_argument.type = p_arginfo.hint_string;
|
||||
} else if (p_arginfo.type == Variant::NIL) {
|
||||
// Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary
|
||||
p_argument.type = "Variant";
|
||||
} else {
|
||||
p_argument.type = Variant::get_type_name(p_arginfo.type);
|
||||
}
|
||||
}
|
||||
|
||||
void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc) {
|
||||
p_method.name = p_methodinfo.name;
|
||||
p_method.description = p_desc;
|
||||
|
||||
if (p_methodinfo.flags & METHOD_FLAG_VIRTUAL) {
|
||||
p_method.qualifiers = "virtual";
|
||||
}
|
||||
|
||||
if (p_methodinfo.flags & METHOD_FLAG_CONST) {
|
||||
if (!p_method.qualifiers.is_empty()) {
|
||||
p_method.qualifiers += " ";
|
||||
}
|
||||
p_method.qualifiers += "const";
|
||||
}
|
||||
|
||||
if (p_methodinfo.flags & METHOD_FLAG_VARARG) {
|
||||
if (!p_method.qualifiers.is_empty()) {
|
||||
p_method.qualifiers += " ";
|
||||
}
|
||||
p_method.qualifiers += "vararg";
|
||||
}
|
||||
|
||||
if (p_methodinfo.flags & METHOD_FLAG_STATIC) {
|
||||
if (!p_method.qualifiers.is_empty()) {
|
||||
p_method.qualifiers += " ";
|
||||
}
|
||||
p_method.qualifiers += "static";
|
||||
}
|
||||
|
||||
return_doc_from_retinfo(p_method, p_methodinfo.return_val);
|
||||
|
||||
int i = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = p_methodinfo.arguments.begin(); itr != p_methodinfo.arguments.end(); ++itr, ++i) {
|
||||
DocData::ArgumentDoc argument;
|
||||
argument_doc_from_arginfo(argument, *itr);
|
||||
int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
|
||||
if (default_arg_index >= 0) {
|
||||
Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
|
||||
argument.default_value = get_default_value_string(default_arg);
|
||||
}
|
||||
p_method.arguments.push_back(argument);
|
||||
}
|
||||
}
|
|
@ -1,984 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* doc_data.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DOC_DATA_H
|
||||
#define DOC_DATA_H
|
||||
|
||||
#include "core/io/xml_parser.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class DocData {
|
||||
public:
|
||||
struct ArgumentDoc {
|
||||
String name;
|
||||
String type;
|
||||
String enumeration;
|
||||
bool is_bitfield = false;
|
||||
String default_value;
|
||||
bool operator<(const ArgumentDoc &p_arg) const {
|
||||
if (name == p_arg.name) {
|
||||
return type < p_arg.type;
|
||||
}
|
||||
return name < p_arg.name;
|
||||
}
|
||||
static ArgumentDoc from_dict(const Dictionary &p_dict) {
|
||||
ArgumentDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("type")) {
|
||||
doc.type = p_dict["type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("enumeration")) {
|
||||
doc.enumeration = p_dict["enumeration"];
|
||||
if (p_dict.has("is_bitfield")) {
|
||||
doc.is_bitfield = p_dict["is_bitfield"];
|
||||
}
|
||||
}
|
||||
|
||||
if (p_dict.has("default_value")) {
|
||||
doc.default_value = p_dict["default_value"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const ArgumentDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.type.is_empty()) {
|
||||
dict["type"] = p_doc.type;
|
||||
}
|
||||
|
||||
if (!p_doc.enumeration.is_empty()) {
|
||||
dict["enumeration"] = p_doc.enumeration;
|
||||
dict["is_bitfield"] = p_doc.is_bitfield;
|
||||
}
|
||||
|
||||
if (!p_doc.default_value.is_empty()) {
|
||||
dict["default_value"] = p_doc.default_value;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct MethodDoc {
|
||||
String name;
|
||||
String return_type;
|
||||
String return_enum;
|
||||
bool return_is_bitfield = false;
|
||||
String qualifiers;
|
||||
String description;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
Vector<ArgumentDoc> arguments;
|
||||
Vector<int> errors_returned;
|
||||
String keywords;
|
||||
bool operator<(const MethodDoc &p_method) const {
|
||||
if (name == p_method.name) {
|
||||
// Must be an operator or a constructor since there is no other overloading
|
||||
if (name.left(8) == "operator") {
|
||||
if (arguments.size() == p_method.arguments.size()) {
|
||||
if (arguments.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
return arguments[0].type < p_method.arguments[0].type;
|
||||
}
|
||||
return arguments.size() < p_method.arguments.size();
|
||||
} else {
|
||||
// Must be a constructor
|
||||
// We want this arbitrary order for a class "Foo":
|
||||
// - 1. Default constructor: Foo()
|
||||
// - 2. Copy constructor: Foo(Foo)
|
||||
// - 3+. Other constructors Foo(Bar, ...) based on first argument's name
|
||||
if (arguments.size() == 0 || p_method.arguments.size() == 0) { // 1.
|
||||
return arguments.size() < p_method.arguments.size();
|
||||
}
|
||||
if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2.
|
||||
return (arguments[0].type == return_type) || (p_method.arguments[0].type != p_method.return_type);
|
||||
}
|
||||
return arguments[0] < p_method.arguments[0];
|
||||
}
|
||||
}
|
||||
return name.naturalcasecmp_to(p_method.name) < 0;
|
||||
}
|
||||
static MethodDoc from_dict(const Dictionary &p_dict) {
|
||||
MethodDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("return_type")) {
|
||||
doc.return_type = p_dict["return_type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("return_enum")) {
|
||||
doc.return_enum = p_dict["return_enum"];
|
||||
if (p_dict.has("return_is_bitfield")) {
|
||||
doc.return_is_bitfield = p_dict["return_is_bitfield"];
|
||||
}
|
||||
}
|
||||
|
||||
if (p_dict.has("qualifiers")) {
|
||||
doc.qualifiers = p_dict["qualifiers"];
|
||||
}
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_dict.has("is_deprecated")) {
|
||||
doc.is_deprecated = p_dict["is_deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_experimental")) {
|
||||
doc.is_experimental = p_dict["is_experimental"];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
Array arguments;
|
||||
if (p_dict.has("arguments")) {
|
||||
arguments = p_dict["arguments"];
|
||||
}
|
||||
for (int i = 0; i < arguments.size(); i++) {
|
||||
doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
|
||||
}
|
||||
|
||||
Array errors_returned;
|
||||
if (p_dict.has("errors_returned")) {
|
||||
errors_returned = p_dict["errors_returned"];
|
||||
}
|
||||
for (int i = 0; i < errors_returned.size(); i++) {
|
||||
doc.errors_returned.push_back(errors_returned[i]);
|
||||
}
|
||||
|
||||
if (p_dict.has("keywords")) {
|
||||
doc.keywords = p_dict["keywords"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const MethodDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.return_type.is_empty()) {
|
||||
dict["return_type"] = p_doc.return_type;
|
||||
}
|
||||
|
||||
if (!p_doc.return_enum.is_empty()) {
|
||||
dict["return_enum"] = p_doc.return_enum;
|
||||
dict["return_is_bitfield"] = p_doc.return_is_bitfield;
|
||||
}
|
||||
|
||||
if (!p_doc.qualifiers.is_empty()) {
|
||||
dict["qualifiers"] = p_doc.qualifiers;
|
||||
}
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
if (!p_doc.keywords.is_empty()) {
|
||||
dict["keywords"] = p_doc.keywords;
|
||||
}
|
||||
|
||||
if (!p_doc.arguments.is_empty()) {
|
||||
Array arguments;
|
||||
for (int i = 0; i < p_doc.arguments.size(); i++) {
|
||||
arguments.push_back(ArgumentDoc::to_dict(p_doc.arguments[i]));
|
||||
}
|
||||
dict["arguments"] = arguments;
|
||||
}
|
||||
|
||||
if (!p_doc.errors_returned.is_empty()) {
|
||||
Array errors_returned;
|
||||
for (int i = 0; i < p_doc.errors_returned.size(); i++) {
|
||||
errors_returned.push_back(p_doc.errors_returned[i]);
|
||||
}
|
||||
dict["errors_returned"] = errors_returned;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConstantDoc {
|
||||
String name;
|
||||
String value;
|
||||
bool is_value_valid = false;
|
||||
String type;
|
||||
String enumeration;
|
||||
bool is_bitfield = false;
|
||||
String description;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
String keywords;
|
||||
bool operator<(const ConstantDoc &p_const) const {
|
||||
return name < p_const.name;
|
||||
}
|
||||
static ConstantDoc from_dict(const Dictionary &p_dict) {
|
||||
ConstantDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("value")) {
|
||||
doc.value = p_dict["value"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_value_valid")) {
|
||||
doc.is_value_valid = p_dict["is_value_valid"];
|
||||
}
|
||||
|
||||
if (p_dict.has("type")) {
|
||||
doc.type = p_dict["type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("enumeration")) {
|
||||
doc.enumeration = p_dict["enumeration"];
|
||||
if (p_dict.has("is_bitfield")) {
|
||||
doc.is_bitfield = p_dict["is_bitfield"];
|
||||
}
|
||||
}
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_dict.has("is_deprecated")) {
|
||||
doc.is_deprecated = p_dict["is_deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_experimental")) {
|
||||
doc.is_experimental = p_dict["is_experimental"];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
if (p_dict.has("keywords")) {
|
||||
doc.keywords = p_dict["keywords"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const ConstantDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.value.is_empty()) {
|
||||
dict["value"] = p_doc.value;
|
||||
}
|
||||
|
||||
dict["is_value_valid"] = p_doc.is_value_valid;
|
||||
|
||||
dict["type"] = p_doc.type;
|
||||
|
||||
if (!p_doc.enumeration.is_empty()) {
|
||||
dict["enumeration"] = p_doc.enumeration;
|
||||
dict["is_bitfield"] = p_doc.is_bitfield;
|
||||
}
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
if (!p_doc.keywords.is_empty()) {
|
||||
dict["keywords"] = p_doc.keywords;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct PropertyDoc {
|
||||
String name;
|
||||
String type;
|
||||
String enumeration;
|
||||
bool is_bitfield = false;
|
||||
String description;
|
||||
String setter, getter;
|
||||
String default_value;
|
||||
bool overridden = false;
|
||||
String overrides;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
String keywords;
|
||||
bool operator<(const PropertyDoc &p_prop) const {
|
||||
return name.naturalcasecmp_to(p_prop.name) < 0;
|
||||
}
|
||||
static PropertyDoc from_dict(const Dictionary &p_dict) {
|
||||
PropertyDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("type")) {
|
||||
doc.type = p_dict["type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("enumeration")) {
|
||||
doc.enumeration = p_dict["enumeration"];
|
||||
if (p_dict.has("is_bitfield")) {
|
||||
doc.is_bitfield = p_dict["is_bitfield"];
|
||||
}
|
||||
}
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
if (p_dict.has("setter")) {
|
||||
doc.setter = p_dict["setter"];
|
||||
}
|
||||
|
||||
if (p_dict.has("getter")) {
|
||||
doc.getter = p_dict["getter"];
|
||||
}
|
||||
|
||||
if (p_dict.has("default_value")) {
|
||||
doc.default_value = p_dict["default_value"];
|
||||
}
|
||||
|
||||
if (p_dict.has("overridden")) {
|
||||
doc.overridden = p_dict["overridden"];
|
||||
}
|
||||
|
||||
if (p_dict.has("overrides")) {
|
||||
doc.overrides = p_dict["overrides"];
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_dict.has("is_deprecated")) {
|
||||
doc.is_deprecated = p_dict["is_deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_experimental")) {
|
||||
doc.is_experimental = p_dict["is_experimental"];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
if (p_dict.has("keywords")) {
|
||||
doc.keywords = p_dict["keywords"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const PropertyDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.type.is_empty()) {
|
||||
dict["type"] = p_doc.type;
|
||||
}
|
||||
|
||||
if (!p_doc.enumeration.is_empty()) {
|
||||
dict["enumeration"] = p_doc.enumeration;
|
||||
dict["is_bitfield"] = p_doc.is_bitfield;
|
||||
}
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (!p_doc.setter.is_empty()) {
|
||||
dict["setter"] = p_doc.setter;
|
||||
}
|
||||
|
||||
if (!p_doc.getter.is_empty()) {
|
||||
dict["getter"] = p_doc.getter;
|
||||
}
|
||||
|
||||
if (!p_doc.default_value.is_empty()) {
|
||||
dict["default_value"] = p_doc.default_value;
|
||||
}
|
||||
|
||||
dict["overridden"] = p_doc.overridden;
|
||||
|
||||
if (!p_doc.overrides.is_empty()) {
|
||||
dict["overrides"] = p_doc.overrides;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
if (!p_doc.keywords.is_empty()) {
|
||||
dict["keywords"] = p_doc.keywords;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct ThemeItemDoc {
|
||||
String name;
|
||||
String type;
|
||||
String data_type;
|
||||
String description;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
String default_value;
|
||||
String keywords;
|
||||
bool operator<(const ThemeItemDoc &p_theme_item) const {
|
||||
// First sort by the data type, then by name.
|
||||
if (data_type == p_theme_item.data_type) {
|
||||
return name.naturalcasecmp_to(p_theme_item.name) < 0;
|
||||
}
|
||||
return data_type < p_theme_item.data_type;
|
||||
}
|
||||
static ThemeItemDoc from_dict(const Dictionary &p_dict) {
|
||||
ThemeItemDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("type")) {
|
||||
doc.type = p_dict["type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("data_type")) {
|
||||
doc.data_type = p_dict["data_type"];
|
||||
}
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
if (p_dict.has("default_value")) {
|
||||
doc.default_value = p_dict["default_value"];
|
||||
}
|
||||
|
||||
if (p_dict.has("keywords")) {
|
||||
doc.keywords = p_dict["keywords"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const ThemeItemDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.type.is_empty()) {
|
||||
dict["type"] = p_doc.type;
|
||||
}
|
||||
|
||||
if (!p_doc.data_type.is_empty()) {
|
||||
dict["data_type"] = p_doc.data_type;
|
||||
}
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
if (!p_doc.default_value.is_empty()) {
|
||||
dict["default_value"] = p_doc.default_value;
|
||||
}
|
||||
|
||||
if (!p_doc.keywords.is_empty()) {
|
||||
dict["keywords"] = p_doc.keywords;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct TutorialDoc {
|
||||
String link;
|
||||
String title;
|
||||
static TutorialDoc from_dict(const Dictionary &p_dict) {
|
||||
TutorialDoc doc;
|
||||
|
||||
if (p_dict.has("link")) {
|
||||
doc.link = p_dict["link"];
|
||||
}
|
||||
|
||||
if (p_dict.has("title")) {
|
||||
doc.title = p_dict["title"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const TutorialDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.link.is_empty()) {
|
||||
dict["link"] = p_doc.link;
|
||||
}
|
||||
|
||||
if (!p_doc.title.is_empty()) {
|
||||
dict["title"] = p_doc.title;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct EnumDoc {
|
||||
String description;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
static EnumDoc from_dict(const Dictionary &p_dict) {
|
||||
EnumDoc doc;
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_dict.has("is_deprecated")) {
|
||||
doc.is_deprecated = p_dict["is_deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_experimental")) {
|
||||
doc.is_experimental = p_dict["is_experimental"];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const EnumDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassDoc {
|
||||
String name;
|
||||
String inherits;
|
||||
String brief_description;
|
||||
String description;
|
||||
String keywords;
|
||||
Vector<TutorialDoc> tutorials;
|
||||
Vector<MethodDoc> constructors;
|
||||
Vector<MethodDoc> methods;
|
||||
Vector<MethodDoc> operators;
|
||||
Vector<MethodDoc> signals;
|
||||
Vector<ConstantDoc> constants;
|
||||
HashMap<String, EnumDoc> enums;
|
||||
Vector<PropertyDoc> properties;
|
||||
Vector<MethodDoc> annotations;
|
||||
Vector<ThemeItemDoc> theme_properties;
|
||||
bool is_deprecated = false;
|
||||
String deprecated_message;
|
||||
bool is_experimental = false;
|
||||
String experimental_message;
|
||||
bool is_script_doc = false;
|
||||
String script_path;
|
||||
bool operator<(const ClassDoc &p_class) const {
|
||||
return name < p_class.name;
|
||||
}
|
||||
static ClassDoc from_dict(const Dictionary &p_dict) {
|
||||
ClassDoc doc;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
doc.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("inherits")) {
|
||||
doc.inherits = p_dict["inherits"];
|
||||
}
|
||||
|
||||
if (p_dict.has("brief_description")) {
|
||||
doc.brief_description = p_dict["brief_description"];
|
||||
}
|
||||
|
||||
if (p_dict.has("description")) {
|
||||
doc.description = p_dict["description"];
|
||||
}
|
||||
|
||||
if (p_dict.has("keywords")) {
|
||||
doc.keywords = p_dict["keywords"];
|
||||
}
|
||||
|
||||
Array tutorials;
|
||||
if (p_dict.has("tutorials")) {
|
||||
tutorials = p_dict["tutorials"];
|
||||
}
|
||||
for (int i = 0; i < tutorials.size(); i++) {
|
||||
doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
|
||||
}
|
||||
|
||||
Array constructors;
|
||||
if (p_dict.has("constructors")) {
|
||||
constructors = p_dict["constructors"];
|
||||
}
|
||||
for (int i = 0; i < constructors.size(); i++) {
|
||||
doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
|
||||
}
|
||||
|
||||
Array methods;
|
||||
if (p_dict.has("methods")) {
|
||||
methods = p_dict["methods"];
|
||||
}
|
||||
for (int i = 0; i < methods.size(); i++) {
|
||||
doc.methods.push_back(MethodDoc::from_dict(methods[i]));
|
||||
}
|
||||
|
||||
Array operators;
|
||||
if (p_dict.has("operators")) {
|
||||
operators = p_dict["operators"];
|
||||
}
|
||||
for (int i = 0; i < operators.size(); i++) {
|
||||
doc.operators.push_back(MethodDoc::from_dict(operators[i]));
|
||||
}
|
||||
|
||||
Array signals;
|
||||
if (p_dict.has("signals")) {
|
||||
signals = p_dict["signals"];
|
||||
}
|
||||
for (int i = 0; i < signals.size(); i++) {
|
||||
doc.signals.push_back(MethodDoc::from_dict(signals[i]));
|
||||
}
|
||||
|
||||
Array constants;
|
||||
if (p_dict.has("constants")) {
|
||||
constants = p_dict["constants"];
|
||||
}
|
||||
for (int i = 0; i < constants.size(); i++) {
|
||||
doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
|
||||
}
|
||||
|
||||
Dictionary enums;
|
||||
if (p_dict.has("enums")) {
|
||||
enums = p_dict["enums"];
|
||||
}
|
||||
for (int i = 0; i < enums.size(); i++) {
|
||||
doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i));
|
||||
}
|
||||
|
||||
Array properties;
|
||||
if (p_dict.has("properties")) {
|
||||
properties = p_dict["properties"];
|
||||
}
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
|
||||
}
|
||||
|
||||
Array annotations;
|
||||
if (p_dict.has("annotations")) {
|
||||
annotations = p_dict["annotations"];
|
||||
}
|
||||
for (int i = 0; i < annotations.size(); i++) {
|
||||
doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
|
||||
}
|
||||
|
||||
Array theme_properties;
|
||||
if (p_dict.has("theme_properties")) {
|
||||
theme_properties = p_dict["theme_properties"];
|
||||
}
|
||||
for (int i = 0; i < theme_properties.size(); i++) {
|
||||
doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_dict.has("is_deprecated")) {
|
||||
doc.is_deprecated = p_dict["is_deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_experimental")) {
|
||||
doc.is_experimental = p_dict["is_experimental"];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_dict.has("deprecated")) {
|
||||
doc.is_deprecated = true;
|
||||
doc.deprecated_message = p_dict["deprecated"];
|
||||
}
|
||||
|
||||
if (p_dict.has("experimental")) {
|
||||
doc.is_experimental = true;
|
||||
doc.experimental_message = p_dict["experimental"];
|
||||
}
|
||||
|
||||
if (p_dict.has("is_script_doc")) {
|
||||
doc.is_script_doc = p_dict["is_script_doc"];
|
||||
}
|
||||
|
||||
if (p_dict.has("script_path")) {
|
||||
doc.script_path = p_dict["script_path"];
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
static Dictionary to_dict(const ClassDoc &p_doc) {
|
||||
Dictionary dict;
|
||||
|
||||
if (!p_doc.name.is_empty()) {
|
||||
dict["name"] = p_doc.name;
|
||||
}
|
||||
|
||||
if (!p_doc.inherits.is_empty()) {
|
||||
dict["inherits"] = p_doc.inherits;
|
||||
}
|
||||
|
||||
if (!p_doc.brief_description.is_empty()) {
|
||||
dict["brief_description"] = p_doc.brief_description;
|
||||
}
|
||||
|
||||
if (!p_doc.description.is_empty()) {
|
||||
dict["description"] = p_doc.description;
|
||||
}
|
||||
|
||||
if (!p_doc.tutorials.is_empty()) {
|
||||
Array tutorials;
|
||||
for (int i = 0; i < p_doc.tutorials.size(); i++) {
|
||||
tutorials.push_back(TutorialDoc::to_dict(p_doc.tutorials[i]));
|
||||
}
|
||||
dict["tutorials"] = tutorials;
|
||||
}
|
||||
|
||||
if (!p_doc.constructors.is_empty()) {
|
||||
Array constructors;
|
||||
for (int i = 0; i < p_doc.constructors.size(); i++) {
|
||||
constructors.push_back(MethodDoc::to_dict(p_doc.constructors[i]));
|
||||
}
|
||||
dict["constructors"] = constructors;
|
||||
}
|
||||
|
||||
if (!p_doc.methods.is_empty()) {
|
||||
Array methods;
|
||||
for (int i = 0; i < p_doc.methods.size(); i++) {
|
||||
methods.push_back(MethodDoc::to_dict(p_doc.methods[i]));
|
||||
}
|
||||
dict["methods"] = methods;
|
||||
}
|
||||
|
||||
if (!p_doc.operators.is_empty()) {
|
||||
Array operators;
|
||||
for (int i = 0; i < p_doc.operators.size(); i++) {
|
||||
operators.push_back(MethodDoc::to_dict(p_doc.operators[i]));
|
||||
}
|
||||
dict["operators"] = operators;
|
||||
}
|
||||
|
||||
if (!p_doc.signals.is_empty()) {
|
||||
Array signals;
|
||||
for (int i = 0; i < p_doc.signals.size(); i++) {
|
||||
signals.push_back(MethodDoc::to_dict(p_doc.signals[i]));
|
||||
}
|
||||
dict["signals"] = signals;
|
||||
}
|
||||
|
||||
if (!p_doc.constants.is_empty()) {
|
||||
Array constants;
|
||||
for (int i = 0; i < p_doc.constants.size(); i++) {
|
||||
constants.push_back(ConstantDoc::to_dict(p_doc.constants[i]));
|
||||
}
|
||||
dict["constants"] = constants;
|
||||
}
|
||||
|
||||
if (!p_doc.enums.is_empty()) {
|
||||
Dictionary enums;
|
||||
for (const KeyValue<String, EnumDoc> &E : p_doc.enums) {
|
||||
enums[E.key] = EnumDoc::to_dict(E.value);
|
||||
}
|
||||
dict["enums"] = enums;
|
||||
}
|
||||
|
||||
if (!p_doc.properties.is_empty()) {
|
||||
Array properties;
|
||||
for (int i = 0; i < p_doc.properties.size(); i++) {
|
||||
properties.push_back(PropertyDoc::to_dict(p_doc.properties[i]));
|
||||
}
|
||||
dict["properties"] = properties;
|
||||
}
|
||||
|
||||
if (!p_doc.annotations.is_empty()) {
|
||||
Array annotations;
|
||||
for (int i = 0; i < p_doc.annotations.size(); i++) {
|
||||
annotations.push_back(MethodDoc::to_dict(p_doc.annotations[i]));
|
||||
}
|
||||
dict["annotations"] = annotations;
|
||||
}
|
||||
|
||||
if (!p_doc.theme_properties.is_empty()) {
|
||||
Array theme_properties;
|
||||
for (int i = 0; i < p_doc.theme_properties.size(); i++) {
|
||||
theme_properties.push_back(ThemeItemDoc::to_dict(p_doc.theme_properties[i]));
|
||||
}
|
||||
dict["theme_properties"] = theme_properties;
|
||||
}
|
||||
|
||||
if (p_doc.is_deprecated) {
|
||||
dict["deprecated"] = p_doc.deprecated_message;
|
||||
}
|
||||
|
||||
if (p_doc.is_experimental) {
|
||||
dict["experimental"] = p_doc.experimental_message;
|
||||
}
|
||||
|
||||
dict["is_script_doc"] = p_doc.is_script_doc;
|
||||
|
||||
if (!p_doc.script_path.is_empty()) {
|
||||
dict["script_path"] = p_doc.script_path;
|
||||
}
|
||||
|
||||
if (!p_doc.keywords.is_empty()) {
|
||||
dict["keywords"] = p_doc.keywords;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
static String get_default_value_string(const Variant &p_value);
|
||||
|
||||
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
|
||||
static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo);
|
||||
static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc);
|
||||
};
|
||||
|
||||
#endif // DOC_DATA_H
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_error = env.Clone()
|
||||
|
||||
env_error.add_source_files(env.core_sources, "*.cpp")
|
|
@ -1,85 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* error_list.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "error_list.h"
|
||||
|
||||
const char *error_names[] = {
|
||||
"OK", // OK
|
||||
"Failed", // FAILED
|
||||
"Unavailable", // ERR_UNAVAILABLE
|
||||
"Unconfigured", // ERR_UNCONFIGURED
|
||||
"Unauthorized", // ERR_UNAUTHORIZED
|
||||
"Parameter out of range", // ERR_PARAMETER_RANGE_ERROR
|
||||
"Out of memory", // ERR_OUT_OF_MEMORY
|
||||
"File not found", // ERR_FILE_NOT_FOUND
|
||||
"File: Bad drive", // ERR_FILE_BAD_DRIVE
|
||||
"File: Bad path", // ERR_FILE_BAD_PATH
|
||||
"File: Permission denied", // ERR_FILE_NO_PERMISSION
|
||||
"File already in use", // ERR_FILE_ALREADY_IN_USE
|
||||
"Can't open file", // ERR_FILE_CANT_OPEN
|
||||
"Can't write file", // ERR_FILE_CANT_WRITE
|
||||
"Can't read file", // ERR_FILE_CANT_READ
|
||||
"File unrecognized", // ERR_FILE_UNRECOGNIZED
|
||||
"File corrupt", // ERR_FILE_CORRUPT
|
||||
"Missing dependencies for file", // ERR_FILE_MISSING_DEPENDENCIES
|
||||
"End of file", // ERR_FILE_EOF
|
||||
"Can't open", // ERR_CANT_OPEN
|
||||
"Can't create", // ERR_CANT_CREATE
|
||||
"Query failed", // ERR_QUERY_FAILED
|
||||
"Already in use", // ERR_ALREADY_IN_USE
|
||||
"Locked", // ERR_LOCKED
|
||||
"Timeout", // ERR_TIMEOUT
|
||||
"Can't connect", // ERR_CANT_CONNECT
|
||||
"Can't resolve", // ERR_CANT_RESOLVE
|
||||
"Connection error", // ERR_CONNECTION_ERROR
|
||||
"Can't acquire resource", // ERR_CANT_ACQUIRE_RESOURCE
|
||||
"Can't fork", // ERR_CANT_FORK
|
||||
"Invalid data", // ERR_INVALID_DATA
|
||||
"Invalid parameter", // ERR_INVALID_PARAMETER
|
||||
"Already exists", // ERR_ALREADY_EXISTS
|
||||
"Does not exist", // ERR_DOES_NOT_EXIST
|
||||
"Can't read database", // ERR_DATABASE_CANT_READ
|
||||
"Can't write database", // ERR_DATABASE_CANT_WRITE
|
||||
"Compilation failed", // ERR_COMPILATION_FAILED
|
||||
"Method not found", // ERR_METHOD_NOT_FOUND
|
||||
"Link failed", // ERR_LINK_FAILED
|
||||
"Script failed", // ERR_SCRIPT_FAILED
|
||||
"Cyclic link detected", // ERR_CYCLIC_LINK
|
||||
"Invalid declaration", // ERR_INVALID_DECLARATION
|
||||
"Duplicate symbol", // ERR_DUPLICATE_SYMBOL
|
||||
"Parse error", // ERR_PARSE_ERROR
|
||||
"Busy", // ERR_BUSY
|
||||
"Skip", // ERR_SKIP
|
||||
"Help", // ERR_HELP
|
||||
"Bug", // ERR_BUG
|
||||
"Printer on fire", // ERR_PRINTER_ON_FIRE
|
||||
};
|
||||
|
||||
static_assert(sizeof(error_names) / sizeof(*error_names) == ERR_MAX);
|
|
@ -1,102 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* error_list.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ERROR_LIST_H
|
||||
#define ERROR_LIST_H
|
||||
|
||||
/** Error List. Please never compare an error against FAILED
|
||||
* Either do result != OK , or !result. This way, Error fail
|
||||
* values can be more detailed in the future.
|
||||
*
|
||||
* This is a generic error list, mainly for organizing a language of returning errors.
|
||||
*
|
||||
* Errors:
|
||||
* - Are added to the Error enum in core/error/error_list.h
|
||||
* - Have a description added to error_names in core/error/error_list.cpp
|
||||
* - Are bound with BIND_CORE_ENUM_CONSTANT() in core/core_constants.cpp
|
||||
* - Have a matching Android version in platform/android/java/lib/src/org/godotengine/godot/error/Error.kt
|
||||
*/
|
||||
|
||||
enum Error {
|
||||
OK, // (0)
|
||||
FAILED, ///< Generic fail error
|
||||
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
|
||||
ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
|
||||
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
|
||||
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
|
||||
ERR_OUT_OF_MEMORY, ///< Out of memory
|
||||
ERR_FILE_NOT_FOUND,
|
||||
ERR_FILE_BAD_DRIVE,
|
||||
ERR_FILE_BAD_PATH,
|
||||
ERR_FILE_NO_PERMISSION, // (10)
|
||||
ERR_FILE_ALREADY_IN_USE,
|
||||
ERR_FILE_CANT_OPEN,
|
||||
ERR_FILE_CANT_WRITE,
|
||||
ERR_FILE_CANT_READ,
|
||||
ERR_FILE_UNRECOGNIZED, // (15)
|
||||
ERR_FILE_CORRUPT,
|
||||
ERR_FILE_MISSING_DEPENDENCIES,
|
||||
ERR_FILE_EOF,
|
||||
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
|
||||
ERR_CANT_CREATE, // (20)
|
||||
ERR_QUERY_FAILED,
|
||||
ERR_ALREADY_IN_USE,
|
||||
ERR_LOCKED, ///< resource is locked
|
||||
ERR_TIMEOUT,
|
||||
ERR_CANT_CONNECT, // (25)
|
||||
ERR_CANT_RESOLVE,
|
||||
ERR_CONNECTION_ERROR,
|
||||
ERR_CANT_ACQUIRE_RESOURCE,
|
||||
ERR_CANT_FORK,
|
||||
ERR_INVALID_DATA, ///< Data passed is invalid (30)
|
||||
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
|
||||
ERR_ALREADY_EXISTS, ///< When adding, item already exists
|
||||
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
|
||||
ERR_DATABASE_CANT_READ, ///< database is full
|
||||
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
|
||||
ERR_COMPILATION_FAILED,
|
||||
ERR_METHOD_NOT_FOUND,
|
||||
ERR_LINK_FAILED,
|
||||
ERR_SCRIPT_FAILED,
|
||||
ERR_CYCLIC_LINK, // (40)
|
||||
ERR_INVALID_DECLARATION,
|
||||
ERR_DUPLICATE_SYMBOL,
|
||||
ERR_PARSE_ERROR,
|
||||
ERR_BUSY,
|
||||
ERR_SKIP, // (45)
|
||||
ERR_HELP, ///< user requested help!!
|
||||
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
|
||||
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
|
||||
ERR_MAX, // Not being returned, value represents the number of errors
|
||||
};
|
||||
|
||||
extern const char *error_names[];
|
||||
|
||||
#endif // ERROR_LIST_H
|
|
@ -1,203 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* error_macros.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "error_macros.h"
|
||||
|
||||
#include "core/io/logger.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
// Optional physics interpolation warnings try to include the path to the relevant node.
|
||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||
#include "core/config/project_settings.h"
|
||||
#include "scene/main/node.h"
|
||||
#endif
|
||||
|
||||
static ErrorHandlerList *error_handler_list = nullptr;
|
||||
|
||||
void add_error_handler(ErrorHandlerList *p_handler) {
|
||||
// If p_handler is already in error_handler_list
|
||||
// we'd better remove it first then we can add it.
|
||||
// This prevent cyclic redundancy.
|
||||
remove_error_handler(p_handler);
|
||||
|
||||
_global_lock();
|
||||
|
||||
p_handler->next = error_handler_list;
|
||||
error_handler_list = p_handler;
|
||||
|
||||
_global_unlock();
|
||||
}
|
||||
|
||||
void remove_error_handler(const ErrorHandlerList *p_handler) {
|
||||
_global_lock();
|
||||
|
||||
ErrorHandlerList *prev = nullptr;
|
||||
ErrorHandlerList *l = error_handler_list;
|
||||
|
||||
while (l) {
|
||||
if (l == p_handler) {
|
||||
if (prev) {
|
||||
prev->next = l->next;
|
||||
} else {
|
||||
error_handler_list = l->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = l;
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
_global_unlock();
|
||||
}
|
||||
|
||||
// Errors without messages.
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
_err_print_error(p_function, p_file, p_line, p_error, "", p_editor_notify, p_type);
|
||||
}
|
||||
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), "", p_editor_notify, p_type);
|
||||
}
|
||||
|
||||
// Main error printing function.
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
if (OS::get_singleton()) {
|
||||
OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type);
|
||||
} else {
|
||||
// Fallback if errors happen before OS init or after it's destroyed.
|
||||
const char *err_details = (p_message && *p_message) ? p_message : p_error;
|
||||
fprintf(stderr, "ERROR: %s\n at: %s (%s:%i)\n", err_details, p_function, p_file, p_line);
|
||||
}
|
||||
|
||||
_global_lock();
|
||||
ErrorHandlerList *l = error_handler_list;
|
||||
while (l) {
|
||||
l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type);
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
_global_unlock();
|
||||
}
|
||||
|
||||
// For printing errors when we may crash at any point, so we must flush ASAP a lot of lines
|
||||
// but we don't want to make it noisy by printing lots of file & line info (because it's already
|
||||
// been printing by a preceding _err_print_error).
|
||||
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type) {
|
||||
if (OS::get_singleton()) {
|
||||
OS::get_singleton()->printerr("ERROR: %s\n", p_error.utf8().get_data());
|
||||
} else {
|
||||
// Fallback if errors happen before OS init or after it's destroyed.
|
||||
const char *err_details = p_error.utf8().get_data();
|
||||
fprintf(stderr, "ERROR: %s\n", err_details);
|
||||
}
|
||||
|
||||
_global_lock();
|
||||
ErrorHandlerList *l = error_handler_list;
|
||||
while (l) {
|
||||
l->errfunc(l->userdata, "", "", 0, p_error.utf8().get_data(), "", false, p_type);
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
_global_unlock();
|
||||
}
|
||||
|
||||
// Errors with message. (All combinations of p_error and p_message as String or char*.)
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_type);
|
||||
}
|
||||
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
_err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, p_type);
|
||||
}
|
||||
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, p_type);
|
||||
}
|
||||
|
||||
// Index errors. (All combinations of p_message as String or char*.)
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) {
|
||||
String fstr(p_fatal ? "FATAL: " : "");
|
||||
String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
|
||||
_err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, ERR_HANDLER_ERROR);
|
||||
}
|
||||
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) {
|
||||
_err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
|
||||
}
|
||||
|
||||
void _err_flush_stdout() {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// Prevent error spam by limiting the warnings to a certain frequency.
|
||||
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string) {
|
||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||
const uint32_t warn_max = 2048;
|
||||
const uint32_t warn_timeout_seconds = 15;
|
||||
|
||||
static uint32_t warn_count = warn_max;
|
||||
static uint32_t warn_timeout = warn_timeout_seconds;
|
||||
|
||||
uint32_t time_now = UINT32_MAX;
|
||||
|
||||
if (warn_count) {
|
||||
warn_count--;
|
||||
}
|
||||
|
||||
if (!warn_count) {
|
||||
time_now = OS::get_singleton()->get_ticks_msec() / 1000;
|
||||
}
|
||||
|
||||
if ((warn_count == 0) && (time_now >= warn_timeout)) {
|
||||
warn_count = warn_max;
|
||||
warn_timeout = time_now + warn_timeout_seconds;
|
||||
|
||||
if (GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
||||
// UINT64_MAX means unused.
|
||||
if (p_id.operator uint64_t() == UINT64_MAX) {
|
||||
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + " (possibly benign).", false, ERR_HANDLER_WARNING);
|
||||
} else {
|
||||
String node_name;
|
||||
if (p_id.is_valid()) {
|
||||
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id));
|
||||
if (node && node->is_inside_tree()) {
|
||||
node_name = "\"" + String(node->get_path()) + "\"";
|
||||
} else {
|
||||
node_name = "\"unknown\"";
|
||||
}
|
||||
}
|
||||
|
||||
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + ": " + node_name + " (possibly benign).", false, ERR_HANDLER_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,849 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* error_macros.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ERROR_MACROS_H
|
||||
#define ERROR_MACROS_H
|
||||
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes.
|
||||
|
||||
class String;
|
||||
|
||||
enum ErrorHandlerType {
|
||||
ERR_HANDLER_ERROR,
|
||||
ERR_HANDLER_WARNING,
|
||||
ERR_HANDLER_SCRIPT,
|
||||
ERR_HANDLER_SHADER,
|
||||
};
|
||||
|
||||
// Pointer to the error handler printing function. Reassign to any function to have errors printed.
|
||||
// Parameters: userdata, function, file, line, error, explanation, type.
|
||||
typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
|
||||
|
||||
struct ErrorHandlerList {
|
||||
ErrorHandlerFunc errfunc = nullptr;
|
||||
void *userdata = nullptr;
|
||||
|
||||
ErrorHandlerList *next = nullptr;
|
||||
|
||||
ErrorHandlerList() {}
|
||||
};
|
||||
|
||||
void add_error_handler(ErrorHandlerList *p_handler);
|
||||
void remove_error_handler(const ErrorHandlerList *p_handler);
|
||||
|
||||
// Functions used by the error macros.
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false);
|
||||
void _err_flush_stdout();
|
||||
|
||||
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string);
|
||||
|
||||
#ifdef __GNUC__
|
||||
//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#else
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __debugbreak()
|
||||
#else
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __builtin_trap()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Error macros.
|
||||
* WARNING: These macros work in the opposite way to assert().
|
||||
*
|
||||
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
|
||||
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
|
||||
* running application to fail or crash.
|
||||
* Always try to return processable data, so the engine can keep running well.
|
||||
* Use the _MSG versions to print a meaningful message to help with debugging.
|
||||
*
|
||||
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
|
||||
* those macros, making them look like proper statements.
|
||||
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
|
||||
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
|
||||
*/
|
||||
|
||||
// Index out of bounds error macros.
|
||||
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
|
||||
|
||||
// Integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Unsigned integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Null reference error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL(m_param) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V(m_param, m_retval) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V(m_cond, m_retval) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_CONTINUE_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_BREAK_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_BREAK_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the application crashes.
|
||||
*/
|
||||
#define CRASH_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Generic error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns.
|
||||
*/
|
||||
#define ERR_FAIL() \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_MSG(m_msg) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_EDMSG(m_msg) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V(m_retval) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
|
||||
* Only use this macro at the start of a function that has not been implemented yet, or
|
||||
* if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`.
|
||||
*/
|
||||
#define ERR_PRINT(m_msg) \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ED(m_msg) \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Print warning message macros.
|
||||
|
||||
/**
|
||||
* Prints `m_msg`.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT(m_msg) \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ED(m_msg) \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Warns about `m_msg` only when verbose mode is enabled.
|
||||
*/
|
||||
#define WARN_VERBOSE(m_msg) \
|
||||
{ \
|
||||
if (is_print_verbose_enabled()) { \
|
||||
WARN_PRINT(m_msg); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Print deprecated warning message macros.
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated.
|
||||
*/
|
||||
#define WARN_DEPRECATED \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated and prints `m_msg`.
|
||||
*/
|
||||
#define WARN_DEPRECATED_MSG(m_msg) \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
* If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
|
||||
*
|
||||
* The application crashes.
|
||||
*/
|
||||
#define CRASH_NOW() \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Only use if the application should never reach this point.
|
||||
*
|
||||
* Prints `m_msg`, and then the application crashes.
|
||||
*/
|
||||
#define CRASH_NOW_MSG(m_msg) \
|
||||
if (true) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Note: IN MOST CASES YOU SHOULD NOT USE THIS MACRO.
|
||||
* Do not use unless you understand the trade-offs.
|
||||
*
|
||||
* DEV macros will be compiled out in releases, they are wrapped in DEV_ENABLED.
|
||||
*
|
||||
* Prefer WARNINGS / ERR_FAIL macros (which fail without crashing) - ERR_FAIL should be used in most cases.
|
||||
* Then CRASH_NOW_MSG macros (on rare occasions where error cannot be recovered).
|
||||
*
|
||||
* DEV_ASSERT should generally only be used when both of the following conditions are met:
|
||||
* 1) Bottleneck code where a check in release would be too expensive.
|
||||
* 2) Situations where the check would fail obviously and straight away during the maintenance of the code
|
||||
* (i.e. strict conditions that should be true no matter what)
|
||||
* and that can't fail for other contributors once the code is finished and merged.
|
||||
*/
|
||||
#ifdef DEV_ENABLED
|
||||
#define DEV_ASSERT(m_cond) \
|
||||
if (unlikely(!(m_cond))) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
|
||||
_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define DEV_ASSERT(m_cond)
|
||||
#endif
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
#define DEV_CHECK_ONCE(m_cond) \
|
||||
if (unlikely(!(m_cond))) { \
|
||||
ERR_PRINT_ONCE("DEV_CHECK_ONCE failed \"" _STR(m_cond) "\" is false."); \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define DEV_CHECK_ONCE(m_cond)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Physics Interpolation warnings.
|
||||
* These are spam protection warnings.
|
||||
*/
|
||||
#define PHYSICS_INTERPOLATION_NODE_WARNING(m_object_id, m_string) \
|
||||
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, m_object_id, m_string)
|
||||
|
||||
#define PHYSICS_INTERPOLATION_WARNING(m_string) \
|
||||
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string)
|
||||
|
||||
#endif // ERROR_MACROS_H
|
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
import make_interface_dumper
|
||||
import make_wrappers
|
||||
|
||||
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
|
||||
env.CommandNoCache(
|
||||
"gdextension_interface_dump.gen.h",
|
||||
["gdextension_interface.h", "make_interface_dumper.py"],
|
||||
env.Run(make_interface_dumper.run),
|
||||
)
|
||||
|
||||
env_extension = env.Clone()
|
||||
|
||||
env_extension.add_source_files(env.core_sources, "*.cpp")
|
File diff suppressed because it is too large
Load diff
|
@ -1,46 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* extension_api_dump.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EXTENSION_API_DUMP_H
|
||||
#define EXTENSION_API_DUMP_H
|
||||
|
||||
#include "core/extension/gdextension.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
class GDExtensionAPIDump {
|
||||
public:
|
||||
static Dictionary generate_extension_api(bool p_include_docs = false);
|
||||
static void generate_extension_json_file(const String &p_path, bool p_include_docs = false);
|
||||
static Error validate_extension_json_file(const String &p_path);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // EXTENSION_API_DUMP_H
|
|
@ -1,49 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
void GDExtension::_close_library_bind_compat_88418() {
|
||||
}
|
||||
|
||||
void GDExtension::_initialize_library_bind_compat_88418(InitializationLevel p_level) {
|
||||
}
|
||||
|
||||
void GDExtension::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88418);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("close_library"), &GDExtension::_close_library_bind_compat_88418);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418);
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,230 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDEXTENSION_H
|
||||
#define GDEXTENSION_H
|
||||
|
||||
#include "core/extension/gdextension_interface.h"
|
||||
#include "core/extension/gdextension_loader.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class GDExtensionMethodBind;
|
||||
|
||||
class GDExtension : public Resource {
|
||||
GDCLASS(GDExtension, Resource)
|
||||
|
||||
friend class GDExtensionManager;
|
||||
|
||||
Ref<GDExtensionLoader> loader;
|
||||
|
||||
bool reloadable = false;
|
||||
|
||||
struct Extension {
|
||||
ObjectGDExtension gdextension;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool is_reloading = false;
|
||||
HashMap<StringName, GDExtensionMethodBind *> methods;
|
||||
HashSet<ObjectID> instances;
|
||||
|
||||
struct InstanceState {
|
||||
List<Pair<String, Variant>> properties;
|
||||
bool is_placeholder = false;
|
||||
};
|
||||
HashMap<ObjectID, InstanceState> instance_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
HashMap<StringName, Extension> extension_classes;
|
||||
|
||||
struct ClassCreationDeprecatedInfo {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
GDExtensionClassNotification notification_func = nullptr;
|
||||
GDExtensionClassFreePropertyList free_property_list_func = nullptr;
|
||||
GDExtensionClassCreateInstance create_instance_func = nullptr;
|
||||
GDExtensionClassGetRID get_rid_func = nullptr;
|
||||
GDExtensionClassGetVirtual get_virtual_func = nullptr;
|
||||
GDExtensionClassGetVirtualCallData get_virtual_call_data_func = nullptr;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
};
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs);
|
||||
static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
|
||||
static void _register_extension_class3(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
static void _register_extension_class4(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
|
||||
static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr);
|
||||
static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
|
||||
static void _register_extension_class_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info);
|
||||
static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
|
||||
static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
|
||||
static void _register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
|
||||
static void _register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_group_name, GDExtensionConstStringNamePtr p_prefix);
|
||||
static void _register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_subgroup_name, GDExtensionConstStringNamePtr p_prefix);
|
||||
static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
|
||||
static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
|
||||
static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
|
||||
|
||||
GDExtensionInitialization initialization;
|
||||
int32_t level_initialized = -1;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool is_reloading = false;
|
||||
Vector<GDExtensionMethodBind *> invalid_methods;
|
||||
Vector<ObjectID> instance_bindings;
|
||||
|
||||
static void _track_instance(void *p_user_data, void *p_instance);
|
||||
static void _untrack_instance(void *p_user_data, void *p_instance);
|
||||
|
||||
void _clear_extension(Extension *p_extension);
|
||||
|
||||
// Only called by GDExtensionManager during the reload process.
|
||||
void prepare_reload();
|
||||
void finish_reload();
|
||||
void clear_instance_bindings();
|
||||
#endif
|
||||
|
||||
static HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
HashMap<String, String> class_icon_paths;
|
||||
|
||||
virtual bool editor_can_reload_from_file() override { return false; } // Reloading is handled in a special way.
|
||||
|
||||
static String get_extension_list_config_file();
|
||||
|
||||
const Ref<GDExtensionLoader> get_loader() const { return loader; }
|
||||
|
||||
Error open_library(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
|
||||
void close_library();
|
||||
bool is_library_open() const;
|
||||
|
||||
enum InitializationLevel {
|
||||
INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
|
||||
INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
|
||||
INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
|
||||
INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
|
||||
};
|
||||
|
||||
protected:
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Error _open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol);
|
||||
void _close_library_bind_compat_88418();
|
||||
void _initialize_library_bind_compat_88418(InitializationLevel p_level);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool is_reloadable() const { return reloadable; }
|
||||
void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
|
||||
|
||||
bool has_library_changed() const;
|
||||
|
||||
void track_instance_binding(Object *p_object);
|
||||
void untrack_instance_binding(Object *p_object);
|
||||
#endif
|
||||
|
||||
InitializationLevel get_minimum_library_initialization_level() const;
|
||||
void initialize_library(InitializationLevel p_level);
|
||||
void deinitialize_library(InitializationLevel p_level);
|
||||
|
||||
static void register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
|
||||
static GDExtensionInterfaceFunctionPtr get_interface_function(const StringName &p_function_name);
|
||||
static void initialize_gdextensions();
|
||||
static void finalize_gdextensions();
|
||||
|
||||
GDExtension();
|
||||
~GDExtension();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(GDExtension::InitializationLevel)
|
||||
|
||||
class GDExtensionResourceLoader : public ResourceFormatLoader {
|
||||
public:
|
||||
static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
|
||||
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
};
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
class GDExtensionEditorPlugins {
|
||||
private:
|
||||
static Vector<StringName> extension_classes;
|
||||
|
||||
protected:
|
||||
friend class EditorNode;
|
||||
|
||||
// Since this in core, we can't directly reference EditorNode, so it will
|
||||
// set these function pointers in its constructor.
|
||||
typedef void (*EditorPluginRegisterFunc)(const StringName &p_class_name);
|
||||
static EditorPluginRegisterFunc editor_node_add_plugin;
|
||||
static EditorPluginRegisterFunc editor_node_remove_plugin;
|
||||
|
||||
public:
|
||||
static void add_extension_class(const StringName &p_class_name);
|
||||
static void remove_extension_class(const StringName &p_class_name);
|
||||
|
||||
static const Vector<StringName> &get_extension_classes() {
|
||||
return extension_classes;
|
||||
}
|
||||
};
|
||||
|
||||
class GDExtensionEditorHelp {
|
||||
protected:
|
||||
friend class EditorHelp;
|
||||
|
||||
// Similarly to EditorNode above, we need to be able to ask EditorHelp to parse
|
||||
// new documentation data. Note though that, differently from EditorHelp, this
|
||||
// is initialized even _before_ it gets instantiated, as we need to rely on
|
||||
// this method while initializing the engine.
|
||||
typedef void (*EditorHelpLoadXmlBufferFunc)(const uint8_t *p_buffer, int p_size);
|
||||
static EditorHelpLoadXmlBufferFunc editor_help_load_xml_buffer;
|
||||
|
||||
typedef void (*EditorHelpRemoveClassFunc)(const String &p_class);
|
||||
static EditorHelpRemoveClassFunc editor_help_remove_class;
|
||||
|
||||
public:
|
||||
static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
|
||||
static void remove_class(const String &p_class);
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // GDEXTENSION_H
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,394 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_library_loader.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gdextension_library_loader.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/version.h"
|
||||
#include "gdextension.h"
|
||||
|
||||
Vector<SharedObject> GDExtensionLibraryLoader::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) {
|
||||
Vector<SharedObject> dependencies_shared_objects;
|
||||
if (p_config->has_section("dependencies")) {
|
||||
List<String> config_dependencies;
|
||||
p_config->get_section_keys("dependencies", &config_dependencies);
|
||||
|
||||
for (const String &dependency : config_dependencies) {
|
||||
Vector<String> dependency_tags = dependency.split(".");
|
||||
bool all_tags_met = true;
|
||||
for (int i = 0; i < dependency_tags.size(); i++) {
|
||||
String tag = dependency_tags[i].strip_edges();
|
||||
if (!p_has_feature(tag)) {
|
||||
all_tags_met = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_tags_met) {
|
||||
Dictionary dependency_value = p_config->get_value("dependencies", dependency);
|
||||
for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) {
|
||||
String dependency_path = *key;
|
||||
String target_path = dependency_value[*key];
|
||||
if (dependency_path.is_relative_path()) {
|
||||
dependency_path = p_path.get_base_dir().path_join(dependency_path);
|
||||
}
|
||||
dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies_shared_objects;
|
||||
}
|
||||
|
||||
String GDExtensionLibraryLoader::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) {
|
||||
// First, check the explicit libraries.
|
||||
if (p_config->has_section("libraries")) {
|
||||
List<String> libraries;
|
||||
p_config->get_section_keys("libraries", &libraries);
|
||||
|
||||
// Iterate the libraries, finding the best matching tags.
|
||||
String best_library_path;
|
||||
Vector<String> best_library_tags;
|
||||
for (const String &E : libraries) {
|
||||
Vector<String> tags = E.split(".");
|
||||
bool all_tags_met = true;
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
String tag = tags[i].strip_edges();
|
||||
if (!p_has_feature(tag)) {
|
||||
all_tags_met = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_tags_met && tags.size() > best_library_tags.size()) {
|
||||
best_library_path = p_config->get_value("libraries", E);
|
||||
best_library_tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best_library_path.is_empty()) {
|
||||
if (best_library_path.is_relative_path()) {
|
||||
best_library_path = p_path.get_base_dir().path_join(best_library_path);
|
||||
}
|
||||
if (r_tags != nullptr) {
|
||||
r_tags->append_array(best_library_tags);
|
||||
}
|
||||
return best_library_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Second, try to autodetect.
|
||||
String autodetect_library_prefix;
|
||||
if (p_config->has_section_key("configuration", "autodetect_library_prefix")) {
|
||||
autodetect_library_prefix = p_config->get_value("configuration", "autodetect_library_prefix");
|
||||
}
|
||||
if (!autodetect_library_prefix.is_empty()) {
|
||||
String autodetect_path = autodetect_library_prefix;
|
||||
if (autodetect_path.is_relative_path()) {
|
||||
autodetect_path = p_path.get_base_dir().path_join(autodetect_path);
|
||||
}
|
||||
|
||||
// Find the folder and file parts of the prefix.
|
||||
String folder;
|
||||
String file_prefix;
|
||||
if (DirAccess::dir_exists_absolute(autodetect_path)) {
|
||||
folder = autodetect_path;
|
||||
} else if (DirAccess::dir_exists_absolute(autodetect_path.get_base_dir())) {
|
||||
folder = autodetect_path.get_base_dir();
|
||||
file_prefix = autodetect_path.get_file();
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(String(), vformat("Error in extension: %s. Could not find folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
|
||||
}
|
||||
|
||||
// Open the folder.
|
||||
Ref<DirAccess> dir = DirAccess::open(folder);
|
||||
ERR_FAIL_COND_V_MSG(dir.is_null(), String(), vformat("Error in extension: %s. Could not open folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
|
||||
|
||||
// Iterate the files and check the prefixes, finding the best matching file.
|
||||
String best_file;
|
||||
Vector<String> best_file_tags;
|
||||
dir->list_dir_begin();
|
||||
String file_name = dir->_get_next();
|
||||
while (file_name != "") {
|
||||
if (!dir->current_is_dir() && file_name.begins_with(file_prefix)) {
|
||||
// Check if the files matches all requested feature tags.
|
||||
String tags_str = file_name.trim_prefix(file_prefix);
|
||||
tags_str = tags_str.trim_suffix(tags_str.get_extension());
|
||||
|
||||
Vector<String> tags = tags_str.split(".", false);
|
||||
bool all_tags_met = true;
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
String tag = tags[i].strip_edges();
|
||||
if (!p_has_feature(tag)) {
|
||||
all_tags_met = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If all tags are found in the feature list, and we found more tags than before, use this file.
|
||||
if (all_tags_met && tags.size() > best_file_tags.size()) {
|
||||
best_file_tags = tags;
|
||||
best_file = file_name;
|
||||
}
|
||||
}
|
||||
file_name = dir->_get_next();
|
||||
}
|
||||
|
||||
if (!best_file.is_empty()) {
|
||||
String library_path = folder.path_join(best_file);
|
||||
if (r_tags != nullptr) {
|
||||
r_tags->append_array(best_file_tags);
|
||||
}
|
||||
return library_path;
|
||||
}
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
Error GDExtensionLibraryLoader::open_library(const String &p_path) {
|
||||
Error err = parse_gdextension_file(p_path);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
|
||||
|
||||
Vector<String> abs_dependencies_paths;
|
||||
if (!library_dependencies.is_empty()) {
|
||||
for (const SharedObject &dependency : library_dependencies) {
|
||||
abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path));
|
||||
}
|
||||
}
|
||||
|
||||
OS::GDExtensionData data = {
|
||||
true, // also_set_library_path
|
||||
&library_path, // r_resolved_path
|
||||
Engine::get_singleton()->is_editor_hint(), // generate_temp_files
|
||||
&abs_dependencies_paths, // library_dependencies
|
||||
};
|
||||
|
||||
err = OS::get_singleton()->open_dynamic_library(is_static_library ? String() : abs_path, library, &data);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error GDExtensionLibraryLoader::initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
p_extension->set_reloadable(is_reloadable && Engine::get_singleton()->is_extension_reloading_enabled());
|
||||
#endif
|
||||
|
||||
for (const KeyValue<String, String> &icon : class_icon_paths) {
|
||||
p_extension->class_icon_paths[icon.key] = icon.value;
|
||||
}
|
||||
|
||||
void *entry_funcptr = nullptr;
|
||||
|
||||
Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, entry_symbol, entry_funcptr, false);
|
||||
|
||||
if (err != OK) {
|
||||
ERR_PRINT(vformat("GDExtension entry point '%s' not found in library %s.", entry_symbol, library_path));
|
||||
return err;
|
||||
}
|
||||
|
||||
GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
|
||||
|
||||
GDExtensionBool ret = initialization_function(p_get_proc_address, p_extension.ptr(), r_initialization);
|
||||
|
||||
if (ret) {
|
||||
return OK;
|
||||
} else {
|
||||
ERR_PRINT(vformat("GDExtension initialization function '%s' returned an error.", entry_symbol));
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
void GDExtensionLibraryLoader::close_library() {
|
||||
OS::get_singleton()->close_dynamic_library(library);
|
||||
library = nullptr;
|
||||
}
|
||||
|
||||
bool GDExtensionLibraryLoader::is_library_open() const {
|
||||
return library != nullptr;
|
||||
}
|
||||
|
||||
bool GDExtensionLibraryLoader::has_library_changed() const {
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Check only that the last modified time is different (rather than checking
|
||||
// that it's newer) since some OS's (namely Windows) will preserve the modified
|
||||
// time by default when copying files.
|
||||
if (FileAccess::get_modified_time(resource_path) != resource_last_modified_time) {
|
||||
return true;
|
||||
}
|
||||
if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GDExtensionLibraryLoader::library_exists() const {
|
||||
return FileAccess::exists(resource_path);
|
||||
}
|
||||
|
||||
Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
|
||||
resource_path = p_path;
|
||||
|
||||
Ref<ConfigFile> config;
|
||||
config.instantiate();
|
||||
|
||||
Error err = config->load(p_path);
|
||||
|
||||
if (err != OK) {
|
||||
ERR_PRINT(vformat("Error loading GDExtension configuration file: '%s'.", p_path));
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!config->has_section_key("configuration", "entry_symbol")) {
|
||||
ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: '%s'.", p_path));
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
entry_symbol = config->get_value("configuration", "entry_symbol");
|
||||
|
||||
uint32_t compatibility_minimum[3] = { 0, 0, 0 };
|
||||
if (config->has_section_key("configuration", "compatibility_minimum")) {
|
||||
String compat_string = config->get_value("configuration", "compatibility_minimum");
|
||||
Vector<int> parts = compat_string.split_ints(".");
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
if (i >= 3) {
|
||||
break;
|
||||
}
|
||||
if (parts[i] >= 0) {
|
||||
compatibility_minimum[i] = parts[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: '%s'.", p_path));
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) {
|
||||
ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
bool compatible = true;
|
||||
// Check version lexicographically.
|
||||
if (VERSION_MAJOR != compatibility_minimum[0]) {
|
||||
compatible = VERSION_MAJOR > compatibility_minimum[0];
|
||||
} else if (VERSION_MINOR != compatibility_minimum[1]) {
|
||||
compatible = VERSION_MINOR > compatibility_minimum[1];
|
||||
} else {
|
||||
compatible = VERSION_PATCH >= compatibility_minimum[2];
|
||||
}
|
||||
if (!compatible) {
|
||||
ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Optionally check maximum compatibility.
|
||||
if (config->has_section_key("configuration", "compatibility_maximum")) {
|
||||
uint32_t compatibility_maximum[3] = { 0, 0, 0 };
|
||||
String compat_string = config->get_value("configuration", "compatibility_maximum");
|
||||
Vector<int> parts = compat_string.split_ints(".");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i < parts.size() && parts[i] >= 0) {
|
||||
compatibility_maximum[i] = parts[i];
|
||||
} else {
|
||||
// If a version part is missing, set the maximum to an arbitrary high value.
|
||||
compatibility_maximum[i] = 9999;
|
||||
}
|
||||
}
|
||||
|
||||
compatible = true;
|
||||
if (VERSION_MAJOR != compatibility_maximum[0]) {
|
||||
compatible = VERSION_MAJOR < compatibility_maximum[0];
|
||||
} else if (VERSION_MINOR != compatibility_maximum[1]) {
|
||||
compatible = VERSION_MINOR < compatibility_maximum[1];
|
||||
}
|
||||
#if VERSION_PATCH
|
||||
// #if check to avoid -Wtype-limits warning when 0.
|
||||
else {
|
||||
compatible = VERSION_PATCH <= compatibility_maximum[2];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!compatible) {
|
||||
ERR_PRINT(vformat("GDExtension only compatible with Godot version %s or earlier: %s", compat_string, p_path));
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
library_path = find_extension_library(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
|
||||
|
||||
if (library_path.is_empty()) {
|
||||
const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
|
||||
ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
|
||||
return ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework");
|
||||
|
||||
if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
|
||||
library_path = p_path.get_base_dir().path_join(library_path);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
is_reloadable = config->get_value("configuration", "reloadable", false);
|
||||
|
||||
update_last_modified_time(
|
||||
FileAccess::get_modified_time(resource_path),
|
||||
FileAccess::get_modified_time(library_path));
|
||||
#endif
|
||||
|
||||
library_dependencies = find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
|
||||
|
||||
// Handle icons if any are specified.
|
||||
if (config->has_section("icons")) {
|
||||
List<String> keys;
|
||||
config->get_section_keys("icons", &keys);
|
||||
for (const String &key : keys) {
|
||||
String icon_path = config->get_value("icons", key);
|
||||
if (icon_path.is_relative_path()) {
|
||||
icon_path = p_path.get_base_dir().path_join(icon_path);
|
||||
}
|
||||
|
||||
class_icon_paths[key] = icon_path;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_library_loader.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDEXTENSION_LIBRARY_LOADER_H
|
||||
#define GDEXTENSION_LIBRARY_LOADER_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "core/extension/gdextension_loader.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/os/shared_object.h"
|
||||
|
||||
class GDExtensionLibraryLoader : public GDExtensionLoader {
|
||||
friend class GDExtensionManager;
|
||||
friend class GDExtension;
|
||||
|
||||
private:
|
||||
String resource_path;
|
||||
|
||||
void *library = nullptr; // pointer if valid.
|
||||
String library_path;
|
||||
String entry_symbol;
|
||||
|
||||
bool is_static_library = false;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool is_reloadable = false;
|
||||
#endif
|
||||
|
||||
Vector<SharedObject> library_dependencies;
|
||||
|
||||
HashMap<String, String> class_icon_paths;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
uint64_t resource_last_modified_time = 0;
|
||||
uint64_t library_last_modified_time = 0;
|
||||
|
||||
void update_last_modified_time(uint64_t p_resource_last_modified_time, uint64_t p_library_last_modified_time) {
|
||||
resource_last_modified_time = p_resource_last_modified_time;
|
||||
library_last_modified_time = p_library_last_modified_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
|
||||
static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature);
|
||||
|
||||
virtual Error open_library(const String &p_path) override;
|
||||
virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) override;
|
||||
virtual void close_library() override;
|
||||
virtual bool is_library_open() const override;
|
||||
virtual bool has_library_changed() const override;
|
||||
virtual bool library_exists() const override;
|
||||
|
||||
Error parse_gdextension_file(const String &p_path);
|
||||
};
|
||||
|
||||
#endif // GDEXTENSION_LIBRARY_LOADER_H
|
|
@ -1,48 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_loader.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDEXTENSION_LOADER_H
|
||||
#define GDEXTENSION_LOADER_H
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class GDExtension;
|
||||
|
||||
class GDExtensionLoader : public RefCounted {
|
||||
public:
|
||||
virtual Error open_library(const String &p_path) = 0;
|
||||
virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) = 0;
|
||||
virtual void close_library() = 0;
|
||||
virtual bool is_library_open() const = 0;
|
||||
virtual bool has_library_changed() const = 0;
|
||||
virtual bool library_exists() const = 0;
|
||||
};
|
||||
|
||||
#endif // GDEXTENSION_LOADER_H
|
|
@ -1,432 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_manager.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gdextension_manager.h"
|
||||
|
||||
#include "core/extension/gdextension_library_loader.h"
|
||||
#include "core/extension/gdextension_special_compat_hashes.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/object/script_language.h"
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load) {
|
||||
if (level >= 0) { // Already initialized up to some level.
|
||||
int32_t minimum_level = 0;
|
||||
if (!p_first_load) {
|
||||
minimum_level = p_extension->get_minimum_library_initialization_level();
|
||||
if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
|
||||
return LOAD_STATUS_NEEDS_RESTART;
|
||||
}
|
||||
}
|
||||
// Initialize up to current level.
|
||||
for (int32_t i = minimum_level; i <= level; i++) {
|
||||
p_extension->initialize_library(GDExtension::InitializationLevel(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
|
||||
gdextension_class_icon_paths[kv.key] = kv.value;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Signals that a new extension is loaded so GDScript can register new class names.
|
||||
emit_signal("extension_loaded", p_extension);
|
||||
#endif
|
||||
|
||||
return LOAD_STATUS_OK;
|
||||
}
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(const Ref<GDExtension> &p_extension) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Signals that a new extension is unloading so GDScript can unregister class names.
|
||||
emit_signal("extension_unloading", p_extension);
|
||||
#endif
|
||||
|
||||
if (level >= 0) { // Already initialized up to some level.
|
||||
// Deinitialize down from current level.
|
||||
for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
|
||||
p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
|
||||
gdextension_class_icon_paths.erase(kv.key);
|
||||
}
|
||||
|
||||
return LOAD_STATUS_OK;
|
||||
}
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return LOAD_STATUS_FAILED;
|
||||
}
|
||||
|
||||
Ref<GDExtensionLibraryLoader> loader;
|
||||
loader.instantiate();
|
||||
return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader);
|
||||
}
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader) {
|
||||
DEV_ASSERT(p_loader.is_valid());
|
||||
|
||||
if (gdextension_map.has(p_path)) {
|
||||
return LOAD_STATUS_ALREADY_LOADED;
|
||||
}
|
||||
|
||||
Ref<GDExtension> extension;
|
||||
extension.instantiate();
|
||||
Error err = extension->open_library(p_path, p_loader);
|
||||
if (err != OK) {
|
||||
return LOAD_STATUS_FAILED;
|
||||
}
|
||||
|
||||
LoadStatus status = _load_extension_internal(extension, true);
|
||||
if (status != LOAD_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
extension->set_path(p_path);
|
||||
gdextension_map[p_path] = extension;
|
||||
return LOAD_STATUS_OK;
|
||||
}
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String &p_path) {
|
||||
#ifndef TOOLS_ENABLED
|
||||
ERR_FAIL_V_MSG(LOAD_STATUS_FAILED, "GDExtensions can only be reloaded in an editor build.");
|
||||
#else
|
||||
ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled.");
|
||||
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return LOAD_STATUS_FAILED;
|
||||
}
|
||||
|
||||
if (!gdextension_map.has(p_path)) {
|
||||
return LOAD_STATUS_NOT_LOADED;
|
||||
}
|
||||
|
||||
Ref<GDExtension> extension = gdextension_map[p_path];
|
||||
ERR_FAIL_COND_V_MSG(!extension->is_reloadable(), LOAD_STATUS_FAILED, vformat("This GDExtension is not marked as 'reloadable' or doesn't support reloading: %s.", p_path));
|
||||
|
||||
LoadStatus status;
|
||||
|
||||
extension->prepare_reload();
|
||||
|
||||
// Unload library if it's open. It may not be open if the developer made a
|
||||
// change that broke loading in a previous hot-reload attempt.
|
||||
if (extension->is_library_open()) {
|
||||
status = _unload_extension_internal(extension);
|
||||
if (status != LOAD_STATUS_OK) {
|
||||
// We need to clear these no matter what.
|
||||
extension->clear_instance_bindings();
|
||||
return status;
|
||||
}
|
||||
|
||||
extension->clear_instance_bindings();
|
||||
extension->close_library();
|
||||
}
|
||||
|
||||
Error err = extension->open_library(p_path, extension->loader);
|
||||
if (err != OK) {
|
||||
return LOAD_STATUS_FAILED;
|
||||
}
|
||||
|
||||
status = _load_extension_internal(extension, false);
|
||||
if (status != LOAD_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
extension->finish_reload();
|
||||
|
||||
return LOAD_STATUS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return LOAD_STATUS_FAILED;
|
||||
}
|
||||
|
||||
if (!gdextension_map.has(p_path)) {
|
||||
return LOAD_STATUS_NOT_LOADED;
|
||||
}
|
||||
|
||||
Ref<GDExtension> extension = gdextension_map[p_path];
|
||||
|
||||
LoadStatus status = _unload_extension_internal(extension);
|
||||
if (status != LOAD_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
gdextension_map.erase(p_path);
|
||||
return LOAD_STATUS_OK;
|
||||
}
|
||||
|
||||
bool GDExtensionManager::is_extension_loaded(const String &p_path) const {
|
||||
return gdextension_map.has(p_path);
|
||||
}
|
||||
|
||||
Vector<String> GDExtensionManager::get_loaded_extensions() const {
|
||||
Vector<String> ret;
|
||||
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
ret.push_back(E.key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Ref<GDExtension> GDExtensionManager::get_extension(const String &p_path) {
|
||||
HashMap<String, Ref<GDExtension>>::Iterator E = gdextension_map.find(p_path);
|
||||
ERR_FAIL_COND_V(!E, Ref<GDExtension>());
|
||||
return E->value;
|
||||
}
|
||||
|
||||
bool GDExtensionManager::class_has_icon_path(const String &p_class) const {
|
||||
// TODO: Check that the icon belongs to a registered class somehow.
|
||||
return gdextension_class_icon_paths.has(p_class);
|
||||
}
|
||||
|
||||
String GDExtensionManager::class_get_icon_path(const String &p_class) const {
|
||||
// TODO: Check that the icon belongs to a registered class somehow.
|
||||
if (gdextension_class_icon_paths.has(p_class)) {
|
||||
return gdextension_class_icon_paths[p_class];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(int32_t(p_level) - 1 != level);
|
||||
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
E.value->initialize_library(p_level);
|
||||
|
||||
if (p_level == GDExtension::INITIALIZATION_LEVEL_EDITOR) {
|
||||
for (const KeyValue<String, String> &kv : E.value->class_icon_paths) {
|
||||
gdextension_class_icon_paths[kv.key] = kv.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
level = p_level;
|
||||
}
|
||||
|
||||
void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(int32_t(p_level) != level);
|
||||
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
E.value->deinitialize_library(p_level);
|
||||
}
|
||||
level = int32_t(p_level) - 1;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void GDExtensionManager::track_instance_binding(void *p_token, Object *p_object) {
|
||||
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
if (E.value.ptr() == p_token) {
|
||||
if (E.value->is_reloadable()) {
|
||||
E.value->track_instance_binding(p_object);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDExtensionManager::untrack_instance_binding(void *p_token, Object *p_object) {
|
||||
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
if (E.value.ptr() == p_token) {
|
||||
if (E.value->is_reloadable()) {
|
||||
E.value->untrack_instance_binding(p_object);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDExtensionManager::_reload_all_scripts() {
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptServer::get_language(i)->reload_all_scripts();
|
||||
}
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
void GDExtensionManager::load_extensions() {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
|
||||
while (f.is_valid() && !f->eof_reached()) {
|
||||
String s = f->get_line().strip_edges();
|
||||
if (!s.is_empty()) {
|
||||
LoadStatus err = load_extension(s);
|
||||
ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, vformat("Error loading extension: '%s'.", s));
|
||||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->load_platform_gdextensions();
|
||||
}
|
||||
|
||||
void GDExtensionManager::reload_extensions() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
return;
|
||||
}
|
||||
bool reloaded = false;
|
||||
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||
if (!E.value->is_reloadable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (E.value->has_library_changed()) {
|
||||
reloaded = true;
|
||||
reload_extension(E.value->get_path());
|
||||
}
|
||||
}
|
||||
|
||||
if (reloaded) {
|
||||
emit_signal("extensions_reloaded");
|
||||
|
||||
// Reload all scripts to clear out old references.
|
||||
callable_mp_static(&GDExtensionManager::_reload_all_scripts).call_deferred();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GDExtensionManager::ensure_extensions_loaded(const HashSet<String> &p_extensions) {
|
||||
Vector<String> extensions_added;
|
||||
Vector<String> extensions_removed;
|
||||
|
||||
for (const String &E : p_extensions) {
|
||||
if (!is_extension_loaded(E)) {
|
||||
extensions_added.push_back(E);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> loaded_extensions = get_loaded_extensions();
|
||||
for (const String &loaded_extension : loaded_extensions) {
|
||||
if (!p_extensions.has(loaded_extension)) {
|
||||
// The extension may not have a .gdextension file.
|
||||
const Ref<GDExtension> extension = GDExtensionManager::get_singleton()->get_extension(loaded_extension);
|
||||
if (!extension->get_loader()->library_exists()) {
|
||||
extensions_removed.push_back(loaded_extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String extension_list_config_file = GDExtension::get_extension_list_config_file();
|
||||
if (p_extensions.size()) {
|
||||
if (extensions_added.size() || extensions_removed.size()) {
|
||||
// Extensions were added or removed.
|
||||
Ref<FileAccess> f = FileAccess::open(extension_list_config_file, FileAccess::WRITE);
|
||||
for (const String &E : p_extensions) {
|
||||
f->store_line(E);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (loaded_extensions.size() || FileAccess::exists(extension_list_config_file)) {
|
||||
// Extensions were removed.
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
da->remove(extension_list_config_file);
|
||||
}
|
||||
}
|
||||
|
||||
bool needs_restart = false;
|
||||
for (const String &extension : extensions_added) {
|
||||
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->load_extension(extension);
|
||||
if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
|
||||
needs_restart = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const String &extension : extensions_removed) {
|
||||
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->unload_extension(extension);
|
||||
if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
|
||||
needs_restart = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (extensions_added.size() || extensions_removed.size()) {
|
||||
// Emitting extensions_reloaded so EditorNode can reload Inspector and regenerate documentation.
|
||||
emit_signal("extensions_reloaded");
|
||||
|
||||
// Reload all scripts to clear out old references.
|
||||
callable_mp_static(&GDExtensionManager::_reload_all_scripts).call_deferred();
|
||||
}
|
||||
#endif
|
||||
|
||||
return needs_restart;
|
||||
}
|
||||
|
||||
GDExtensionManager *GDExtensionManager::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void GDExtensionManager::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension);
|
||||
ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension);
|
||||
ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension);
|
||||
ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &GDExtensionManager::get_loaded_extensions);
|
||||
ClassDB::bind_method(D_METHOD("get_extension", "path"), &GDExtensionManager::get_extension);
|
||||
|
||||
BIND_ENUM_CONSTANT(LOAD_STATUS_OK);
|
||||
BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED);
|
||||
BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED);
|
||||
BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED);
|
||||
BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("extensions_reloaded"));
|
||||
ADD_SIGNAL(MethodInfo("extension_loaded", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
|
||||
ADD_SIGNAL(MethodInfo("extension_unloading", PropertyInfo(Variant::OBJECT, "extension", PROPERTY_HINT_RESOURCE_TYPE, "GDExtension")));
|
||||
}
|
||||
|
||||
GDExtensionManager *GDExtensionManager::singleton = nullptr;
|
||||
|
||||
GDExtensionManager::GDExtensionManager() {
|
||||
ERR_FAIL_COND(singleton != nullptr);
|
||||
singleton = this;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
GDExtensionSpecialCompatHashes::initialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
GDExtensionManager::~GDExtensionManager() {
|
||||
if (singleton == this) {
|
||||
singleton = nullptr;
|
||||
}
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
GDExtensionSpecialCompatHashes::finalize();
|
||||
#endif
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_manager.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDEXTENSION_MANAGER_H
|
||||
#define GDEXTENSION_MANAGER_H
|
||||
|
||||
#include "core/extension/gdextension.h"
|
||||
|
||||
class GDExtensionManager : public Object {
|
||||
GDCLASS(GDExtensionManager, Object);
|
||||
|
||||
int32_t level = -1;
|
||||
HashMap<String, Ref<GDExtension>> gdextension_map;
|
||||
HashMap<String, String> gdextension_class_icon_paths;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
static GDExtensionManager *singleton;
|
||||
|
||||
public:
|
||||
enum LoadStatus {
|
||||
LOAD_STATUS_OK,
|
||||
LOAD_STATUS_FAILED,
|
||||
LOAD_STATUS_ALREADY_LOADED,
|
||||
LOAD_STATUS_NOT_LOADED,
|
||||
LOAD_STATUS_NEEDS_RESTART,
|
||||
};
|
||||
|
||||
private:
|
||||
LoadStatus _load_extension_internal(const Ref<GDExtension> &p_extension, bool p_first_load);
|
||||
LoadStatus _unload_extension_internal(const Ref<GDExtension> &p_extension);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _reload_all_scripts();
|
||||
#endif
|
||||
|
||||
public:
|
||||
LoadStatus load_extension(const String &p_path);
|
||||
LoadStatus load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
|
||||
LoadStatus reload_extension(const String &p_path);
|
||||
LoadStatus unload_extension(const String &p_path);
|
||||
bool is_extension_loaded(const String &p_path) const;
|
||||
Vector<String> get_loaded_extensions() const;
|
||||
Ref<GDExtension> get_extension(const String &p_path);
|
||||
|
||||
bool class_has_icon_path(const String &p_class) const;
|
||||
String class_get_icon_path(const String &p_class) const;
|
||||
|
||||
void initialize_extensions(GDExtension::InitializationLevel p_level);
|
||||
void deinitialize_extensions(GDExtension::InitializationLevel p_level);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void track_instance_binding(void *p_token, Object *p_object);
|
||||
void untrack_instance_binding(void *p_token, Object *p_object);
|
||||
#endif
|
||||
|
||||
static GDExtensionManager *get_singleton();
|
||||
|
||||
void load_extensions();
|
||||
void reload_extensions();
|
||||
bool ensure_extensions_loaded(const HashSet<String> &p_extensions);
|
||||
|
||||
GDExtensionManager();
|
||||
~GDExtensionManager();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus)
|
||||
|
||||
#endif // GDEXTENSION_MANAGER_H
|
File diff suppressed because it is too large
Load diff
|
@ -1,62 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdextension_special_compat_hashes.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H
|
||||
#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
|
||||
// Note: In most situations, compatibility methods should be registered via ClassDB::bind_compatibility_method().
|
||||
// This class is only meant to be used in exceptional circumstances, for example, when Godot's hashing
|
||||
// algorithm changes and registering compatibility methods for all affect methods would be onerous.
|
||||
|
||||
class GDExtensionSpecialCompatHashes {
|
||||
struct Mapping {
|
||||
StringName method;
|
||||
uint32_t legacy_hash;
|
||||
uint32_t current_hash;
|
||||
};
|
||||
|
||||
static HashMap<StringName, LocalVector<Mapping>> mappings;
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
static bool lookup_current_hash(const StringName &p_class, const StringName &p_method, uint32_t p_legacy_hash, uint32_t *r_current_hash);
|
||||
static bool get_legacy_hashes(const StringName &p_class, const StringName &p_method, Array &r_hashes, bool p_check_valid = true);
|
||||
};
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H
|
|
@ -1,55 +0,0 @@
|
|||
import zlib
|
||||
|
||||
|
||||
def run(target, source, env):
|
||||
src = str(source[0])
|
||||
dst = str(target[0])
|
||||
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
buf = f.read()
|
||||
decomp_size = len(buf)
|
||||
|
||||
# Use maximum zlib compression level to further reduce file size
|
||||
# (at the cost of initial build times).
|
||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
||||
|
||||
g.write(
|
||||
"""/* THIS FILE IS GENERATED DO NOT EDIT */
|
||||
#ifndef GDEXTENSION_INTERFACE_DUMP_H
|
||||
#define GDEXTENSION_INTERFACE_DUMP_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/io/compression.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
g.write("static const int _gdextension_interface_data_compressed_size = " + str(len(buf)) + ";\n")
|
||||
g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n")
|
||||
g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n")
|
||||
for i in range(len(buf)):
|
||||
g.write("\t" + str(buf[i]) + ",\n")
|
||||
g.write("};\n")
|
||||
|
||||
g.write(
|
||||
"""
|
||||
class GDExtensionInterfaceDump {
|
||||
public:
|
||||
static void generate_gdextension_interface_file(const String &p_path) {
|
||||
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
|
||||
Vector<uint8_t> data;
|
||||
data.resize(_gdextension_interface_data_uncompressed_size);
|
||||
int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
|
||||
ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
|
||||
fa->store_buffer(data.ptr(), data.size());
|
||||
};
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // GDEXTENSION_INTERFACE_DUMP_H
|
||||
"""
|
||||
)
|
|
@ -1,144 +0,0 @@
|
|||
proto_mod = """
|
||||
#define MODBIND$VER($RETTYPE m_name$ARG) \\
|
||||
virtual $RETVAL _##m_name($FUNCARGS) $CONST; \\
|
||||
_FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
|
||||
$RETX _##m_name($CALLARGS);\\
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def generate_mod_version(argcount, const=False, returns=False):
|
||||
s = proto_mod
|
||||
sproto = str(argcount)
|
||||
if returns:
|
||||
sproto += "R"
|
||||
s = s.replace("$RETTYPE", "m_ret, ")
|
||||
s = s.replace("$RETVAL", "m_ret")
|
||||
s = s.replace("$RETX", "return")
|
||||
|
||||
else:
|
||||
s = s.replace("$RETTYPE", "")
|
||||
s = s.replace("$RETVAL", "void")
|
||||
s = s.replace("$RETX", "")
|
||||
|
||||
if const:
|
||||
sproto += "C"
|
||||
s = s.replace("$CONST", "const")
|
||||
else:
|
||||
s = s.replace("$CONST", "")
|
||||
|
||||
s = s.replace("$VER", sproto)
|
||||
argtext = ""
|
||||
funcargs = ""
|
||||
callargs = ""
|
||||
|
||||
for i in range(argcount):
|
||||
if i > 0:
|
||||
funcargs += ", "
|
||||
callargs += ", "
|
||||
|
||||
argtext += ", m_type" + str(i + 1)
|
||||
funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
|
||||
callargs += "arg" + str(i + 1)
|
||||
|
||||
if argcount:
|
||||
s = s.replace("$ARG", argtext)
|
||||
s = s.replace("$FUNCARGS", funcargs)
|
||||
s = s.replace("$CALLARGS", callargs)
|
||||
else:
|
||||
s = s.replace("$ARG", "")
|
||||
s = s.replace("$FUNCARGS", funcargs)
|
||||
s = s.replace("$CALLARGS", callargs)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
proto_ex = """
|
||||
#define EXBIND$VER($RETTYPE m_name$ARG) \\
|
||||
GDVIRTUAL$VER_REQUIRED($RETTYPE_##m_name$ARG)\\
|
||||
virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
|
||||
$RETPRE\\
|
||||
GDVIRTUAL_CALL(_##m_name$CALLARGS$RETREF);\\
|
||||
$RETPOST\\
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def generate_ex_version(argcount, const=False, returns=False):
|
||||
s = proto_ex
|
||||
sproto = str(argcount)
|
||||
if returns:
|
||||
sproto += "R"
|
||||
s = s.replace("$RETTYPE", "m_ret, ")
|
||||
s = s.replace("$RETVAL", "m_ret")
|
||||
s = s.replace("$RETPRE", "m_ret ret; ZeroInitializer<m_ret>::initialize(ret);\\\n")
|
||||
s = s.replace("$RETPOST", "return ret;\\\n")
|
||||
|
||||
else:
|
||||
s = s.replace("$RETTYPE", "")
|
||||
s = s.replace("$RETVAL", "void")
|
||||
s = s.replace("$RETPRE", "")
|
||||
s = s.replace("$RETPOST", "return;")
|
||||
|
||||
if const:
|
||||
sproto += "C"
|
||||
s = s.replace("$CONST", "const")
|
||||
else:
|
||||
s = s.replace("$CONST", "")
|
||||
|
||||
s = s.replace("$VER", sproto)
|
||||
argtext = ""
|
||||
funcargs = ""
|
||||
callargs = ""
|
||||
|
||||
for i in range(argcount):
|
||||
if i > 0:
|
||||
funcargs += ", "
|
||||
|
||||
argtext += ", m_type" + str(i + 1)
|
||||
funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
|
||||
callargs += ", arg" + str(i + 1)
|
||||
|
||||
if argcount:
|
||||
s = s.replace("$ARG", argtext)
|
||||
s = s.replace("$FUNCARGS", funcargs)
|
||||
s = s.replace("$CALLARGS", callargs)
|
||||
else:
|
||||
s = s.replace("$ARG", "")
|
||||
s = s.replace("$FUNCARGS", funcargs)
|
||||
s = s.replace("$CALLARGS", callargs)
|
||||
|
||||
if returns:
|
||||
s = s.replace("$RETREF", ", ret")
|
||||
else:
|
||||
s = s.replace("$RETREF", "")
|
||||
|
||||
return s
|
||||
|
||||
|
||||
def run(target, source, env):
|
||||
max_versions = 12
|
||||
|
||||
txt = """
|
||||
#ifndef GDEXTENSION_WRAPPERS_GEN_H
|
||||
#define GDEXTENSION_WRAPPERS_GEN_H
|
||||
"""
|
||||
|
||||
for i in range(max_versions + 1):
|
||||
txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n"
|
||||
txt += generate_ex_version(i, False, False)
|
||||
txt += generate_ex_version(i, False, True)
|
||||
txt += generate_ex_version(i, True, False)
|
||||
txt += generate_ex_version(i, True, True)
|
||||
|
||||
for i in range(max_versions + 1):
|
||||
txt += "\n/* Module Wrapper " + str(i) + " Arguments */\n"
|
||||
txt += generate_mod_version(i, False, False)
|
||||
txt += generate_mod_version(i, False, True)
|
||||
txt += generate_mod_version(i, True, False)
|
||||
txt += generate_mod_version(i, True, True)
|
||||
|
||||
txt += "\n#endif\n"
|
||||
|
||||
with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(txt)
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
import input_builders
|
||||
|
||||
# Order matters here. Higher index controller database files write on top of lower index database files.
|
||||
controller_databases = [
|
||||
"gamecontrollerdb.txt",
|
||||
"godotcontrollerdb.txt",
|
||||
]
|
||||
|
||||
gensource = env.CommandNoCache(
|
||||
"default_controller_mappings.gen.cpp",
|
||||
controller_databases,
|
||||
env.Run(input_builders.make_default_controller_mappings),
|
||||
)
|
||||
|
||||
env.add_source_files(env.core_sources, "*.cpp")
|
||||
env.add_source_files(env.core_sources, gensource)
|
|
@ -1,39 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* default_controller_mappings.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEFAULT_CONTROLLER_MAPPINGS_H
|
||||
#define DEFAULT_CONTROLLER_MAPPINGS_H
|
||||
|
||||
class DefaultControllerMappings {
|
||||
public:
|
||||
static const char *mappings[];
|
||||
};
|
||||
|
||||
#endif // DEFAULT_CONTROLLER_MAPPINGS_H
|
File diff suppressed because it is too large
Load diff
|
@ -1,35 +0,0 @@
|
|||
# Game Controller DB for Godot in SDL 2.0.16 format
|
||||
# Source: https://github.com/godotengine/godot
|
||||
|
||||
# Windows
|
||||
__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
|
||||
|
||||
# Android
|
||||
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
|
||||
|
||||
# Web
|
||||
standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:+a4,righttrigger:+a5,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
|
||||
Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||
Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Web,
|
||||
Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Web,
|
||||
MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
|
||||
MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
|
||||
MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
|
||||
MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
|
||||
MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
|
||||
Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
||||
Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
|
||||
MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
|
||||
Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
|
||||
Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
|
||||
MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Web
|
||||
Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
|
||||
Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
|
||||
Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
||||
Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
|
||||
Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
|
@ -1,41 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
void Input::_vibrate_handheld_bind_compat_91143(int p_duration_ms) {
|
||||
vibrate_handheld(p_duration_ms, -1.0);
|
||||
}
|
||||
|
||||
void Input::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::_vibrate_handheld_bind_compat_91143, DEFVAL(500));
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
File diff suppressed because it is too large
Load diff
|
@ -1,407 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
#include "core/input/input_event.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/templates/rb_set.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
class Input : public Object {
|
||||
GDCLASS(Input, Object);
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
static Input *singleton;
|
||||
|
||||
static constexpr uint64_t MAX_EVENT = 32;
|
||||
|
||||
public:
|
||||
// Keep synced with "DisplayServer::MouseMode" enum.
|
||||
enum MouseMode {
|
||||
MOUSE_MODE_VISIBLE,
|
||||
MOUSE_MODE_HIDDEN,
|
||||
MOUSE_MODE_CAPTURED,
|
||||
MOUSE_MODE_CONFINED,
|
||||
MOUSE_MODE_CONFINED_HIDDEN,
|
||||
MOUSE_MODE_MAX,
|
||||
};
|
||||
|
||||
#undef CursorShape
|
||||
enum CursorShape {
|
||||
CURSOR_ARROW,
|
||||
CURSOR_IBEAM,
|
||||
CURSOR_POINTING_HAND,
|
||||
CURSOR_CROSS,
|
||||
CURSOR_WAIT,
|
||||
CURSOR_BUSY,
|
||||
CURSOR_DRAG,
|
||||
CURSOR_CAN_DROP,
|
||||
CURSOR_FORBIDDEN,
|
||||
CURSOR_VSIZE,
|
||||
CURSOR_HSIZE,
|
||||
CURSOR_BDIAGSIZE,
|
||||
CURSOR_FDIAGSIZE,
|
||||
CURSOR_MOVE,
|
||||
CURSOR_VSPLIT,
|
||||
CURSOR_HSPLIT,
|
||||
CURSOR_HELP,
|
||||
CURSOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
JOYPADS_MAX = 16,
|
||||
};
|
||||
|
||||
typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
|
||||
|
||||
private:
|
||||
BitField<MouseButtonMask> mouse_button_mask;
|
||||
|
||||
RBSet<Key> key_label_pressed;
|
||||
RBSet<Key> physical_keys_pressed;
|
||||
RBSet<Key> keys_pressed;
|
||||
RBSet<JoyButton> joy_buttons_pressed;
|
||||
RBMap<JoyAxis, float> _joy_axis;
|
||||
//RBMap<StringName,int> custom_action_press;
|
||||
bool gravity_enabled = false;
|
||||
Vector3 gravity;
|
||||
bool accelerometer_enabled = false;
|
||||
Vector3 accelerometer;
|
||||
bool magnetometer_enabled = false;
|
||||
Vector3 magnetometer;
|
||||
bool gyroscope_enabled = false;
|
||||
Vector3 gyroscope;
|
||||
Vector2 mouse_pos;
|
||||
int64_t mouse_window = 0;
|
||||
bool legacy_just_pressed_behavior = false;
|
||||
bool disable_input = false;
|
||||
|
||||
struct ActionState {
|
||||
uint64_t pressed_physics_frame = UINT64_MAX;
|
||||
uint64_t pressed_process_frame = UINT64_MAX;
|
||||
uint64_t released_physics_frame = UINT64_MAX;
|
||||
uint64_t released_process_frame = UINT64_MAX;
|
||||
bool exact = true;
|
||||
|
||||
struct DeviceState {
|
||||
bool pressed[MAX_EVENT] = { false };
|
||||
float strength[MAX_EVENT] = { 0.0 };
|
||||
float raw_strength[MAX_EVENT] = { 0.0 };
|
||||
};
|
||||
bool api_pressed = false;
|
||||
float api_strength = 0.0;
|
||||
HashMap<int, DeviceState> device_states;
|
||||
|
||||
// Cache.
|
||||
struct ActionStateCache {
|
||||
bool pressed = false;
|
||||
float strength = false;
|
||||
float raw_strength = false;
|
||||
} cache;
|
||||
};
|
||||
|
||||
HashMap<StringName, ActionState> action_states;
|
||||
|
||||
bool emulate_touch_from_mouse = false;
|
||||
bool emulate_mouse_from_touch = false;
|
||||
bool agile_input_event_flushing = false;
|
||||
bool use_accumulated_input = true;
|
||||
|
||||
int mouse_from_touch_index = -1;
|
||||
|
||||
struct VibrationInfo {
|
||||
float weak_magnitude;
|
||||
float strong_magnitude;
|
||||
float duration; // Duration in seconds
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
HashMap<int, VibrationInfo> joy_vibration;
|
||||
|
||||
struct VelocityTrack {
|
||||
uint64_t last_tick = 0;
|
||||
Vector2 velocity;
|
||||
Vector2 screen_velocity;
|
||||
Vector2 accum;
|
||||
Vector2 screen_accum;
|
||||
float accum_t = 0.0f;
|
||||
float min_ref_frame;
|
||||
float max_ref_frame;
|
||||
|
||||
void update(const Vector2 &p_delta_p, const Vector2 &p_screen_delta_p);
|
||||
void reset();
|
||||
VelocityTrack();
|
||||
};
|
||||
|
||||
struct Joypad {
|
||||
StringName name;
|
||||
StringName uid;
|
||||
bool connected = false;
|
||||
bool last_buttons[(size_t)JoyButton::MAX] = { false };
|
||||
float last_axis[(size_t)JoyAxis::MAX] = { 0.0f };
|
||||
HatMask last_hat = HatMask::CENTER;
|
||||
int mapping = -1;
|
||||
int hat_current = 0;
|
||||
Dictionary info;
|
||||
};
|
||||
|
||||
VelocityTrack mouse_velocity_track;
|
||||
HashMap<int, VelocityTrack> touch_velocity_track;
|
||||
HashMap<int, Joypad> joy_names;
|
||||
|
||||
HashSet<uint32_t> ignored_device_ids;
|
||||
|
||||
int fallback_mapping = -1; // Index of the guid in map_db.
|
||||
|
||||
CursorShape default_shape = CURSOR_ARROW;
|
||||
|
||||
enum JoyType {
|
||||
TYPE_BUTTON,
|
||||
TYPE_AXIS,
|
||||
TYPE_HAT,
|
||||
TYPE_MAX,
|
||||
};
|
||||
|
||||
enum JoyAxisRange {
|
||||
NEGATIVE_HALF_AXIS = -1,
|
||||
FULL_AXIS = 0,
|
||||
POSITIVE_HALF_AXIS = 1
|
||||
};
|
||||
|
||||
struct JoyEvent {
|
||||
int type = TYPE_MAX;
|
||||
int index = -1; // Can be either JoyAxis or JoyButton.
|
||||
float value = 0.f;
|
||||
};
|
||||
|
||||
struct JoyBinding {
|
||||
JoyType inputType;
|
||||
union {
|
||||
JoyButton button;
|
||||
|
||||
struct {
|
||||
JoyAxis axis;
|
||||
JoyAxisRange range;
|
||||
bool invert;
|
||||
} axis;
|
||||
|
||||
struct {
|
||||
HatDir hat;
|
||||
HatMask hat_mask;
|
||||
} hat;
|
||||
|
||||
} input;
|
||||
|
||||
JoyType outputType;
|
||||
union {
|
||||
JoyButton button;
|
||||
|
||||
struct {
|
||||
JoyAxis axis;
|
||||
JoyAxisRange range;
|
||||
} axis;
|
||||
|
||||
} output;
|
||||
};
|
||||
|
||||
struct JoyDeviceMapping {
|
||||
String uid;
|
||||
String name;
|
||||
Vector<JoyBinding> bindings;
|
||||
};
|
||||
|
||||
Vector<JoyDeviceMapping> map_db;
|
||||
|
||||
void _set_joypad_mapping(Joypad &p_js, int p_map_index);
|
||||
|
||||
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
|
||||
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
|
||||
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
|
||||
JoyButton _get_output_button(const String &output);
|
||||
JoyAxis _get_output_axis(const String &output);
|
||||
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
|
||||
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
|
||||
void _update_action_cache(const StringName &p_action_name, ActionState &r_action_state);
|
||||
|
||||
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
|
||||
|
||||
List<Ref<InputEvent>> buffered_events;
|
||||
#ifdef DEBUG_ENABLED
|
||||
HashSet<Ref<InputEvent>> frame_parsed_events;
|
||||
uint64_t last_parsed_frame = UINT64_MAX;
|
||||
#endif
|
||||
|
||||
friend class DisplayServer;
|
||||
|
||||
static void (*set_mouse_mode_func)(MouseMode);
|
||||
static MouseMode (*get_mouse_mode_func)();
|
||||
static void (*set_mouse_mode_override_func)(MouseMode);
|
||||
static MouseMode (*get_mouse_mode_override_func)();
|
||||
static void (*set_mouse_mode_override_enabled_func)(bool);
|
||||
static bool (*is_mouse_mode_override_enabled_func)();
|
||||
static void (*warp_mouse_func)(const Vector2 &p_position);
|
||||
|
||||
static CursorShape (*get_current_cursor_shape_func)();
|
||||
static void (*set_custom_mouse_cursor_func)(const Ref<Resource> &, CursorShape, const Vector2 &);
|
||||
|
||||
EventDispatchFunc event_dispatch_function = nullptr;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _vibrate_handheld_bind_compat_91143(int p_duration_ms = 500);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_mouse_mode(MouseMode p_mode);
|
||||
MouseMode get_mouse_mode() const;
|
||||
void set_mouse_mode_override(MouseMode p_mode);
|
||||
MouseMode get_mouse_mode_override() const;
|
||||
void set_mouse_mode_override_enabled(bool p_override_enabled);
|
||||
bool is_mouse_mode_override_enabled();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
static Input *get_singleton();
|
||||
|
||||
bool is_anything_pressed() const;
|
||||
bool is_anything_pressed_except_mouse() const;
|
||||
bool is_key_pressed(Key p_keycode) const;
|
||||
bool is_physical_key_pressed(Key p_keycode) const;
|
||||
bool is_key_label_pressed(Key p_keycode) const;
|
||||
bool is_mouse_button_pressed(MouseButton p_button) const;
|
||||
bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
|
||||
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
|
||||
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
|
||||
bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
|
||||
float get_action_strength(const StringName &p_action, bool p_exact = false) const;
|
||||
float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
|
||||
|
||||
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
|
||||
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
|
||||
|
||||
float get_joy_axis(int p_device, JoyAxis p_axis) const;
|
||||
String get_joy_name(int p_idx);
|
||||
TypedArray<int> get_connected_joypads();
|
||||
Vector2 get_joy_vibration_strength(int p_device);
|
||||
float get_joy_vibration_duration(int p_device);
|
||||
uint64_t get_joy_vibration_timestamp(int p_device);
|
||||
void joy_connection_changed(int p_idx, bool p_connected, const String &p_name, const String &p_guid = "", const Dictionary &p_joypad_info = Dictionary());
|
||||
|
||||
Vector3 get_gravity() const;
|
||||
Vector3 get_accelerometer() const;
|
||||
Vector3 get_magnetometer() const;
|
||||
Vector3 get_gyroscope() const;
|
||||
|
||||
Point2 get_mouse_position() const;
|
||||
Vector2 get_last_mouse_velocity();
|
||||
Vector2 get_last_mouse_screen_velocity();
|
||||
BitField<MouseButtonMask> get_mouse_button_mask() const;
|
||||
|
||||
void warp_mouse(const Vector2 &p_position);
|
||||
Point2 warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
|
||||
|
||||
void parse_input_event(const Ref<InputEvent> &p_event);
|
||||
|
||||
void set_gravity(const Vector3 &p_gravity);
|
||||
void set_accelerometer(const Vector3 &p_accel);
|
||||
void set_magnetometer(const Vector3 &p_magnetometer);
|
||||
void set_gyroscope(const Vector3 &p_gyroscope);
|
||||
void set_joy_axis(int p_device, JoyAxis p_axis, float p_value);
|
||||
|
||||
void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
|
||||
void stop_joy_vibration(int p_device);
|
||||
void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);
|
||||
|
||||
void set_mouse_position(const Point2 &p_posf);
|
||||
|
||||
void action_press(const StringName &p_action, float p_strength = 1.f);
|
||||
void action_release(const StringName &p_action);
|
||||
|
||||
void set_emulate_touch_from_mouse(bool p_emulate);
|
||||
bool is_emulating_touch_from_mouse() const;
|
||||
void ensure_touch_mouse_raised();
|
||||
|
||||
void set_emulate_mouse_from_touch(bool p_emulate);
|
||||
bool is_emulating_mouse_from_touch() const;
|
||||
|
||||
CursorShape get_default_cursor_shape() const;
|
||||
void set_default_cursor_shape(CursorShape p_shape);
|
||||
CursorShape get_current_cursor_shape() const;
|
||||
void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
|
||||
|
||||
void parse_mapping(const String &p_mapping);
|
||||
void joy_button(int p_device, JoyButton p_button, bool p_pressed);
|
||||
void joy_axis(int p_device, JoyAxis p_axis, float p_value);
|
||||
void joy_hat(int p_device, BitField<HatMask> p_val);
|
||||
|
||||
void add_joy_mapping(const String &p_mapping, bool p_update_existing = false);
|
||||
void remove_joy_mapping(const String &p_guid);
|
||||
|
||||
int get_unused_joy_id();
|
||||
|
||||
bool is_joy_known(int p_device);
|
||||
String get_joy_guid(int p_device) const;
|
||||
bool should_ignore_device(int p_vendor_id, int p_product_id) const;
|
||||
Dictionary get_joy_info(int p_device) const;
|
||||
void set_fallback_mapping(const String &p_guid);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void flush_frame_parsed_events();
|
||||
#endif
|
||||
void flush_buffered_events();
|
||||
bool is_agile_input_event_flushing();
|
||||
void set_agile_input_event_flushing(bool p_enable);
|
||||
void set_use_accumulated_input(bool p_enable);
|
||||
bool is_using_accumulated_input();
|
||||
|
||||
void release_pressed_events();
|
||||
|
||||
void set_event_dispatch_function(EventDispatchFunc p_function);
|
||||
|
||||
void set_disable_input(bool p_disable);
|
||||
bool is_input_disabled() const;
|
||||
|
||||
Input();
|
||||
~Input();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Input::MouseMode);
|
||||
VARIANT_ENUM_CAST(Input::CursorShape);
|
||||
|
||||
#endif // INPUT_H
|
|
@ -1,59 +0,0 @@
|
|||
"""Functions used to generate source files during build time"""
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def make_default_controller_mappings(target, source, env):
|
||||
dst = str(target[0])
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write('#include "core/typedefs.h"\n')
|
||||
g.write('#include "core/input/default_controller_mappings.h"\n')
|
||||
|
||||
# ensure mappings have a consistent order
|
||||
platform_mappings: dict = OrderedDict()
|
||||
for src_path in source:
|
||||
with open(str(src_path), "r", encoding="utf-8") as f:
|
||||
# read mapping file and skip header
|
||||
mapping_file_lines = f.readlines()[2:]
|
||||
|
||||
current_platform = None
|
||||
for line in mapping_file_lines:
|
||||
if not line:
|
||||
continue
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
continue
|
||||
if line[0] == "#":
|
||||
current_platform = line[1:].strip()
|
||||
if current_platform not in platform_mappings:
|
||||
platform_mappings[current_platform] = {}
|
||||
elif current_platform:
|
||||
line_parts = line.split(",")
|
||||
guid = line_parts[0]
|
||||
if guid in platform_mappings[current_platform]:
|
||||
g.write(
|
||||
"// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
|
||||
src_path, current_platform, platform_mappings[current_platform][guid]
|
||||
)
|
||||
)
|
||||
platform_mappings[current_platform][guid] = line
|
||||
|
||||
platform_variables = {
|
||||
"Linux": "#ifdef LINUXBSD_ENABLED",
|
||||
"Windows": "#ifdef WINDOWS_ENABLED",
|
||||
"Mac OS X": "#ifdef MACOS_ENABLED",
|
||||
"Android": "#ifdef ANDROID_ENABLED",
|
||||
"iOS": "#ifdef IOS_ENABLED",
|
||||
"Web": "#ifdef WEB_ENABLED",
|
||||
}
|
||||
|
||||
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
|
||||
for platform, mappings in platform_mappings.items():
|
||||
variable = platform_variables[platform]
|
||||
g.write("{}\n".format(variable))
|
||||
for mapping in mappings.values():
|
||||
g.write('\t"{}",\n'.format(mapping))
|
||||
g.write("#endif\n")
|
||||
|
||||
g.write("\tnullptr\n};\n")
|
|
@ -1,141 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input_enums.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef INPUT_ENUMS_H
|
||||
#define INPUT_ENUMS_H
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
|
||||
enum class HatDir {
|
||||
UP = 0,
|
||||
RIGHT = 1,
|
||||
DOWN = 2,
|
||||
LEFT = 3,
|
||||
MAX = 4,
|
||||
};
|
||||
|
||||
enum class HatMask {
|
||||
CENTER = 0,
|
||||
UP = 1,
|
||||
RIGHT = 2,
|
||||
DOWN = 4,
|
||||
LEFT = 8,
|
||||
};
|
||||
|
||||
enum class JoyAxis {
|
||||
INVALID = -1,
|
||||
LEFT_X = 0,
|
||||
LEFT_Y = 1,
|
||||
RIGHT_X = 2,
|
||||
RIGHT_Y = 3,
|
||||
TRIGGER_LEFT = 4,
|
||||
TRIGGER_RIGHT = 5,
|
||||
SDL_MAX = 6,
|
||||
MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
|
||||
};
|
||||
|
||||
enum class JoyButton {
|
||||
INVALID = -1,
|
||||
A = 0,
|
||||
B = 1,
|
||||
X = 2,
|
||||
Y = 3,
|
||||
BACK = 4,
|
||||
GUIDE = 5,
|
||||
START = 6,
|
||||
LEFT_STICK = 7,
|
||||
RIGHT_STICK = 8,
|
||||
LEFT_SHOULDER = 9,
|
||||
RIGHT_SHOULDER = 10,
|
||||
DPAD_UP = 11,
|
||||
DPAD_DOWN = 12,
|
||||
DPAD_LEFT = 13,
|
||||
DPAD_RIGHT = 14,
|
||||
MISC1 = 15,
|
||||
PADDLE1 = 16,
|
||||
PADDLE2 = 17,
|
||||
PADDLE3 = 18,
|
||||
PADDLE4 = 19,
|
||||
TOUCHPAD = 20,
|
||||
SDL_MAX = 21,
|
||||
MAX = 128, // Android supports up to 36 buttons. DirectInput supports up to 128 buttons.
|
||||
};
|
||||
|
||||
enum class MIDIMessage {
|
||||
NONE = 0,
|
||||
NOTE_OFF = 0x8,
|
||||
NOTE_ON = 0x9,
|
||||
AFTERTOUCH = 0xA,
|
||||
CONTROL_CHANGE = 0xB,
|
||||
PROGRAM_CHANGE = 0xC,
|
||||
CHANNEL_PRESSURE = 0xD,
|
||||
PITCH_BEND = 0xE,
|
||||
SYSTEM_EXCLUSIVE = 0xF0,
|
||||
QUARTER_FRAME = 0xF1,
|
||||
SONG_POSITION_POINTER = 0xF2,
|
||||
SONG_SELECT = 0xF3,
|
||||
TUNE_REQUEST = 0xF6,
|
||||
TIMING_CLOCK = 0xF8,
|
||||
START = 0xFA,
|
||||
CONTINUE = 0xFB,
|
||||
STOP = 0xFC,
|
||||
ACTIVE_SENSING = 0xFE,
|
||||
SYSTEM_RESET = 0xFF,
|
||||
};
|
||||
|
||||
enum class MouseButton {
|
||||
NONE = 0,
|
||||
LEFT = 1,
|
||||
RIGHT = 2,
|
||||
MIDDLE = 3,
|
||||
WHEEL_UP = 4,
|
||||
WHEEL_DOWN = 5,
|
||||
WHEEL_LEFT = 6,
|
||||
WHEEL_RIGHT = 7,
|
||||
MB_XBUTTON1 = 8, // "XBUTTON1" is a reserved word on Windows.
|
||||
MB_XBUTTON2 = 9, // "XBUTTON2" is a reserved word on Windows.
|
||||
};
|
||||
|
||||
enum class MouseButtonMask {
|
||||
NONE = 0,
|
||||
LEFT = (1 << (int(MouseButton::LEFT) - 1)),
|
||||
RIGHT = (1 << (int(MouseButton::RIGHT) - 1)),
|
||||
MIDDLE = (1 << (int(MouseButton::MIDDLE) - 1)),
|
||||
MB_XBUTTON1 = (1 << (int(MouseButton::MB_XBUTTON1) - 1)),
|
||||
MB_XBUTTON2 = (1 << (int(MouseButton::MB_XBUTTON2) - 1)),
|
||||
};
|
||||
|
||||
inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
|
||||
ERR_FAIL_COND_V(button == MouseButton::NONE, MouseButtonMask::NONE);
|
||||
|
||||
return MouseButtonMask(1 << ((int)button - 1));
|
||||
}
|
||||
|
||||
#endif // INPUT_ENUMS_H
|
File diff suppressed because it is too large
Load diff
|
@ -1,599 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input_event.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef INPUT_EVENT_H
|
||||
#define INPUT_EVENT_H
|
||||
|
||||
#include "core/input/input_enums.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/math/transform_2d.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
/**
|
||||
* Input Event classes. These are used in the main loop.
|
||||
* The events are pretty obvious.
|
||||
*/
|
||||
|
||||
class Shortcut;
|
||||
|
||||
/**
|
||||
* Input Modifier Status
|
||||
* for keyboard/mouse events.
|
||||
*/
|
||||
|
||||
class InputEvent : public Resource {
|
||||
GDCLASS(InputEvent, Resource);
|
||||
|
||||
int device = 0;
|
||||
|
||||
protected:
|
||||
bool canceled = false;
|
||||
bool pressed = false;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static const int DEVICE_ID_EMULATION;
|
||||
static const int DEVICE_ID_INTERNAL;
|
||||
|
||||
void set_device(int p_device);
|
||||
int get_device() const;
|
||||
|
||||
bool is_action(const StringName &p_action, bool p_exact_match = false) const;
|
||||
bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
|
||||
bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
|
||||
float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
|
||||
float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
|
||||
|
||||
bool is_canceled() const;
|
||||
bool is_pressed() const;
|
||||
bool is_released() const;
|
||||
virtual bool is_echo() const;
|
||||
|
||||
virtual String as_text() const = 0;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const;
|
||||
|
||||
virtual bool is_action_type() const;
|
||||
|
||||
virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
|
||||
|
||||
InputEvent() {}
|
||||
};
|
||||
|
||||
class InputEventFromWindow : public InputEvent {
|
||||
GDCLASS(InputEventFromWindow, InputEvent);
|
||||
|
||||
int64_t window_id = 0;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_window_id(int64_t p_id);
|
||||
int64_t get_window_id() const;
|
||||
|
||||
InputEventFromWindow() {}
|
||||
};
|
||||
|
||||
class InputEventWithModifiers : public InputEventFromWindow {
|
||||
GDCLASS(InputEventWithModifiers, InputEventFromWindow);
|
||||
|
||||
bool command_or_control_autoremap = false;
|
||||
|
||||
bool shift_pressed = false;
|
||||
bool alt_pressed = false;
|
||||
bool meta_pressed = false; // "Command" on macOS, "Meta/Win" key on other platforms.
|
||||
bool ctrl_pressed = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _validate_property(PropertyInfo &p_property) const;
|
||||
|
||||
public:
|
||||
void set_command_or_control_autoremap(bool p_enabled);
|
||||
bool is_command_or_control_autoremap() const;
|
||||
|
||||
bool is_command_or_control_pressed() const;
|
||||
|
||||
void set_shift_pressed(bool p_pressed);
|
||||
bool is_shift_pressed() const;
|
||||
|
||||
void set_alt_pressed(bool p_pressed);
|
||||
bool is_alt_pressed() const;
|
||||
|
||||
void set_ctrl_pressed(bool p_pressed);
|
||||
bool is_ctrl_pressed() const;
|
||||
|
||||
void set_meta_pressed(bool p_pressed);
|
||||
bool is_meta_pressed() const;
|
||||
|
||||
void set_modifiers_from_event(const InputEventWithModifiers *event);
|
||||
|
||||
BitField<KeyModifierMask> get_modifiers_mask() const;
|
||||
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventWithModifiers() {}
|
||||
};
|
||||
|
||||
class InputEventKey : public InputEventWithModifiers {
|
||||
GDCLASS(InputEventKey, InputEventWithModifiers);
|
||||
|
||||
Key keycode = Key::NONE; // Key enum, without modifier masks.
|
||||
Key physical_keycode = Key::NONE;
|
||||
Key key_label = Key::NONE;
|
||||
uint32_t unicode = 0; ///unicode
|
||||
KeyLocation location = KeyLocation::UNSPECIFIED;
|
||||
|
||||
bool echo = false; /// true if this is an echo key
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_pressed(bool p_pressed);
|
||||
|
||||
void set_keycode(Key p_keycode);
|
||||
Key get_keycode() const;
|
||||
|
||||
void set_physical_keycode(Key p_keycode);
|
||||
Key get_physical_keycode() const;
|
||||
|
||||
void set_key_label(Key p_key_label);
|
||||
Key get_key_label() const;
|
||||
|
||||
void set_unicode(char32_t p_unicode);
|
||||
char32_t get_unicode() const;
|
||||
|
||||
void set_location(KeyLocation p_key_location);
|
||||
KeyLocation get_location() const;
|
||||
|
||||
void set_echo(bool p_enable);
|
||||
virtual bool is_echo() const override;
|
||||
|
||||
Key get_keycode_with_modifiers() const;
|
||||
Key get_physical_keycode_with_modifiers() const;
|
||||
Key get_key_label_with_modifiers() const;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
|
||||
|
||||
virtual bool is_action_type() const override { return true; }
|
||||
|
||||
virtual String as_text_physical_keycode() const;
|
||||
virtual String as_text_keycode() const;
|
||||
virtual String as_text_key_label() const;
|
||||
virtual String as_text_location() const;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
|
||||
|
||||
InputEventKey() {}
|
||||
};
|
||||
|
||||
class InputEventMouse : public InputEventWithModifiers {
|
||||
GDCLASS(InputEventMouse, InputEventWithModifiers);
|
||||
|
||||
BitField<MouseButtonMask> button_mask;
|
||||
|
||||
Vector2 pos;
|
||||
Vector2 global_pos;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_button_mask(BitField<MouseButtonMask> p_mask);
|
||||
BitField<MouseButtonMask> get_button_mask() const;
|
||||
|
||||
void set_position(const Vector2 &p_pos);
|
||||
Vector2 get_position() const;
|
||||
|
||||
void set_global_position(const Vector2 &p_global_pos);
|
||||
Vector2 get_global_position() const;
|
||||
|
||||
InputEventMouse() {}
|
||||
};
|
||||
|
||||
class InputEventMouseButton : public InputEventMouse {
|
||||
GDCLASS(InputEventMouseButton, InputEventMouse);
|
||||
|
||||
float factor = 1;
|
||||
MouseButton button_index = MouseButton::NONE;
|
||||
bool double_click = false; //last even less than double click time
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_factor(float p_factor);
|
||||
float get_factor() const;
|
||||
|
||||
void set_button_index(MouseButton p_index);
|
||||
MouseButton get_button_index() const;
|
||||
|
||||
void set_pressed(bool p_pressed);
|
||||
void set_canceled(bool p_canceled);
|
||||
|
||||
void set_double_click(bool p_double_click);
|
||||
bool is_double_click() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
|
||||
|
||||
virtual bool is_action_type() const override { return true; }
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventMouseButton() {}
|
||||
};
|
||||
|
||||
class InputEventMouseMotion : public InputEventMouse {
|
||||
GDCLASS(InputEventMouseMotion, InputEventMouse);
|
||||
|
||||
Vector2 tilt;
|
||||
float pressure = 0;
|
||||
Vector2 relative;
|
||||
Vector2 screen_relative;
|
||||
Vector2 velocity;
|
||||
Vector2 screen_velocity;
|
||||
bool pen_inverted = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_tilt(const Vector2 &p_tilt);
|
||||
Vector2 get_tilt() const;
|
||||
|
||||
void set_pressure(float p_pressure);
|
||||
float get_pressure() const;
|
||||
|
||||
void set_pen_inverted(bool p_inverted);
|
||||
bool get_pen_inverted() const;
|
||||
|
||||
void set_relative(const Vector2 &p_relative);
|
||||
Vector2 get_relative() const;
|
||||
|
||||
void set_relative_screen_position(const Vector2 &p_relative);
|
||||
Vector2 get_relative_screen_position() const;
|
||||
|
||||
void set_velocity(const Vector2 &p_velocity);
|
||||
Vector2 get_velocity() const;
|
||||
|
||||
void set_screen_velocity(const Vector2 &p_velocity);
|
||||
Vector2 get_screen_velocity() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
virtual bool accumulate(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
InputEventMouseMotion() {}
|
||||
};
|
||||
|
||||
class InputEventJoypadMotion : public InputEvent {
|
||||
GDCLASS(InputEventJoypadMotion, InputEvent);
|
||||
JoyAxis axis = (JoyAxis)0; ///< Joypad axis
|
||||
float axis_value = 0; ///< -1 to 1
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_axis(JoyAxis p_axis);
|
||||
JoyAxis get_axis() const;
|
||||
|
||||
void set_axis_value(float p_value);
|
||||
float get_axis_value() const;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
|
||||
|
||||
virtual bool is_action_type() const override { return true; }
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
static Ref<InputEventJoypadMotion> create_reference(JoyAxis p_axis, float p_value);
|
||||
|
||||
InputEventJoypadMotion() {}
|
||||
};
|
||||
|
||||
class InputEventJoypadButton : public InputEvent {
|
||||
GDCLASS(InputEventJoypadButton, InputEvent);
|
||||
|
||||
JoyButton button_index = (JoyButton)0;
|
||||
float pressure = 0; //0 to 1
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_button_index(JoyButton p_index);
|
||||
JoyButton get_button_index() const;
|
||||
|
||||
void set_pressed(bool p_pressed);
|
||||
|
||||
void set_pressure(float p_pressure);
|
||||
float get_pressure() const;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
|
||||
|
||||
virtual bool is_action_type() const override { return true; }
|
||||
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
static Ref<InputEventJoypadButton> create_reference(JoyButton p_btn_index);
|
||||
|
||||
InputEventJoypadButton() {}
|
||||
};
|
||||
|
||||
class InputEventScreenTouch : public InputEventFromWindow {
|
||||
GDCLASS(InputEventScreenTouch, InputEventFromWindow);
|
||||
int index = 0;
|
||||
Vector2 pos;
|
||||
bool double_tap = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_index(int p_index);
|
||||
int get_index() const;
|
||||
|
||||
void set_position(const Vector2 &p_pos);
|
||||
Vector2 get_position() const;
|
||||
|
||||
void set_pressed(bool p_pressed);
|
||||
void set_canceled(bool p_canceled);
|
||||
|
||||
void set_double_tap(bool p_double_tap);
|
||||
bool is_double_tap() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventScreenTouch() {}
|
||||
};
|
||||
|
||||
class InputEventScreenDrag : public InputEventFromWindow {
|
||||
GDCLASS(InputEventScreenDrag, InputEventFromWindow);
|
||||
int index = 0;
|
||||
Vector2 pos;
|
||||
Vector2 relative;
|
||||
Vector2 screen_relative;
|
||||
Vector2 velocity;
|
||||
Vector2 screen_velocity;
|
||||
Vector2 tilt;
|
||||
float pressure = 0;
|
||||
bool pen_inverted = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_index(int p_index);
|
||||
int get_index() const;
|
||||
|
||||
void set_tilt(const Vector2 &p_tilt);
|
||||
Vector2 get_tilt() const;
|
||||
|
||||
void set_pressure(float p_pressure);
|
||||
float get_pressure() const;
|
||||
|
||||
void set_pen_inverted(bool p_inverted);
|
||||
bool get_pen_inverted() const;
|
||||
|
||||
void set_position(const Vector2 &p_pos);
|
||||
Vector2 get_position() const;
|
||||
|
||||
void set_relative(const Vector2 &p_relative);
|
||||
Vector2 get_relative() const;
|
||||
|
||||
void set_relative_screen_position(const Vector2 &p_relative);
|
||||
Vector2 get_relative_screen_position() const;
|
||||
|
||||
void set_velocity(const Vector2 &p_velocity);
|
||||
Vector2 get_velocity() const;
|
||||
|
||||
void set_screen_velocity(const Vector2 &p_velocity);
|
||||
Vector2 get_screen_velocity() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
virtual bool accumulate(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
InputEventScreenDrag() {}
|
||||
};
|
||||
|
||||
class InputEventAction : public InputEvent {
|
||||
GDCLASS(InputEventAction, InputEvent);
|
||||
|
||||
StringName action;
|
||||
float strength = 1.0f;
|
||||
int event_index = -1;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_action(const StringName &p_action);
|
||||
StringName get_action() const;
|
||||
|
||||
void set_pressed(bool p_pressed);
|
||||
|
||||
void set_strength(float p_strength);
|
||||
float get_strength() const;
|
||||
|
||||
void set_event_index(int p_index);
|
||||
int get_event_index() const;
|
||||
|
||||
virtual bool is_action(const StringName &p_action) const;
|
||||
|
||||
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
|
||||
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
|
||||
|
||||
virtual bool is_action_type() const override { return true; }
|
||||
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventAction() {}
|
||||
};
|
||||
|
||||
class InputEventGesture : public InputEventWithModifiers {
|
||||
GDCLASS(InputEventGesture, InputEventWithModifiers);
|
||||
|
||||
Vector2 pos;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_position(const Vector2 &p_pos);
|
||||
Vector2 get_position() const;
|
||||
};
|
||||
|
||||
class InputEventMagnifyGesture : public InputEventGesture {
|
||||
GDCLASS(InputEventMagnifyGesture, InputEventGesture);
|
||||
real_t factor = 1.0;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_factor(real_t p_factor);
|
||||
real_t get_factor() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventMagnifyGesture() {}
|
||||
};
|
||||
|
||||
class InputEventPanGesture : public InputEventGesture {
|
||||
GDCLASS(InputEventPanGesture, InputEventGesture);
|
||||
Vector2 delta;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_delta(const Vector2 &p_delta);
|
||||
Vector2 get_delta() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventPanGesture() {}
|
||||
};
|
||||
|
||||
class InputEventMIDI : public InputEvent {
|
||||
GDCLASS(InputEventMIDI, InputEvent);
|
||||
|
||||
int channel = 0;
|
||||
MIDIMessage message = MIDIMessage::NONE;
|
||||
int pitch = 0;
|
||||
int velocity = 0;
|
||||
int instrument = 0;
|
||||
int pressure = 0;
|
||||
int controller_number = 0;
|
||||
int controller_value = 0;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_channel(const int p_channel);
|
||||
int get_channel() const;
|
||||
|
||||
void set_message(const MIDIMessage p_message);
|
||||
MIDIMessage get_message() const;
|
||||
|
||||
void set_pitch(const int p_pitch);
|
||||
int get_pitch() const;
|
||||
|
||||
void set_velocity(const int p_velocity);
|
||||
int get_velocity() const;
|
||||
|
||||
void set_instrument(const int p_instrument);
|
||||
int get_instrument() const;
|
||||
|
||||
void set_pressure(const int p_pressure);
|
||||
int get_pressure() const;
|
||||
|
||||
void set_controller_number(const int p_controller_number);
|
||||
int get_controller_number() const;
|
||||
|
||||
void set_controller_value(const int p_controller_value);
|
||||
int get_controller_value() const;
|
||||
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventMIDI() {}
|
||||
};
|
||||
|
||||
class InputEventShortcut : public InputEvent {
|
||||
GDCLASS(InputEventShortcut, InputEvent);
|
||||
|
||||
Ref<Shortcut> shortcut;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_shortcut(Ref<Shortcut> p_shortcut);
|
||||
Ref<Shortcut> get_shortcut();
|
||||
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
InputEventShortcut();
|
||||
};
|
||||
|
||||
#endif // INPUT_EVENT_H
|
|
@ -1,41 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input_map.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
void InputMap::_add_action_bind_compat_97281(const StringName &p_action, float p_deadzone) {
|
||||
add_action(p_action, p_deadzone);
|
||||
}
|
||||
|
||||
void InputMap::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::_add_action_bind_compat_97281, DEFVAL(0.5f));
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
|
@ -1,868 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input_map.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "input_map.h"
|
||||
#include "input_map.compat.inc"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/input/input.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
InputMap *InputMap::singleton = nullptr;
|
||||
|
||||
int InputMap::ALL_DEVICES = -1;
|
||||
|
||||
void InputMap::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
|
||||
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
|
||||
ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE));
|
||||
ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
|
||||
ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone);
|
||||
ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
|
||||
ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
|
||||
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
|
||||
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
|
||||
ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
|
||||
ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an nonexistent action error message with a suggestion of the closest
|
||||
* matching action name (if possible).
|
||||
*/
|
||||
String InputMap::suggest_actions(const StringName &p_action) const {
|
||||
List<StringName> actions = get_actions();
|
||||
StringName closest_action;
|
||||
float closest_similarity = 0.0;
|
||||
|
||||
// Find the most action with the most similar name.
|
||||
for (const StringName &action : actions) {
|
||||
const float similarity = String(action).similarity(p_action);
|
||||
|
||||
if (similarity > closest_similarity) {
|
||||
closest_action = action;
|
||||
closest_similarity = similarity;
|
||||
}
|
||||
}
|
||||
|
||||
String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
|
||||
|
||||
if (closest_similarity >= 0.4) {
|
||||
// Only include a suggestion in the error message if it's similar enough.
|
||||
error_message += vformat(" Did you mean \"%s\"?", closest_action);
|
||||
}
|
||||
return error_message;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void InputMap::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
|
||||
const String pf = p_function;
|
||||
bool first_argument_is_action = false;
|
||||
if (p_idx == 0) {
|
||||
first_argument_is_action = (pf == "has_action" || pf == "erase_action" ||
|
||||
pf == "action_set_deadzone" || pf == "action_get_deadzone" ||
|
||||
pf == "action_has_event" || pf == "action_add_event" || pf == "action_get_events" ||
|
||||
pf == "action_erase_event" || pf == "action_erase_events");
|
||||
}
|
||||
if (first_argument_is_action || (p_idx == 1 && pf == "event_is_action")) {
|
||||
// Cannot rely on `get_actions()`, otherwise the actions would be in the context of the Editor (no user-defined actions).
|
||||
List<PropertyInfo> pinfo;
|
||||
ProjectSettings::get_singleton()->get_property_list(&pinfo);
|
||||
|
||||
for (const PropertyInfo &pi : pinfo) {
|
||||
if (!pi.name.begins_with("input/")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
|
||||
r_options->push_back(name.quote());
|
||||
}
|
||||
}
|
||||
|
||||
Object::get_argument_options(p_function, p_idx, r_options);
|
||||
}
|
||||
#endif
|
||||
|
||||
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
|
||||
ERR_FAIL_COND_MSG(input_map.has(p_action), vformat("InputMap already has action \"%s\".", String(p_action)));
|
||||
input_map[p_action] = Action();
|
||||
static int last_id = 1;
|
||||
input_map[p_action].id = last_id;
|
||||
input_map[p_action].deadzone = p_deadzone;
|
||||
last_id++;
|
||||
}
|
||||
|
||||
void InputMap::erase_action(const StringName &p_action) {
|
||||
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
|
||||
|
||||
input_map.erase(p_action);
|
||||
}
|
||||
|
||||
TypedArray<StringName> InputMap::_get_actions() {
|
||||
TypedArray<StringName> ret;
|
||||
List<StringName> actions = get_actions();
|
||||
if (actions.is_empty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (const StringName &E : actions) {
|
||||
ret.push_back(E);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
List<StringName> InputMap::get_actions() const {
|
||||
List<StringName> actions = List<StringName>();
|
||||
if (input_map.is_empty()) {
|
||||
return actions;
|
||||
}
|
||||
|
||||
for (const KeyValue<StringName, Action> &E : input_map) {
|
||||
actions.push_back(E.key);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
|
||||
ERR_FAIL_COND_V(p_event.is_null(), nullptr);
|
||||
|
||||
int i = 0;
|
||||
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
|
||||
int device = E->get()->get_device();
|
||||
if (device == ALL_DEVICES || device == p_event->get_device()) {
|
||||
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
|
||||
if (r_event_index) {
|
||||
*r_event_index = i;
|
||||
}
|
||||
return E;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool InputMap::has_action(const StringName &p_action) const {
|
||||
return input_map.has(p_action);
|
||||
}
|
||||
|
||||
float InputMap::action_get_deadzone(const StringName &p_action) {
|
||||
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action));
|
||||
|
||||
return input_map[p_action].deadzone;
|
||||
}
|
||||
|
||||
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
|
||||
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
|
||||
|
||||
input_map[p_action].deadzone = p_deadzone;
|
||||
}
|
||||
|
||||
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
|
||||
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
|
||||
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
|
||||
if (_find_event(input_map[p_action], p_event, true)) {
|
||||
return; // Already added.
|
||||
}
|
||||
|
||||
input_map[p_action].inputs.push_back(p_event);
|
||||
}
|
||||
|
||||
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
|
||||
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, suggest_actions(p_action));
|
||||
return (_find_event(input_map[p_action], p_event, true) != nullptr);
|
||||
}
|
||||
|
||||
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
|
||||
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
|
||||
|
||||
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
|
||||
if (E) {
|
||||
input_map[p_action].inputs.erase(E);
|
||||
|
||||
if (Input::get_singleton()->is_action_pressed(p_action)) {
|
||||
Input::get_singleton()->action_release(p_action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputMap::action_erase_events(const StringName &p_action) {
|
||||
ERR_FAIL_COND_MSG(!input_map.has(p_action), suggest_actions(p_action));
|
||||
|
||||
input_map[p_action].inputs.clear();
|
||||
}
|
||||
|
||||
TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) {
|
||||
TypedArray<InputEvent> ret;
|
||||
const List<Ref<InputEvent>> *al = action_get_events(p_action);
|
||||
if (al) {
|
||||
for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
|
||||
ret.push_back(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
|
||||
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
|
||||
if (!E) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &E->value.inputs;
|
||||
}
|
||||
|
||||
bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
|
||||
return event_get_action_status(p_event, p_action, p_exact_match);
|
||||
}
|
||||
|
||||
int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
|
||||
int index = -1;
|
||||
bool valid = event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
|
||||
return valid ? index : -1;
|
||||
}
|
||||
|
||||
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
|
||||
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
|
||||
ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
|
||||
|
||||
Ref<InputEventAction> input_event_action = p_event;
|
||||
if (input_event_action.is_valid()) {
|
||||
const bool pressed = input_event_action->is_pressed();
|
||||
if (r_pressed != nullptr) {
|
||||
*r_pressed = pressed;
|
||||
}
|
||||
const float strength = pressed ? input_event_action->get_strength() : 0.0f;
|
||||
if (r_strength != nullptr) {
|
||||
*r_strength = strength;
|
||||
}
|
||||
if (r_raw_strength != nullptr) {
|
||||
*r_raw_strength = strength;
|
||||
}
|
||||
if (r_event_index) {
|
||||
if (input_event_action->get_event_index() >= 0) {
|
||||
*r_event_index = input_event_action->get_event_index();
|
||||
} else {
|
||||
*r_event_index = E->value.inputs.size();
|
||||
}
|
||||
}
|
||||
return input_event_action->get_action() == p_action;
|
||||
}
|
||||
|
||||
List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index);
|
||||
return event != nullptr;
|
||||
}
|
||||
|
||||
const HashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
|
||||
return input_map;
|
||||
}
|
||||
|
||||
void InputMap::load_from_project_settings() {
|
||||
input_map.clear();
|
||||
|
||||
List<PropertyInfo> pinfo;
|
||||
ProjectSettings::get_singleton()->get_property_list(&pinfo);
|
||||
|
||||
for (const PropertyInfo &pi : pinfo) {
|
||||
if (!pi.name.begins_with("input/")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
|
||||
|
||||
Dictionary action = GLOBAL_GET(pi.name);
|
||||
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
|
||||
Array events = action["events"];
|
||||
|
||||
add_action(name, deadzone);
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Ref<InputEvent> event = events[i];
|
||||
if (event.is_null()) {
|
||||
continue;
|
||||
}
|
||||
action_add_event(name, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct _BuiltinActionDisplayName {
|
||||
const char *name;
|
||||
const char *display_name;
|
||||
};
|
||||
|
||||
static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
|
||||
/* clang-format off */
|
||||
{ "ui_accept", TTRC("Accept") },
|
||||
{ "ui_select", TTRC("Select") },
|
||||
{ "ui_cancel", TTRC("Cancel") },
|
||||
{ "ui_focus_next", TTRC("Focus Next") },
|
||||
{ "ui_focus_prev", TTRC("Focus Prev") },
|
||||
{ "ui_left", TTRC("Left") },
|
||||
{ "ui_right", TTRC("Right") },
|
||||
{ "ui_up", TTRC("Up") },
|
||||
{ "ui_down", TTRC("Down") },
|
||||
{ "ui_page_up", TTRC("Page Up") },
|
||||
{ "ui_page_down", TTRC("Page Down") },
|
||||
{ "ui_home", TTRC("Home") },
|
||||
{ "ui_end", TTRC("End") },
|
||||
{ "ui_cut", TTRC("Cut") },
|
||||
{ "ui_copy", TTRC("Copy") },
|
||||
{ "ui_paste", TTRC("Paste") },
|
||||
{ "ui_undo", TTRC("Undo") },
|
||||
{ "ui_redo", TTRC("Redo") },
|
||||
{ "ui_text_completion_query", TTRC("Completion Query") },
|
||||
{ "ui_text_newline", TTRC("New Line") },
|
||||
{ "ui_text_newline_blank", TTRC("New Blank Line") },
|
||||
{ "ui_text_newline_above", TTRC("New Line Above") },
|
||||
{ "ui_text_indent", TTRC("Indent") },
|
||||
{ "ui_text_dedent", TTRC("Dedent") },
|
||||
{ "ui_text_backspace", TTRC("Backspace") },
|
||||
{ "ui_text_backspace_word", TTRC("Backspace Word") },
|
||||
{ "ui_text_backspace_word.macos", TTRC("Backspace Word") },
|
||||
{ "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
|
||||
{ "ui_text_backspace_all_to_left.macos", TTRC("Backspace all to Left") },
|
||||
{ "ui_text_delete", TTRC("Delete") },
|
||||
{ "ui_text_delete_word", TTRC("Delete Word") },
|
||||
{ "ui_text_delete_word.macos", TTRC("Delete Word") },
|
||||
{ "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
|
||||
{ "ui_text_delete_all_to_right.macos", TTRC("Delete all to Right") },
|
||||
{ "ui_text_caret_left", TTRC("Caret Left") },
|
||||
{ "ui_text_caret_word_left", TTRC("Caret Word Left") },
|
||||
{ "ui_text_caret_word_left.macos", TTRC("Caret Word Left") },
|
||||
{ "ui_text_caret_right", TTRC("Caret Right") },
|
||||
{ "ui_text_caret_word_right", TTRC("Caret Word Right") },
|
||||
{ "ui_text_caret_word_right.macos", TTRC("Caret Word Right") },
|
||||
{ "ui_text_caret_up", TTRC("Caret Up") },
|
||||
{ "ui_text_caret_down", TTRC("Caret Down") },
|
||||
{ "ui_text_caret_line_start", TTRC("Caret Line Start") },
|
||||
{ "ui_text_caret_line_start.macos", TTRC("Caret Line Start") },
|
||||
{ "ui_text_caret_line_end", TTRC("Caret Line End") },
|
||||
{ "ui_text_caret_line_end.macos", TTRC("Caret Line End") },
|
||||
{ "ui_text_caret_page_up", TTRC("Caret Page Up") },
|
||||
{ "ui_text_caret_page_down", TTRC("Caret Page Down") },
|
||||
{ "ui_text_caret_document_start", TTRC("Caret Document Start") },
|
||||
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
|
||||
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
|
||||
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
|
||||
{ "ui_text_caret_add_below", TTRC("Caret Add Below") },
|
||||
{ "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
|
||||
{ "ui_text_caret_add_above", TTRC("Caret Add Above") },
|
||||
{ "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
|
||||
{ "ui_text_scroll_up", TTRC("Scroll Up") },
|
||||
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
|
||||
{ "ui_text_scroll_down", TTRC("Scroll Down") },
|
||||
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
|
||||
{ "ui_text_select_all", TTRC("Select All") },
|
||||
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
|
||||
{ "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
|
||||
{ "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") },
|
||||
{ "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
|
||||
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
|
||||
{ "ui_text_submit", TTRC("Submit Text") },
|
||||
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
|
||||
{ "ui_graph_delete", TTRC("Delete Nodes") },
|
||||
{ "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
|
||||
{ "ui_filedialog_refresh", TTRC("Refresh") },
|
||||
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
|
||||
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
|
||||
{ "ui_unicode_start", TTRC("Start Unicode Character Input") },
|
||||
{ "", ""}
|
||||
/* clang-format on */
|
||||
};
|
||||
|
||||
String InputMap::get_builtin_display_name(const String &p_name) const {
|
||||
int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (_builtin_action_display_names[i].name == p_name) {
|
||||
return RTR(_builtin_action_display_names[i].display_name);
|
||||
}
|
||||
}
|
||||
|
||||
return p_name;
|
||||
}
|
||||
|
||||
const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
|
||||
// Return cache if it has already been built.
|
||||
if (default_builtin_cache.size()) {
|
||||
return default_builtin_cache;
|
||||
}
|
||||
|
||||
List<Ref<InputEvent>> inputs;
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::SPACE));
|
||||
default_builtin_cache.insert("ui_accept", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::Y));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::SPACE));
|
||||
default_builtin_cache.insert("ui_select", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
|
||||
default_builtin_cache.insert("ui_cancel", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::TAB));
|
||||
default_builtin_cache.insert("ui_focus_next", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_focus_prev", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::LEFT));
|
||||
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_LEFT));
|
||||
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, -1.0));
|
||||
default_builtin_cache.insert("ui_left", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
|
||||
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_RIGHT));
|
||||
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, 1.0));
|
||||
default_builtin_cache.insert("ui_right", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP));
|
||||
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_UP));
|
||||
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, -1.0));
|
||||
default_builtin_cache.insert("ui_up", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN));
|
||||
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_DOWN));
|
||||
inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, 1.0));
|
||||
default_builtin_cache.insert("ui_down", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
|
||||
default_builtin_cache.insert("ui_page_up", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
|
||||
default_builtin_cache.insert("ui_page_down", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::HOME));
|
||||
default_builtin_cache.insert("ui_home", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::END));
|
||||
default_builtin_cache.insert("ui_end", inputs);
|
||||
|
||||
// ///// UI basic Shortcuts /////
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::X | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_cut", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::C | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_copy", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_paste", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_undo", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::Y | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_redo", inputs);
|
||||
|
||||
// ///// UI Text Input Shortcuts /////
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::SPACE | KeyModifierMask::CTRL));
|
||||
default_builtin_cache.insert("ui_text_completion_query", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::TAB));
|
||||
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(KeyModifierMask::SHIFT | Key::KP_ENTER));
|
||||
default_builtin_cache.insert("ui_text_completion_accept", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::TAB));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||
default_builtin_cache.insert("ui_text_completion_replace", inputs);
|
||||
|
||||
// Newlines
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||
default_builtin_cache.insert("ui_text_newline", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_newline_blank", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_newline_above", inputs);
|
||||
|
||||
// Indentation
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::TAB));
|
||||
default_builtin_cache.insert("ui_text_indent", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_text_dedent", inputs);
|
||||
|
||||
// Text Backspace and Delete
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_text_backspace", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_backspace_word", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_backspace_word.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_backspace_all_to_left.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
|
||||
default_builtin_cache.insert("ui_text_delete", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_delete_word", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_delete_word.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_delete_all_to_right.macos", inputs);
|
||||
|
||||
// Text Caret Movement Left/Right
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::LEFT));
|
||||
default_builtin_cache.insert("ui_text_caret_left", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_word_left", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_caret_word_left.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
|
||||
default_builtin_cache.insert("ui_text_caret_right", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_word_right", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_caret_word_right.macos", inputs);
|
||||
|
||||
// Text Caret Movement Up/Down
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP));
|
||||
default_builtin_cache.insert("ui_text_caret_up", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN));
|
||||
default_builtin_cache.insert("ui_text_caret_down", inputs);
|
||||
|
||||
// Text Caret Movement Line Start/End
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::HOME));
|
||||
default_builtin_cache.insert("ui_text_caret_line_start", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::HOME));
|
||||
default_builtin_cache.insert("ui_text_caret_line_start.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::END));
|
||||
default_builtin_cache.insert("ui_text_caret_line_end", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::E | KeyModifierMask::CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::END));
|
||||
default_builtin_cache.insert("ui_text_caret_line_end.macos", inputs);
|
||||
|
||||
// Text Caret Movement Page Up/Down
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::PAGEUP));
|
||||
default_builtin_cache.insert("ui_text_caret_page_up", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::PAGEDOWN));
|
||||
default_builtin_cache.insert("ui_text_caret_page_down", inputs);
|
||||
|
||||
// Text Caret Movement Document Start/End
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_document_start", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_document_start.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_document_end", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
|
||||
|
||||
// Text Caret Addition Below/Above
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_add_below", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_add_above", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
|
||||
|
||||
// Text Scrolling
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_scroll_up", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_scroll_up.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_scroll_down", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_scroll_down.macos", inputs);
|
||||
|
||||
// Text Misc
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_select_all", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::CTRL | KeyModifierMask::META));
|
||||
default_builtin_cache.insert("ui_text_select_word_under_caret.macos", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
|
||||
default_builtin_cache.insert("ui_text_skip_selection_for_next_occurrence", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
|
||||
default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::INSERT));
|
||||
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::MENU));
|
||||
default_builtin_cache.insert("ui_menu", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::ENTER));
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||
default_builtin_cache.insert("ui_text_submit", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::U | KeyModifierMask::CTRL | KeyModifierMask::SHIFT));
|
||||
default_builtin_cache.insert("ui_unicode_start", inputs);
|
||||
|
||||
// ///// UI Graph Shortcuts /////
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_graph_duplicate", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
|
||||
default_builtin_cache.insert("ui_graph_delete", inputs);
|
||||
|
||||
// ///// UI File Dialog Shortcuts /////
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
|
||||
default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::F5));
|
||||
default_builtin_cache.insert("ui_filedialog_refresh", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::H));
|
||||
default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
|
||||
|
||||
inputs = List<Ref<InputEvent>>();
|
||||
inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
|
||||
default_builtin_cache.insert("ui_swap_input_direction", inputs);
|
||||
|
||||
return default_builtin_cache;
|
||||
}
|
||||
|
||||
const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_feature_overrides_applied() {
|
||||
if (default_builtin_with_overrides_cache.size() > 0) {
|
||||
return default_builtin_with_overrides_cache;
|
||||
}
|
||||
|
||||
const HashMap<String, List<Ref<InputEvent>>> &builtins = get_builtins();
|
||||
|
||||
// Get a list of all built in inputs which are valid overrides for the OS
|
||||
// Key = builtin name (e.g. ui_accept)
|
||||
// Value = override/feature names (e.g. macos, if it was defined as "ui_accept.macos" and the platform supports that feature)
|
||||
HashMap<String, Vector<String>> builtins_with_overrides;
|
||||
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
|
||||
String fullname = E.key;
|
||||
|
||||
Vector<String> split = fullname.split(".");
|
||||
const String &name = split[0];
|
||||
String override_for = split.size() > 1 ? split[1] : String();
|
||||
|
||||
if (!override_for.is_empty() && OS::get_singleton()->has_feature(override_for)) {
|
||||
builtins_with_overrides[name].push_back(override_for);
|
||||
}
|
||||
}
|
||||
|
||||
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
|
||||
String fullname = E.key;
|
||||
|
||||
Vector<String> split = fullname.split(".");
|
||||
const String &name = split[0];
|
||||
String override_for = split.size() > 1 ? split[1] : String();
|
||||
|
||||
if (builtins_with_overrides.has(name) && override_for.is_empty()) {
|
||||
// Builtin has an override but this particular one is not an override, so skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!override_for.is_empty() && !OS::get_singleton()->has_feature(override_for)) {
|
||||
// OS does not support this override - skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
default_builtin_with_overrides_cache.insert(name, E.value);
|
||||
}
|
||||
|
||||
return default_builtin_with_overrides_cache;
|
||||
}
|
||||
|
||||
void InputMap::load_default() {
|
||||
HashMap<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
|
||||
|
||||
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
|
||||
String name = E.key;
|
||||
|
||||
add_action(name);
|
||||
|
||||
const List<Ref<InputEvent>> &inputs = E.value;
|
||||
for (const List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
|
||||
Ref<InputEventKey> iek = I->get();
|
||||
|
||||
// For the editor, only add keyboard actions.
|
||||
if (iek.is_valid()) {
|
||||
action_add_event(name, I->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InputMap::InputMap() {
|
||||
ERR_FAIL_COND_MSG(singleton, "Singleton in InputMap already exist.");
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
InputMap::~InputMap() {
|
||||
singleton = nullptr;
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* input_map.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef INPUT_MAP_H
|
||||
#define INPUT_MAP_H
|
||||
|
||||
#include "core/input/input_event.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
|
||||
template <typename T>
|
||||
class TypedArray;
|
||||
|
||||
class InputMap : public Object {
|
||||
GDCLASS(InputMap, Object);
|
||||
|
||||
public:
|
||||
/**
|
||||
* A special value used to signify that a given Action can be triggered by any device
|
||||
*/
|
||||
static int ALL_DEVICES;
|
||||
|
||||
struct Action {
|
||||
int id;
|
||||
float deadzone;
|
||||
List<Ref<InputEvent>> inputs;
|
||||
};
|
||||
|
||||
static constexpr float DEFAULT_DEADZONE = 0.2f;
|
||||
// Keep bigger deadzone for toggle actions (default `ui_*` actions, axis `pressed`) (GH-103360).
|
||||
static constexpr float DEFAULT_TOGGLE_DEADZONE = 0.5f;
|
||||
|
||||
private:
|
||||
static InputMap *singleton;
|
||||
|
||||
mutable HashMap<StringName, Action> input_map;
|
||||
HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
|
||||
HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
|
||||
|
||||
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
|
||||
|
||||
TypedArray<InputEvent> _action_get_events(const StringName &p_action);
|
||||
TypedArray<StringName> _get_actions();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _add_action_bind_compat_97281(const StringName &p_action, float p_deadzone = 0.5);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
public:
|
||||
static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
|
||||
|
||||
bool has_action(const StringName &p_action) const;
|
||||
List<StringName> get_actions() const;
|
||||
void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE);
|
||||
void erase_action(const StringName &p_action);
|
||||
|
||||
float action_get_deadzone(const StringName &p_action);
|
||||
void action_set_deadzone(const StringName &p_action, float p_deadzone);
|
||||
void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
|
||||
bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
|
||||
void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
|
||||
void action_erase_events(const StringName &p_action);
|
||||
|
||||
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
|
||||
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
|
||||
int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
|
||||
bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
|
||||
|
||||
const HashMap<StringName, Action> &get_action_map() const;
|
||||
void load_from_project_settings();
|
||||
void load_default();
|
||||
|
||||
String suggest_actions(const StringName &p_action) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
String get_builtin_display_name(const String &p_name) const;
|
||||
// Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat.
|
||||
const HashMap<String, List<Ref<InputEvent>>> &get_builtins();
|
||||
const HashMap<String, List<Ref<InputEvent>>> &get_builtins_with_feature_overrides_applied();
|
||||
|
||||
InputMap();
|
||||
~InputMap();
|
||||
};
|
||||
|
||||
#endif // INPUT_MAP_H
|
|
@ -1,131 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* shortcut.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "shortcut.h"
|
||||
|
||||
void Shortcut::set_events(const Array &p_events) {
|
||||
for (int i = 0; i < p_events.size(); i++) {
|
||||
Ref<InputEventShortcut> ies = p_events[i];
|
||||
ERR_FAIL_COND_MSG(ies.is_valid(), "Cannot set a shortcut event to an instance of InputEventShortcut.");
|
||||
}
|
||||
|
||||
events = p_events;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void Shortcut::set_events_list(const List<Ref<InputEvent>> *p_events) {
|
||||
events.clear();
|
||||
|
||||
for (const Ref<InputEvent> &ie : *p_events) {
|
||||
events.push_back(ie);
|
||||
}
|
||||
}
|
||||
|
||||
Array Shortcut::get_events() const {
|
||||
return events;
|
||||
}
|
||||
|
||||
bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
|
||||
Ref<InputEventShortcut> ies = p_event;
|
||||
if (ies.is_valid()) {
|
||||
if (ies->get_shortcut().ptr() == this) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Ref<InputEvent> ie = events[i];
|
||||
bool valid = ie.is_valid() && ie->is_match(p_event);
|
||||
|
||||
// Stop on first valid event - don't need to check further.
|
||||
if (valid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String Shortcut::get_as_text() const {
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Ref<InputEvent> ie = events[i];
|
||||
// Return first shortcut which is valid
|
||||
if (ie.is_valid()) {
|
||||
return ie->as_text();
|
||||
}
|
||||
}
|
||||
|
||||
return "None";
|
||||
}
|
||||
|
||||
bool Shortcut::has_valid_event() const {
|
||||
// Tests if there is ANY input event which is valid.
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Ref<InputEvent> ie = events[i];
|
||||
if (ie.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Shortcut::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_events", "events"), &Shortcut::set_events);
|
||||
ClassDB::bind_method(D_METHOD("get_events"), &Shortcut::get_events);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
|
||||
ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("InputEvent")), "set_events", "get_events");
|
||||
}
|
||||
|
||||
bool Shortcut::is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2) {
|
||||
if (p_event_array1.size() != p_event_array2.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_same = true;
|
||||
for (int i = 0; i < p_event_array1.size(); i++) {
|
||||
Ref<InputEvent> ie_1 = p_event_array1[i];
|
||||
Ref<InputEvent> ie_2 = p_event_array2[i];
|
||||
|
||||
is_same = ie_1->is_match(ie_2);
|
||||
|
||||
// Break on the first that doesn't match - don't need to check further.
|
||||
if (!is_same) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return is_same;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue