├── .clang-format ├── .clang-tidy ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── android_builds.yml │ ├── get_version.yml │ ├── ios_builds.yml │ ├── linux_builds.yml │ ├── macos_builds.yml │ ├── release_builds.yml │ ├── runner.yml │ ├── static_checks.yml │ ├── web_builds.yml │ └── windows_builds.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SCsub ├── clang_format.sh ├── config.py ├── doc └── class.xsd ├── doc_classes ├── JavaScript.xml └── JavaScriptModule.xml ├── docs ├── JavaScript.svg.licence ├── header-mobile.svg └── header.svg ├── editor ├── editor_tools.cpp ├── editor_tools.h └── workarounds │ ├── ignore-methods.cpp │ ├── missing-constructors.cpp │ └── missing-enums.cpp ├── generate_builtin_api.py ├── icons ├── JavaScript.svg └── JavaScriptModule.svg ├── javascript.cpp ├── javascript.h ├── javascript_binder.h ├── javascript_callable.h ├── javascript_gc_handler.h ├── javascript_instance.cpp ├── javascript_instance.h ├── misc ├── binding_script.js ├── generate │ ├── bindings.py │ ├── editor_tools.py │ ├── generate_files.py │ ├── templates.py │ └── test_manager.py ├── template-contents │ ├── default.js │ └── empty.js └── typescript │ ├── decorators.ts │ └── godot.d.ts ├── register_types.cpp ├── register_types.h ├── src ├── language │ ├── README.md │ ├── javascript_instance_binding_callbacks.cpp │ ├── javascript_language.cpp │ ├── javascript_language.h │ ├── javascript_language_definitions.cpp │ ├── javascript_templates.cpp │ ├── javascript_todo_debugger.cpp │ ├── javascript_todo_doctools.cpp │ ├── javascript_todo_multithread.cpp │ ├── javascript_todo_profiling.cpp │ ├── javascript_todo_texteditor.cpp │ └── templates │ │ ├── javascript_template_manager.cpp │ │ └── javascript_template_manager.h └── tests │ ├── UnitTest.js │ └── test_manager.h ├── tests └── test_javascript.h └── thirdparty └── quickjs ├── README.md ├── builtin_binding_generator.py ├── quickjs ├── VERSION.txt ├── cutils.c ├── cutils.h ├── libbf.c ├── libbf.h ├── libregexp-opcode.h ├── libregexp.c ├── libregexp.h ├── libunicode-table.h ├── libunicode.c ├── libunicode.h ├── list.h ├── quickjs-atom.h ├── quickjs-debugger.c ├── quickjs-debugger.h ├── quickjs-opcode.h ├── quickjs.c └── quickjs.h ├── quickjs_binder.cpp ├── quickjs_binder.h ├── quickjs_builtin_binder.cpp ├── quickjs_builtin_binder.h ├── quickjs_callable.cpp ├── quickjs_callable.h ├── quickjs_debugger.cpp ├── quickjs_debugger.h ├── quickjs_worker.cpp └── quickjs_worker.h /.clang-format: -------------------------------------------------------------------------------- 1 | # Commented out parameters are those with the same value as base LLVM style. 2 | # We can uncomment them if we want to change their value, or enforce the 3 | # chosen value in case the base style changes (last sync: Clang 14.0). 4 | --- 5 | ### General config, applies to all languages ### 6 | BasedOnStyle: LLVM 7 | AccessModifierOffset: -4 8 | AlignAfterOpenBracket: DontAlign 9 | # AlignArrayOfStructures: None 10 | # AlignConsecutiveMacros: None 11 | # AlignConsecutiveAssignments: None 12 | # AlignConsecutiveBitFields: None 13 | # AlignConsecutiveDeclarations: None 14 | # AlignEscapedNewlines: Right 15 | AlignOperands: DontAlign 16 | AlignTrailingComments: false 17 | # AllowAllArgumentsOnNextLine: true 18 | AllowAllParametersOfDeclarationOnNextLine: false 19 | # AllowShortEnumsOnASingleLine: true 20 | # AllowShortBlocksOnASingleLine: Never 21 | # AllowShortCaseLabelsOnASingleLine: false 22 | # AllowShortFunctionsOnASingleLine: All 23 | # AllowShortLambdasOnASingleLine: All 24 | # AllowShortIfStatementsOnASingleLine: Never 25 | # AllowShortLoopsOnASingleLine: false 26 | # AlwaysBreakAfterDefinitionReturnType: None 27 | # AlwaysBreakAfterReturnType: None 28 | # AlwaysBreakBeforeMultilineStrings: false 29 | # AlwaysBreakTemplateDeclarations: MultiLine 30 | # AttributeMacros: 31 | # - __capability 32 | # BinPackArguments: true 33 | # BinPackParameters: true 34 | # BraceWrapping: 35 | # AfterCaseLabel: false 36 | # AfterClass: false 37 | # AfterControlStatement: Never 38 | # AfterEnum: false 39 | # AfterFunction: false 40 | # AfterNamespace: false 41 | # AfterObjCDeclaration: false 42 | # AfterStruct: false 43 | # AfterUnion: false 44 | # AfterExternBlock: false 45 | # BeforeCatch: false 46 | # BeforeElse: false 47 | # BeforeLambdaBody: false 48 | # BeforeWhile: false 49 | # IndentBraces: false 50 | # SplitEmptyFunction: true 51 | # SplitEmptyRecord: true 52 | # SplitEmptyNamespace: true 53 | # BreakBeforeBinaryOperators: None 54 | # BreakBeforeConceptDeclarations: true 55 | # BreakBeforeBraces: Attach 56 | # BreakBeforeInheritanceComma: false 57 | # BreakInheritanceList: BeforeColon 58 | # BreakBeforeTernaryOperators: true 59 | # BreakConstructorInitializersBeforeComma: false 60 | BreakConstructorInitializers: AfterColon 61 | # BreakStringLiterals: true 62 | ColumnLimit: 0 63 | # CommentPragmas: '^ IWYU pragma:' 64 | # QualifierAlignment: Leave 65 | # CompactNamespaces: false 66 | ConstructorInitializerIndentWidth: 8 67 | ContinuationIndentWidth: 8 68 | Cpp11BracedListStyle: false 69 | # DeriveLineEnding: true 70 | # DerivePointerAlignment: false 71 | # DisableFormat: false 72 | # EmptyLineAfterAccessModifier: Never 73 | # EmptyLineBeforeAccessModifier: LogicalBlock 74 | # ExperimentalAutoDetectBinPacking: false 75 | # PackConstructorInitializers: BinPack 76 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 77 | # AllowAllConstructorInitializersOnNextLine: true 78 | # FixNamespaceComments: true 79 | # ForEachMacros: 80 | # - foreach 81 | # - Q_FOREACH 82 | # - BOOST_FOREACH 83 | # IfMacros: 84 | # - KJ_IF_MAYBE 85 | # IncludeBlocks: Preserve 86 | IncludeCategories: 87 | - Regex: '".*"' 88 | Priority: 1 89 | - Regex: '^<.*\.h>' 90 | Priority: 2 91 | - Regex: '^<.*' 92 | Priority: 3 93 | # IncludeIsMainRegex: '(Test)?$' 94 | # IncludeIsMainSourceRegex: '' 95 | # IndentAccessModifiers: false 96 | IndentCaseLabels: true 97 | # IndentCaseBlocks: false 98 | # IndentGotoLabels: true 99 | # IndentPPDirectives: None 100 | # IndentExternBlock: AfterExternBlock 101 | # IndentRequires: false 102 | IndentWidth: 4 103 | # IndentWrappedFunctionNames: false 104 | # InsertTrailingCommas: None 105 | # JavaScriptQuotes: Leave 106 | # JavaScriptWrapImports: true 107 | KeepEmptyLinesAtTheStartOfBlocks: false 108 | # LambdaBodyIndentation: Signature 109 | # MacroBlockBegin: '' 110 | # MacroBlockEnd: '' 111 | # MaxEmptyLinesToKeep: 1 112 | # NamespaceIndentation: None 113 | # PenaltyBreakAssignment: 2 114 | # PenaltyBreakBeforeFirstCallParameter: 19 115 | # PenaltyBreakComment: 300 116 | # PenaltyBreakFirstLessLess: 120 117 | # PenaltyBreakOpenParenthesis: 0 118 | # PenaltyBreakString: 1000 119 | # PenaltyBreakTemplateDeclaration: 10 120 | # PenaltyExcessCharacter: 1000000 121 | # PenaltyReturnTypeOnItsOwnLine: 60 122 | # PenaltyIndentedWhitespace: 0 123 | # PointerAlignment: Right 124 | # PPIndentWidth: -1 125 | # ReferenceAlignment: Pointer 126 | # ReflowComments: true 127 | # RemoveBracesLLVM: false 128 | # SeparateDefinitionBlocks: Leave 129 | # ShortNamespaceLines: 1 130 | # SortIncludes: CaseSensitive 131 | # SortJavaStaticImport: Before 132 | # SortUsingDeclarations: true 133 | # SpaceAfterCStyleCast: false 134 | # SpaceAfterLogicalNot: false 135 | # SpaceAfterTemplateKeyword: true 136 | # SpaceBeforeAssignmentOperators: true 137 | # SpaceBeforeCaseColon: false 138 | # SpaceBeforeCpp11BracedList: false 139 | # SpaceBeforeCtorInitializerColon: true 140 | # SpaceBeforeInheritanceColon: true 141 | # SpaceBeforeParens: ControlStatements 142 | # SpaceBeforeParensOptions: 143 | # AfterControlStatements: true 144 | # AfterForeachMacros: true 145 | # AfterFunctionDefinitionName: false 146 | # AfterFunctionDeclarationName: false 147 | # AfterIfMacros: true 148 | # AfterOverloadedOperator: false 149 | # BeforeNonEmptyParentheses: false 150 | # SpaceAroundPointerQualifiers: Default 151 | # SpaceBeforeRangeBasedForLoopColon: true 152 | # SpaceInEmptyBlock: false 153 | # SpaceInEmptyParentheses: false 154 | # SpacesBeforeTrailingComments: 1 155 | # SpacesInAngles: Never 156 | # SpacesInConditionalStatement: false 157 | # SpacesInContainerLiterals: true 158 | # SpacesInCStyleCastParentheses: false 159 | ## Godot TODO: We'll want to use a min of 1, but we need to see how to fix 160 | ## our comment capitalization at the same time. 161 | SpacesInLineCommentPrefix: 162 | Minimum: 0 163 | Maximum: -1 164 | # SpacesInParentheses: false 165 | # SpacesInSquareBrackets: false 166 | # SpaceBeforeSquareBrackets: false 167 | # BitFieldColonSpacing: Both 168 | # StatementAttributeLikeMacros: 169 | # - Q_EMIT 170 | # StatementMacros: 171 | # - Q_UNUSED 172 | # - QT_REQUIRE_VERSION 173 | TabWidth: 4 174 | # UseCRLF: false 175 | UseTab: Always 176 | # WhitespaceSensitiveMacros: 177 | # - STRINGIZE 178 | # - PP_STRINGIZE 179 | # - BOOST_PP_STRINGIZE 180 | # - NS_SWIFT_NAME 181 | # - CF_SWIFT_NAME 182 | --- 183 | ### C++ specific config ### 184 | Language: Cpp 185 | Standard: c++17 186 | --- 187 | ### ObjC specific config ### 188 | Language: ObjC 189 | # ObjCBinPackProtocolList: Auto 190 | ObjCBlockIndentWidth: 4 191 | # ObjCBreakBeforeNestedBlockParam: true 192 | # ObjCSpaceAfterProperty: false 193 | # ObjCSpaceBeforeProtocolList: true 194 | --- 195 | ### Java specific config ### 196 | Language: Java 197 | # BreakAfterJavaFieldAnnotations: false 198 | JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax'] 199 | ... 200 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,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' 3 | WarningsAsErrors: '' 4 | HeaderFilterRegex: '' 5 | AnalyzeTemporaryDtors: false 6 | FormatStyle: none 7 | CheckOptions: 8 | - key: cert-dcl16-c.NewSuffixes 9 | value: 'L;LL;LU;LLU' 10 | - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField 11 | value: '0' 12 | - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors 13 | value: '1' 14 | - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic 15 | value: '1' 16 | - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays 17 | value: '1' 18 | - key: cppcoreguidelines-pro-type-member-init.UseAssignment 19 | value: '1' 20 | - key: google-readability-function-size.StatementThreshold 21 | value: '800' 22 | - key: google-readability-namespace-comments.ShortNamespaceLines 23 | value: '10' 24 | - key: google-readability-namespace-comments.SpacesBeforeComments 25 | value: '2' 26 | - key: modernize-loop-convert.MaxCopySize 27 | value: '16' 28 | - key: modernize-loop-convert.MinConfidence 29 | value: reasonable 30 | - key: modernize-loop-convert.NamingStyle 31 | value: CamelCase 32 | - key: modernize-pass-by-value.IncludeStyle 33 | value: llvm 34 | - key: modernize-replace-auto-ptr.IncludeStyle 35 | value: llvm 36 | - key: modernize-use-bool-literals.IgnoreMacros 37 | value: '0' 38 | - key: modernize-use-default-member-init.IgnoreMacros 39 | value: '0' 40 | - key: modernize-use-default-member-init.UseAssignment 41 | value: '1' 42 | - key: modernize-use-nullptr.NullMacros 43 | value: 'NULL' 44 | - key: readability-braces-around-statements.ShortStatementLines 45 | value: '0' 46 | ... 47 | 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Report a bug in GodotJS 3 | body: 4 | 5 | - type: markdown 6 | attributes: 7 | value: | 8 | When reporting bugs, please follow the guidelines in this template. This helps identify the problem precisely and thus enables contributors to fix it faster. 9 | - Write a descriptive issue title above. 10 | - The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them. 11 | - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate. 12 | - Verify that you are using a [supported Godot version](https://github.com/godotjs/javascript/releases). Please always check if your issue is reproducible in the latest version – it may already have been fixed! 13 | 14 | - type: input 15 | attributes: 16 | label: Version 17 | description: > 18 | Specify the Godot version, including the Git commit hash if using a development or non-official build. The exact Godot version (including the commit hash) can be copied by clicking the version shown in the editor (bottom bar) or in the project manager (top bar). 19 | placeholder: 4.1-v0.0.17-alpha-20231003 20 | validations: 21 | required: true 22 | 23 | - type: input 24 | attributes: 25 | label: System information 26 | description: | 27 | - Specify the OS version, and when relevant hardware information. 28 | - For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture. 29 | - For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan). 30 | - **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information. 31 | - **Starting from Godot 4.1, you can copy this information to your clipboard by using *Help > Copy System Info* at the top of the editor window.** 32 | placeholder: Windows 10 - Godot v4.0.3.stable - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 970 (nvidia, 510.85.02) - Intel Core i7-10700KF CPU @ 3.80GHz (16 Threads) 33 | validations: 34 | required: true 35 | 36 | - type: textarea 37 | attributes: 38 | label: Issue description 39 | description: | 40 | Describe your issue briefly. What doesn't work, and how do you expect it to work instead? 41 | You can include images or videos with drag and drop, and format code blocks or logs with \`\`\` tags, on separate lines before and after the text. (Use \`\`\`gdscript to add GDScript syntax highlighting.) 42 | Please do not add code examples or error messages as screenshots, but as text, this helps searching for issues and testing the code. If you are reporting a bug in the editor interface, like the script editor, please provide both a screenshot *and* the text of the code to help with testing. 43 | validations: 44 | required: true 45 | 46 | - type: textarea 47 | attributes: 48 | label: Steps to reproduce 49 | description: | 50 | List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them. 51 | If you include a minimal reproduction project below, you can detail how to use it here. 52 | validations: 53 | required: true 54 | 55 | - type: textarea 56 | attributes: 57 | label: Minimal reproduction project (MRP) 58 | description: | 59 | - A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`). 60 | - Having an MRP is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRP to validate that the fix is working as intended. 61 | - If the reproduction steps are not project dependent (e.g. the bug is visible in a brand new project), you can write "N/A" in the field. 62 | - Drag and drop a ZIP archive to upload it (max 10 MB). **Do not select another field until the project is done uploading.** 63 | validations: 64 | required: true 65 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | Make sure to follow the PR preparation steps in [CONTRIBUTING.md](https://github.com/godotjs/javascript/blob/master/CONTRIBUTING.md#preparing-your-pr) before submitting your PR: 6 | 7 | - [ ] format C++: from the root, run `bash ./misc/formatting/clang_format.sh`. 8 | -------------------------------------------------------------------------------- /.github/workflows/android_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 Android Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | # Global Settings 10 | env: 11 | SCONSFLAGS: warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes 12 | 13 | concurrency: 14 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-android 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | android-template: 19 | runs-on: "ubuntu-20.04" 20 | name: Template (target=template_release) 21 | 22 | steps: 23 | - name: Checkout Godot 24 | uses: actions/checkout@v4 25 | with: 26 | repository: godotengine/godot 27 | ref: ${{ inputs.version }} 28 | 29 | - name: Checkout ECMAScript 30 | uses: actions/checkout@v4 31 | with: 32 | path: ${{github.workspace}}/modules/javascript/ 33 | 34 | - name: Set up Java 11 35 | uses: actions/setup-java@v3 36 | with: 37 | distribution: temurin 38 | java-version: 11 39 | 40 | - name: Setup Godot build cache 41 | uses: ./.github/actions/godot-cache 42 | continue-on-error: true 43 | 44 | - name: Setup python and scons 45 | uses: ./.github/actions/godot-deps 46 | 47 | - name: Compilation (arm32) 48 | uses: ./.github/actions/godot-build 49 | with: 50 | sconsflags: ${{ env.SCONSFLAGS }} arch=arm32 51 | platform: android 52 | target: template_release 53 | tests: false 54 | 55 | - name: Compilation (arm64) 56 | uses: ./.github/actions/godot-build 57 | with: 58 | sconsflags: ${{ env.SCONSFLAGS }} arch=arm64 59 | platform: android 60 | target: template_release 61 | tests: false 62 | 63 | - name: Generate Godot templates 64 | run: | 65 | cd platform/android/java 66 | ./gradlew generateGodotTemplates 67 | cd ../../.. 68 | ls -l bin/ 69 | 70 | - name: Upload artifact 71 | uses: ./.github/actions/upload-artifact 72 | -------------------------------------------------------------------------------- /.github/workflows/get_version.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🆚 Get godot version 3 | 4 | on: 5 | workflow_call: 6 | outputs: 7 | version: 8 | description: "Which version we should use based on target branch" 9 | value: ${{ jobs.version.outputs.version }} 10 | 11 | # We use a godot tag(rc version) as default version for master 12 | # because the api is changing often and this would lead to a lot of struggle 13 | env: 14 | MASTER_VERSION: 4.1 15 | 16 | jobs: 17 | version: 18 | name: Get godot version 19 | runs-on: ubuntu-latest 20 | outputs: 21 | version: ${{ steps.version.outputs.version }} 22 | steps: 23 | - name: 🏷 Get and set godot version 24 | id: version 25 | run: | 26 | VERSION="${{ github.event.pull_request.base.ref || github.event.release.target_commitish || github.ref_name }}" 27 | if [[ $VERSION == "master" ]]; then 28 | VERSION="$MASTER_VERSION" 29 | echo "We are overwrite master to latest rc version: $VERSION" 30 | fi 31 | echo "version=$VERSION" >> $GITHUB_OUTPUT 32 | 33 | - name: 🌳 Log Valid Version 34 | env: 35 | VERSION: ${{ steps.version.outputs.version }} 36 | run: echo "$VERSION" 37 | -------------------------------------------------------------------------------- /.github/workflows/ios_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🍏 iOS Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | # Global Settings 10 | env: 11 | SCONSFLAGS: warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes 12 | 13 | concurrency: 14 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-ios 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | ios-template: 19 | runs-on: "macos-latest" 20 | name: Template (target=template_release) 21 | 22 | steps: 23 | - name: Checkout Godot 24 | uses: actions/checkout@v4 25 | with: 26 | repository: godotengine/godot 27 | ref: ${{ inputs.version }} 28 | 29 | - name: Checkout ECMAScript 30 | uses: actions/checkout@v4 31 | with: 32 | path: ${{github.workspace}}/modules/javascript/ 33 | 34 | - name: Setup Godot build cache 35 | uses: ./.github/actions/godot-cache 36 | continue-on-error: true 37 | 38 | - name: Setup python and scons 39 | uses: ./.github/actions/godot-deps 40 | 41 | - name: Compilation (arm64) 42 | uses: ./.github/actions/godot-build 43 | with: 44 | sconsflags: ${{ env.SCONSFLAGS }} 45 | platform: ios 46 | target: template_release 47 | tests: false 48 | 49 | - name: Upload artifact 50 | uses: ./.github/actions/upload-artifact 51 | -------------------------------------------------------------------------------- /.github/workflows/linux_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🐧 Linux Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | 10 | # Global Settings 11 | env: 12 | # We need to remove 'werror=yes' because of thirdparty/quickjs/quickjs/quickjs.h:975 13 | # Look at https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type for more information 14 | SCONSFLAGS: warnings=extra module_text_server_fb_enabled=yes 15 | DOTNET_NOLOGO: true 16 | DOTNET_CLI_TELEMETRY_OPTOUT: true 17 | 18 | concurrency: 19 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-linux 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | build-linux: 24 | runs-on: "ubuntu-20.04" 25 | name: ${{ matrix.name }} 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | include: 30 | - name: Editor w/ Mono (target=editor) 31 | cache-name: linux-editor-mono 32 | target: editor 33 | tests: false # Disabled due freeze caused by mix Mono build and CI 34 | sconsflags: module_mono_enabled=yes 35 | doc-test: true 36 | bin: "./bin/godot.linuxbsd.editor.x86_64.mono" 37 | build-mono: true 38 | proj-conv: true 39 | artifact: true 40 | 41 | # Removed dev-builds (https://github.com/godotengine/godot/blob/master/.github/workflows/linux_builds.yml#L38) 42 | # TODO: There was an issue with quickjs debugger, maybe this can be enabled again after fixing the debugger 43 | 44 | - name: Template w/ Mono (target=template_release) 45 | cache-name: linux-template-mono 46 | target: template_release 47 | tests: false 48 | sconsflags: module_mono_enabled=yes 49 | build-mono: false 50 | artifact: true 51 | 52 | - name: Minimal template (target=template_release, everything disabled) 53 | cache-name: linux-template-minimal 54 | target: template_release 55 | tests: false 56 | sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no 57 | artifact: true 58 | 59 | steps: 60 | - name: Checkout Godot 61 | uses: actions/checkout@v4 62 | with: 63 | repository: godotengine/godot 64 | ref: ${{ inputs.version }} 65 | 66 | - name: Checkout ECMAScript 67 | uses: actions/checkout@v4 68 | with: 69 | path: ${{github.workspace}}/modules/javascript/ 70 | 71 | # Need newer mesa for lavapipe to work properly. 72 | - name: Linux dependencies for tests 73 | if: ${{ matrix.proj-test }} 74 | run: | 75 | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list 76 | sudo add-apt-repository ppa:kisak/kisak-mesa 77 | sudo apt-get install -qq mesa-vulkan-drivers 78 | 79 | - name: Setup Godot build cache 80 | uses: ./.github/actions/godot-cache 81 | with: 82 | cache-name: ${{ matrix.cache-name }} 83 | continue-on-error: true 84 | 85 | - name: Setup python and scons 86 | uses: ./.github/actions/godot-deps 87 | 88 | - name: Set up .NET Sdk 89 | uses: actions/setup-dotnet@v2 90 | if: ${{ matrix.build-mono }} 91 | with: 92 | dotnet-version: '6.0.x' 93 | 94 | - name: Setup GCC problem matcher 95 | uses: ammaraskar/gcc-problem-matcher@master 96 | 97 | - name: Compilation 98 | uses: ./.github/actions/godot-build 99 | with: 100 | sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} 101 | platform: linuxbsd 102 | target: ${{ matrix.target }} 103 | tests: ${{ matrix.tests }} 104 | 105 | - name: Generate C# glue 106 | if: ${{ matrix.build-mono }} 107 | run: | 108 | ${{ matrix.bin }} --headless --generate-mono-glue ./modules/mono/glue || true 109 | 110 | - name: Build .NET solutions 111 | if: ${{ matrix.build-mono }} 112 | run: | 113 | ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd 114 | 115 | # Execute unit tests for the editor 116 | - name: Unit tests 117 | if: ${{ matrix.tests }} 118 | run: | 119 | ${{ matrix.bin }} --version 120 | ${{ matrix.bin }} --help 121 | ${{ matrix.bin }} --test --headless 122 | 123 | # Check class reference 124 | - name: Check for class reference updates 125 | if: ${{ matrix.doc-test }} 126 | run: | 127 | echo "Running --doctool to see if this changes the public API without updating the documentation." 128 | echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n" 129 | ${{ matrix.bin }} --doctool --headless 2>&1 > /dev/null || true 130 | git diff --color --exit-code && ! git ls-files --others --exclude-standard | sed -e 's/^/New doc file missing in PR: /' | grep 'xml$' 131 | 132 | # Test 3.x -> 4.x project converter 133 | - name: Test project converter 134 | if: ${{ matrix.proj-conv }} 135 | run: | 136 | mkdir converter_test 137 | cd converter_test 138 | touch project.godot 139 | ../${{ matrix.bin }} --headless --validate-conversion-3to4 140 | cd .. 141 | rm converter_test -rf 142 | 143 | # Download and extract zip archive with project, folder is renamed to be able to easy change used project 144 | - name: Download test project 145 | if: ${{ matrix.proj-test }} 146 | run: | 147 | wget https://github.com/godotengine/regression-test-project/archive/4.0.zip 148 | unzip 4.0.zip 149 | mv "regression-test-project-4.0" "test_project" 150 | 151 | # Editor is quite complicated piece of software, so it is easy to introduce bug here 152 | - name: Open and close editor (Vulkan) 153 | if: ${{ matrix.proj-test }} 154 | run: | 155 | xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true 156 | misc/scripts/check_ci_log.py sanitizers_log.txt 157 | 158 | - name: Open and close editor (GLES3) 159 | if: ${{ matrix.proj-test }} 160 | run: | 161 | DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --rendering-driver opengl3 --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true 162 | misc/scripts/check_ci_log.py sanitizers_log.txt 163 | 164 | # Run test project 165 | - name: Run project 166 | if: ${{ matrix.proj-test }} 167 | run: | 168 | xvfb-run ${{ matrix.bin }} 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true 169 | misc/scripts/check_ci_log.py sanitizers_log.txt 170 | 171 | # Checkout godot-cpp 172 | - name: Checkout godot-cpp 173 | if: ${{ matrix.godot-cpp-test }} 174 | uses: actions/checkout@v3 175 | with: 176 | repository: godotengine/godot-cpp 177 | ref: ${{ inputs.version }} 178 | submodules: 'recursive' 179 | path: 'godot-cpp' 180 | 181 | # Dump GDExtension interface and API 182 | - name: Dump GDExtension interface and API for godot-cpp build 183 | if: ${{ matrix.godot-cpp-test }} 184 | run: | 185 | ${{ matrix.bin }} --headless --dump-gdextension-interface --dump-extension-api 186 | cp -f gdextension_interface.h godot-cpp/gdextension/ 187 | cp -f extension_api.json godot-cpp/gdextension/ 188 | 189 | # Build godot-cpp test extension 190 | - name: Build godot-cpp test extension 191 | if: ${{ matrix.godot-cpp-test }} 192 | run: | 193 | cd godot-cpp/test 194 | scons target=template_debug dev_build=yes 195 | cd ../.. 196 | 197 | - name: Prepare artifact 198 | if: ${{ matrix.artifact }} 199 | run: | 200 | strip bin/godot.* 201 | chmod +x bin/godot.* 202 | 203 | - name: Upload artifact 204 | uses: ./.github/actions/upload-artifact 205 | if: ${{ matrix.artifact }} 206 | with: 207 | name: ${{ matrix.cache-name }} 208 | -------------------------------------------------------------------------------- /.github/workflows/macos_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🍎 macOS Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | 10 | # Global Settings 11 | env: 12 | SCONSFLAGS: warnings=extra werror=yes module_text_server_fb_enabled=yes 13 | 14 | concurrency: 15 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-macos 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | build-macos: 20 | runs-on: "macos-latest" 21 | name: ${{ matrix.name }} 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | include: 26 | - name: Editor (target=editor, tests=yes) 27 | cache-name: macos-editor 28 | target: editor 29 | tests: true 30 | bin: "./bin/godot.macos.editor.universal" 31 | 32 | - name: Template (target=template_release) 33 | cache-name: macos-template 34 | target: template_release 35 | tests: false 36 | sconsflags: debug_symbols=no 37 | 38 | steps: 39 | - name: Checkout Godot 40 | uses: actions/checkout@v4 41 | with: 42 | repository: godotengine/godot 43 | ref: ${{ inputs.version }} 44 | 45 | - name: Checkout ECMAScript 46 | uses: actions/checkout@v4 47 | with: 48 | path: ${{github.workspace}}/modules/javascript/ 49 | 50 | - name: Setup Godot build cache 51 | uses: ./.github/actions/godot-cache 52 | with: 53 | cache-name: ${{ matrix.cache-name }} 54 | continue-on-error: true 55 | 56 | - name: Setup python and scons 57 | uses: ./.github/actions/godot-deps 58 | 59 | - name: Setup Vulkan SDK 60 | run: | 61 | sh misc/scripts/install_vulkan_sdk_macos.sh 62 | 63 | - name: Compilation (x86_64) 64 | uses: ./.github/actions/godot-build 65 | with: 66 | sconsflags: ${{ env.SCONSFLAGS }} arch=x86_64 67 | platform: macos 68 | target: ${{ matrix.target }} 69 | tests: ${{ matrix.tests }} 70 | 71 | - name: Compilation (arm64) 72 | uses: ./.github/actions/godot-build 73 | with: 74 | sconsflags: ${{ env.SCONSFLAGS }} arch=arm64 75 | platform: macos 76 | target: ${{ matrix.target }} 77 | tests: ${{ matrix.tests }} 78 | 79 | - name: Prepare artifact 80 | run: | 81 | lipo -create ./bin/godot.macos.${{ matrix.target }}.x86_64 ./bin/godot.macos.${{ matrix.target }}.arm64 -output ./bin/godot.macos.${{ matrix.target }}.universal 82 | rm ./bin/godot.macos.${{ matrix.target }}.x86_64 ./bin/godot.macos.${{ matrix.target }}.arm64 83 | strip bin/godot.* 84 | chmod +x bin/godot.* 85 | 86 | - name: Upload artifact 87 | uses: ./.github/actions/upload-artifact 88 | with: 89 | name: ${{ matrix.cache-name }} 90 | 91 | # Execute unit tests for the editor 92 | - name: Unit tests 93 | if: ${{ matrix.tests }} 94 | run: | 95 | ${{ matrix.bin }} --version 96 | ${{ matrix.bin }} --help 97 | ${{ matrix.bin }} --test --force-colors 98 | -------------------------------------------------------------------------------- /.github/workflows/release_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🦅 Release Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | concurrency: 10 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-android 11 | cancel-in-progress: true 12 | 13 | permissions: 14 | contents: write 15 | 16 | jobs: 17 | rename: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: ⏬ Checkout repo 21 | uses: actions/checkout@v4 22 | 23 | - name: 📛 Add version to release name 24 | uses: actions/github-script@v6 25 | with: 26 | result-encoding: json 27 | script: | 28 | const { repo, owner } = context.repo; 29 | const date = new Date(); 30 | const year = date.getFullYear().toString(); 31 | const month = (date.getMonth() + 1).toString().padStart(2,"0"); 32 | const day = (date.getDay() + 1).toString().padStart(2,"0"); 33 | await github.rest.repos.updateRelease({ 34 | owner, 35 | repo, 36 | release_id: context.payload.release.id, 37 | name: '${{ inputs.version }}-' + context.payload.release.name + '-' + year + month + day, 38 | }); 39 | 40 | release: 41 | runs-on: ubuntu-latest 42 | name: ${{ matrix.name }} 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | name: 47 | - android-template 48 | - ios-template 49 | - linux-editor-mono 50 | - linux-template-minimal 51 | - linux-template-mono 52 | - macos-editor 53 | - macos-template 54 | - web-template 55 | - windows-editor 56 | - windows-template 57 | steps: 58 | - name: ⏬ Checkout repo 59 | uses: actions/checkout@v4 60 | 61 | - name: ⏬ Download build 62 | uses: actions/download-artifact@v4 63 | with: 64 | name: ${{ matrix.name }} 65 | path: ${{ matrix.name }} 66 | 67 | - name: 📦 Pack build as zip 68 | run: zip -r ${{ matrix.name }}.zip ${{ matrix.name }} 69 | shell: bash 70 | 71 | - name: ⏫ Upload Release Asset 72 | id: upload-release-asset 73 | uses: actions/github-script@v6 74 | with: 75 | result-encoding: json 76 | script: | 77 | const FS = require('node:fs') 78 | const { repo, owner } = context.repo; 79 | return await github.rest.repos.uploadReleaseAsset({ 80 | owner, 81 | repo, 82 | release_id: context.payload.release.id, 83 | name: '${{ matrix.name }}.zip', 84 | data: FS.readFileSync('${{ github.workspace }}/${{ matrix.name }}.zip') 85 | }); 86 | -------------------------------------------------------------------------------- /.github/workflows/runner.yml: -------------------------------------------------------------------------------- 1 | name: 🔗 GHA 2 | 3 | # Only run pipeline on open pull_requests and master + versions + releases 4 | # we don't need it on every push and some parameters are not available for push only 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - "master" 10 | - "3.4" 11 | - "4.1" 12 | release: 13 | types: [published] 14 | 15 | concurrency: 16 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | get-version: 21 | name: 🆚 Get godot version 22 | uses: ./.github/workflows/get_version.yml 23 | 24 | static-checks: 25 | name: 📊 Static checks 26 | uses: ./.github/workflows/static_checks.yml 27 | needs: get-version 28 | with: 29 | version: ${{ needs.get-version.outputs.version }} 30 | 31 | android-build: 32 | name: 🤖 Android 33 | needs: [static-checks, get-version] 34 | uses: ./.github/workflows/android_builds.yml 35 | with: 36 | version: ${{ needs.get-version.outputs.version }} 37 | 38 | ios-build: 39 | name: 🍏 iOS 40 | needs: [static-checks, get-version] 41 | uses: ./.github/workflows/ios_builds.yml 42 | with: 43 | version: ${{ needs.get-version.outputs.version }} 44 | 45 | linux-build: 46 | name: 🐧 Linux 47 | needs: [static-checks, get-version] 48 | uses: ./.github/workflows/linux_builds.yml 49 | with: 50 | version: ${{ needs.get-version.outputs.version }} 51 | 52 | macos-build: 53 | name: 🍎 macOS 54 | needs: [static-checks, get-version] 55 | uses: ./.github/workflows/macos_builds.yml 56 | with: 57 | version: ${{ needs.get-version.outputs.version }} 58 | 59 | windows-build: 60 | name: 🏁 Windows 61 | needs: [static-checks, get-version] 62 | uses: ./.github/workflows/windows_builds.yml 63 | with: 64 | version: ${{ needs.get-version.outputs.version }} 65 | 66 | web-build: 67 | name: 🌐 Web 68 | needs: [static-checks, get-version] 69 | uses: ./.github/workflows/web_builds.yml 70 | with: 71 | version: ${{ needs.get-version.outputs.version }} 72 | 73 | checks-done: 74 | if: ${{ always() }} 75 | name: ✅ Check builds 76 | runs-on: ubuntu-latest 77 | steps: 78 | - name: 🎉 Checks done 79 | run: | 80 | resultWebBuild="${{ needs.web-build.result }}" 81 | resultWindowsBuild="${{ needs.windows-build.result }}" 82 | resultMacosBuild="${{ needs.macos-build.result }}" 83 | resultLinuxBuild="${{ needs.linux-build.result }}" 84 | resultIosBuild="${{ needs.ios-build.result }}" 85 | resultAndroidBuild="${{ needs.android-build.result }}" 86 | if [[ 87 | $resultWebBuild == "success" && 88 | $resultWindowsBuild == "success" && 89 | $resultMacosBuild == "success" && 90 | $resultLinuxBuild == "success" && 91 | $resultIosBuild == "success" && 92 | $resultAndroidBuild == "success" 93 | ]]; 94 | then 95 | echo "🎉 All builds were successful." 96 | exit 0 97 | else 98 | echo "😥 Some builds were failing." 99 | exit 1 100 | fi 101 | needs: 102 | [ 103 | web-build, 104 | windows-build, 105 | macos-build, 106 | linux-build, 107 | ios-build, 108 | android-build 109 | ] 110 | 111 | release: 112 | name: 🦅 Release 113 | if: github.event_name == 'release' && github.event.action == 'published' 114 | needs: [checks-done, get-version] 115 | uses: ./.github/workflows/release_builds.yml 116 | secrets: inherit 117 | with: 118 | version: ${{ needs.get-version.outputs.version }} 119 | -------------------------------------------------------------------------------- /.github/workflows/static_checks.yml: -------------------------------------------------------------------------------- 1 | name: 📊 Static Checks 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | concurrency: 10 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | static-checks: 15 | name: Code style, file formatting, and docs 16 | runs-on: ubuntu-22.04 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Checkout Godot 22 | uses: actions/checkout@v4 23 | with: 24 | repository: godotengine/godot 25 | ref: ${{ inputs.version }} 26 | sparse-checkout: | 27 | misc/scripts 28 | sparse-checkout-cone-mode: false 29 | path: tmp 30 | 31 | - name: Checkout workaround 32 | run: | 33 | mv tmp/misc/scripts misc/scripts 34 | cp clang_format.sh misc/scripts/clang_format.sh 35 | 36 | - name: Install APT dependencies 37 | uses: awalsh128/cache-apt-pkgs-action@latest 38 | with: 39 | packages: dos2unix libxml2-utils moreutils 40 | 41 | - name: Install Python dependencies and general setup 42 | run: | 43 | pip3 install black==22.3.0 pytest==7.1.2 mypy==0.971 44 | git config diff.wsErrorHighlight all 45 | 46 | - name: Get changed files 47 | id: changed-files 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | run: | 51 | if [ "${{ github.event_name }}" == "pull_request" ]; then 52 | files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only) 53 | elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then 54 | files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true) 55 | fi 56 | echo "$files" >> changed.txt 57 | cat changed.txt 58 | files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "./{}"' | tr '\n' ' ') 59 | echo "CHANGED_FILES=$files" >> $GITHUB_ENV 60 | 61 | - name: File formatting checks (file_format.sh) 62 | run: | 63 | bash ./misc/scripts/file_format.sh changed.txt 64 | 65 | - name: Python scripts static analysis (mypy_check.sh) 66 | run: | 67 | if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then 68 | bash ./misc/scripts/mypy_check.sh 69 | else 70 | echo "Skipping Python static analysis as no Python files were changed." 71 | fi 72 | 73 | - name: Style checks via clang-format (clang_format.sh) 74 | run: | 75 | clang-format --version 76 | bash ./misc/scripts/clang_format.sh changed.txt 77 | -------------------------------------------------------------------------------- /.github/workflows/web_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🌐 Web Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | 10 | # Global Settings 11 | env: 12 | SCONSFLAGS: warnings=extra werror=yes debug_symbols=no 13 | EM_VERSION: 3.1.18 14 | EM_CACHE_FOLDER: "emsdk-cache" 15 | 16 | concurrency: 17 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-web 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | web-template: 22 | runs-on: "ubuntu-20.04" 23 | name: Template (target=template_release) 24 | 25 | steps: 26 | - name: Checkout Godot 27 | uses: actions/checkout@v4 28 | with: 29 | repository: godotengine/godot 30 | ref: ${{ inputs.version }} 31 | 32 | - name: Checkout ECMAScript 33 | uses: actions/checkout@v4 34 | with: 35 | path: ${{github.workspace}}/modules/javascript/ 36 | 37 | - name: Set up Emscripten latest 38 | uses: mymindstorm/setup-emsdk@v12 39 | with: 40 | version: ${{env.EM_VERSION}} 41 | actions-cache-folder: ${{env.EM_CACHE_FOLDER}} 42 | 43 | - name: Verify Emscripten setup 44 | run: | 45 | emcc -v 46 | 47 | - name: Setup Godot build cache 48 | uses: ./.github/actions/godot-cache 49 | continue-on-error: true 50 | 51 | - name: Setup python and scons 52 | uses: ./.github/actions/godot-deps 53 | 54 | - name: Compilation 55 | uses: ./.github/actions/godot-build 56 | with: 57 | sconsflags: ${{ env.SCONSFLAGS }} 58 | platform: web 59 | target: template_release 60 | tests: false 61 | 62 | - name: Upload artifact 63 | uses: ./.github/actions/upload-artifact 64 | -------------------------------------------------------------------------------- /.github/workflows/windows_builds.yml: -------------------------------------------------------------------------------- 1 | name: 🏁 Windows Builds 2 | on: 3 | workflow_call: 4 | inputs: 5 | version: 6 | required: true 7 | type: string 8 | 9 | 10 | # Global Settings 11 | # SCONS_CACHE for windows must be set in the build environment 12 | env: 13 | SCONSFLAGS: warnings=extra werror=yes module_text_server_fb_enabled=yes 14 | SCONS_CACHE_MSVC_CONFIG: true 15 | 16 | concurrency: 17 | group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-windows 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | build-windows: 22 | # Windows 10 with latest image 23 | runs-on: "windows-latest" 24 | name: ${{ matrix.name }} 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | include: 29 | - name: Editor (target=editor, tests=yes) 30 | cache-name: windows-editor 31 | target: editor 32 | tests: true 33 | # Skip debug symbols, they're way too big with MSVC. 34 | sconsflags: debug_symbols=no vsproj=yes 35 | bin: "./bin/godot.windows.editor.x86_64.exe" 36 | 37 | - name: Template (target=template_release) 38 | cache-name: windows-template 39 | target: template_release 40 | tests: false 41 | sconsflags: debug_symbols=no 42 | 43 | steps: 44 | - name: Checkout Godot 45 | uses: actions/checkout@v4 46 | with: 47 | repository: godotengine/godot 48 | ref: ${{ inputs.version }} 49 | 50 | - name: Checkout ECMAScript 51 | uses: actions/checkout@v4 52 | with: 53 | path: ${{github.workspace}}/modules/javascript/ 54 | 55 | - name: Setup Godot build cache 56 | uses: ./.github/actions/godot-cache 57 | with: 58 | cache-name: ${{ matrix.cache-name }} 59 | continue-on-error: true 60 | 61 | - name: Setup python and scons 62 | uses: ./.github/actions/godot-deps 63 | 64 | - name: Setup MSVC problem matcher 65 | uses: ammaraskar/msvc-problem-matcher@master 66 | 67 | - name: Compilation 68 | uses: ./.github/actions/godot-build 69 | with: 70 | sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} 71 | platform: windows 72 | target: ${{ matrix.target }} 73 | tests: ${{ matrix.tests }} 74 | 75 | # Execute unit tests for the editor 76 | - name: Unit tests 77 | if: ${{ matrix.tests }} 78 | run: | 79 | ${{ matrix.bin }} --version 80 | ${{ matrix.bin }} --help 81 | ${{ matrix.bin }} --test --force-colors 82 | 83 | - name: Prepare artifact 84 | run: | 85 | Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force 86 | 87 | - name: Upload artifact 88 | uses: ./.github/actions/upload-artifact 89 | with: 90 | name: ${{ matrix.cache-name }} 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | *.lib 4 | *.d 5 | *.pyc 6 | *.bc 7 | *.os 8 | *.gen.cpp 9 | *.gen.json 10 | .vscode 11 | .idea 12 | /site 13 | venv 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Project Structure 4 | 5 | - [Clang](https://clang.llvm.org/): Code formatting 6 | - ``.clang-format`` 7 | - ``.clang-tidy`` 8 | - ``clang-format.sh`` 9 | - [Custom Modules in C++](https://docs.godotengine.org/en/stable/contributing/development/core_and_modules/custom_modules_in_cpp.html#custom-modules-in-c) 10 | - ``config.py``: Configs for this module 11 | - ``doc``: For showing documentation in editor 12 | - ``doc_classes``: For showing documentation in editor 13 | - ``icons``: For showing icons in editor 14 | - ``SCsub``: Will be called from Godots `SConstruct` during build 15 | - ``editor``: Custom `.cpp` only bundled for `target=editor` 16 | - ``misc``: Scripts and other files, which aren't related to `c++` 17 | - ``tests``: Some testcases to run in CICD 18 | - ``thirdparty``: Dependencies or libraries which shouldn't be analysed by static checks 19 | - GodotJS custom data 20 | - ``.github``: Runs custom CI/CD in GitHub 21 | - ``docs``: Add some additional stuff for README.md 22 | - ``src``: Contains custom C++ code 23 | - [language](src/language/README.md) 24 | 25 | 26 | ## Preparing your PR 27 | 28 | The project is using [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) to format C++ files. 29 | You need to run `bash clang_format.sh` before your PR for a successful pipeline. 30 | 31 | Furthermore, there is an `utf-8` and `LF` checker to fix file formats. Additionally, some spellchecks run inside the [pipeline](.github/workflows/static_checks.yml). 32 | 33 | ## Release library 34 | 35 | As a maintainer you are able to create a new release. 36 | 1. Go to [create new release](https://github.com/godotjs/javascript/releases/new) 37 | 2. Next you should ``Choose a tag`` and create a new one in the format `v0.0.0` 38 | 3. Select target ``master`` 39 | 4. Click ``Generate release notes`` 40 | 5. (Optional) You can edit the generated release notes 41 | 6. Add a release title in the format `v0.0.0` 42 | 7. Press ``Publish release`` 43 | 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Geequlim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | GodotJS Logo 4 | 5 | 6 | # **GodotJS** 7 | 8 | ***-- JavaScript and TypeScript language binding for Godot game engine --*** 9 | 10 | This module implements JavaScript/TypeScript language support for the Godot game engine using [QuickJS](https://bellard.org/quickjs/) as the JavaScript engine. 11 | 12 | 13 | ## Getting started 14 | 15 | Read the [getting-started](https://godotjs.github.io/documentation/getting-started/). 16 | 17 | ## Features 18 | 19 | - Almost complete ES2020 support 20 | - All Godot API available 21 | - Operator overriding for built-in types (Vector3, Color, etc) 22 | - TypeScript support 23 | - [Using third-party libraries from npm](https://github.com/GodotExplorer/ECMAScriptDemos/tree/master/npm_module) 24 | - Multi-thread support with Worker API 25 | - Full code completion support for all Godot APIs including signals and enumerations 26 | - Debug in Visual Studio Code with the [plugin](https://marketplace.visualstudio.com/items?itemName=geequlim.godot-javascript-debug) - currently not available for 4.x 27 | 28 | ## Getting the engine 29 | 30 | No installation or setup necessary. The binaries for download are the complete, usable Godot editor and engine with JavaScript/TypeScript language support. 31 | 32 | ### Binary downloads 33 | 34 | Download the binaries from the [release page](https://github.com/GodotExplorer/ECMAScript/releases). 35 | 36 | ### Compiling from source 37 | 38 | - Clone the source code of [godot](https://github.com/godotengine/godot): 39 | - `git clone git@github.com:godotengine/godot.git` or 40 | - `git clone https://github.com/godotengine/godot.git` 41 | - This branch uses version `4.1` so checkout the version with: `git checkout 4.1` 42 | - Clone this module and put it into `godot/modules/javascript`: 43 | - `git clone git@github.com:godotjs/javascript.git godot/modules/javascript` or 44 | - `git clone https://github.com/godotjs/javascript.git godot/modules/javascript` 45 | - [Recompile the godot engine](https://docs.godotengine.org/en/4.1/development/compiling/index.html) 46 | - Use `scons` with those additional options `warnings=extra werror=yes module_text_server_fb_enabled=yes` to show all potential errors: 47 | - Windows: `scons platform=windows warnings=extra werror=yes module_text_server_fb_enabled=yes` 48 | - MacOS: `scons platform=macos arch=arm64 warnings=extra werror=yes module_text_server_fb_enabled=yes` 49 | - **Hint**: To enable unit tests you need to add ``tests=true`` to `scons` arguments 50 | 51 | ## Documentation, Tutorials & Demos 52 | 53 | 54 | Read this [documentation](https://godotjs.github.io/documentation/getting-started/) or look at the tutorials or demos: 55 | 56 | - [ECMAScriptDemos](https://github.com/godotjs/javascriptDemos) - Demos 57 | - [godot-ECMAScript-cookbook](https://github.com/why-try313/godot-ECMAScript-cookbook/wiki) - Tutorial 58 | - [godot-typescript-starter](https://github.com/citizenll/godot-typescript-starter) - Template 59 | - [godot-js-template](https://github.com/fukaraadam-workspace/godot-js-template) - Template 60 | 61 | ## Contributing 62 | 63 | If you like to contribute to this project check the [CONTRIBUTING.md](https://github.com/godotjs/javascript/blob/master/CONTRIBUTING.md) file. 64 | -------------------------------------------------------------------------------- /SCsub: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | 4 | from misc.generate.generate_files import generate 5 | 6 | Import("env") 7 | Import("env_modules") 8 | 9 | env_javascript = env_modules.Clone() 10 | 11 | # Default engine to use we might add some more in the future like node or v8 12 | JS_ENGINE = "quickjs" 13 | javascript_dir = os.path.join(GetLaunchDir(), "modules", os.path.basename(os.getcwd())) 14 | 15 | # Windows workaround 16 | if env["platform"] == "windows": 17 | if env["use_mingw"]: 18 | env.Append(LIBS=["pthread"]) 19 | 20 | # Add required files for quickjs into godot 21 | if JS_ENGINE == "quickjs": 22 | import generate_builtin_api 23 | 24 | generate_builtin_api.generate_api_json(javascript_dir) 25 | import thirdparty.quickjs.builtin_binding_generator 26 | 27 | thirdparty.quickjs.builtin_binding_generator.generate_builtin_bindings() 28 | version = open("thirdparty/quickjs/quickjs/VERSION.txt", "r").read().split("\n")[0] 29 | quickjs_env = env_javascript.Clone() 30 | quickjs_env.Append(CPPDEFINES={"QUICKJS_CONFIG_VERSION": '"' + version + '"'}) 31 | quickjs_env.Append(CPPDEFINES=["CONFIG_BIGNUM"]) 32 | if "release" not in (quickjs_env["target"] or ""): 33 | quickjs_env.Append(CPPDEFINES={"DUMP_LEAKS": 1}) 34 | # TODO: Fix debugger 35 | # quickjs_env.Append(CPPDEFINES={"QUICKJS_WITH_DEBUGGER": 1}) 36 | quickjs_env.Append(CPPPATH=["thirdparty/quickjs/quickjs"]) 37 | quickjs_env.Append(CPPPATH=["thirdparty/quickjs"]) 38 | quickjs_env.disable_warnings() 39 | quickjs_env.add_source_files(env.modules_sources, "thirdparty/quickjs/quickjs_builtin_binder.gen.cpp") 40 | quickjs_env.add_source_files(env.modules_sources, "thirdparty/quickjs/*.cpp") 41 | quickjs_env.add_source_files(env.modules_sources, "thirdparty/quickjs/quickjs/*.c") 42 | 43 | # If target=editor is provided via scons 44 | if env.editor_build: 45 | env_javascript.add_source_files(env.modules_sources, "editor/workarounds/*.cpp") 46 | env_javascript.add_source_files(env.modules_sources, "editor/*.cpp") 47 | 48 | # --- Generate editor tool files --- 49 | from misc.generate.editor_tools import get_editor_tools_files 50 | from misc.generate.editor_tools import get_editor_tools_header 51 | 52 | files = get_editor_tools_files() 53 | generate(javascript_dir, get_editor_tools_header(), files) 54 | env_javascript.add_source_files(env.modules_sources, files.keys()) 55 | 56 | # If tests=yes flag is provided via scons 57 | if env["tests"]: 58 | env_javascript.Append(CPPDEFINES=["TESTS_ENABLED"]) 59 | 60 | # --- Generate test files --- 61 | from misc.generate.test_manager import get_test_files 62 | from misc.generate.test_manager import get_test_manager_header 63 | 64 | files = get_test_files() 65 | generate(javascript_dir, get_test_manager_header(), files) 66 | env_javascript.add_source_files(env.modules_sources, files.keys()) 67 | 68 | # --- Files inside editor & targets --- 69 | 70 | sources = [ 71 | "register_types.cpp", 72 | "javascript_instance.cpp", 73 | "javascript.cpp", 74 | ] 75 | 76 | # Add all required files for "Javascript" language into godot 77 | env_javascript.Append(CPPPATH=["#modules/javascript"]) 78 | env_javascript.add_source_files(env.modules_sources, sources) 79 | env_javascript.add_source_files(env.modules_sources, "src/language/*.cpp") 80 | env_javascript.add_source_files(env.modules_sources, "src/language/templates/*.cpp") 81 | 82 | # --- Generate template files --- 83 | from misc.generate.templates import get_templates_header 84 | from misc.generate.templates import get_templates_files 85 | from misc.generate.generate_files import generate_templates 86 | 87 | files = get_templates_files() 88 | generate_templates(javascript_dir, get_templates_header(), files) 89 | env_javascript.add_source_files(env.modules_sources, files.keys()) 90 | 91 | # --- Generate binding files --- 92 | # Binding script to run at engine initializing 93 | # The bindings add some functionality for `this.connect(...)` 94 | from misc.generate.bindings import get_bindings_header 95 | from misc.generate.bindings import get_binding_files 96 | 97 | files = get_binding_files() 98 | generate(javascript_dir, get_bindings_header(), files) 99 | env_javascript.add_source_files(env.modules_sources, files.keys()) 100 | -------------------------------------------------------------------------------- /clang_format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script runs clang-format and fixes copyright headers on all relevant files in the repo. 4 | # This is the primary script responsible for fixing style violations. 5 | 6 | set -uo pipefail 7 | 8 | if [ $# -eq 0 ]; then 9 | # Loop through all code files tracked by Git. 10 | files=$(git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \ 11 | ':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \ 12 | ':!:*-so_wrap.*' ':!:tests/python_build/*') 13 | else 14 | # $1 should be a file listing file paths to process. Used in CI. 15 | files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$" | grep -v "platform/android/java/lib/src/com/google/" | grep -v "\-so_wrap\." | grep -v "tests/python_build/") 16 | fi 17 | 18 | if [ ! -z "$files" ]; then 19 | clang-format --Wno-error=unknown -i $files 20 | fi 21 | 22 | diff=$(git diff --color) 23 | 24 | # If no diff has been generated all is OK, clean up, and exit. 25 | if [ -z "$diff" ] ; then 26 | printf "\e[1;32m*** Files in this commit comply with the clang-format style rules.\e[0m\n" 27 | exit 0 28 | fi 29 | 30 | # A diff has been created, notify the user, clean up, and exit. 31 | printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" 32 | # Perl commands replace trailing spaces with `·` and tabs with ``. 33 | printf "%s\n" "$diff" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' 34 | 35 | printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" 36 | exit 1 37 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | def can_build(env, platform): 2 | return True 3 | 4 | 5 | def configure(env): 6 | pass 7 | 8 | 9 | def get_doc_classes(): 10 | return [ 11 | "JavaScript", 12 | "JavaScriptModule", 13 | ] 14 | 15 | 16 | def get_doc_path(): 17 | return "doc_classes" 18 | -------------------------------------------------------------------------------- /doc_classes/JavaScript.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A JavaScript script resource for creating and managing JavaScript scripts in Godot. 5 | 6 | 7 | The JavaScript class provides a way to create and manage JavaScript scripts within the Godot game engine. It inherits from the Script class and allows you to write game logic using JavaScript as the scripting language. 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc_classes/JavaScriptModule.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A JavaScript module resource for managing JavaScript source code and bytecode. 5 | 6 | 7 | The JavaScriptModule class provides methods to manage JavaScript source code and bytecode. It allows you to get and set both the source code and bytecode of a JavaScript module. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Returns the bytecode of the JavaScript module as a PackedByteArray. 16 | 17 | 18 | 19 | 20 | 21 | Returns the source code of the JavaScript module as a String. 22 | 23 | 24 | 25 | 26 | 27 | 28 | Sets the bytecode of the JavaScript module using a PackedByteArray. 29 | 30 | 31 | 32 | 33 | 34 | 35 | Sets the source code of the JavaScript module using a String. 36 | 37 | 38 | 39 | 40 | 41 | The path to the JavaScript script file. 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/JavaScript.svg.licence: -------------------------------------------------------------------------------- 1 | ../icon/JavaScript.svg: https://commons.wikimedia.org/wiki/File:Unofficial_JavaScript_logo.svg 2 | -------------------------------------------------------------------------------- /editor/editor_tools.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef EDITOR_TOOLS_H 3 | #define EDITOR_TOOLS_H 4 | 5 | #include "editor/editor_node.h" 6 | #include "editor/editor_plugin.h" 7 | #include "editor/gui/editor_file_dialog.h" 8 | 9 | class DocTools; 10 | class EditorFileDialog; 11 | class JavaScriptPlugin : public EditorPlugin { 12 | GDCLASS(JavaScriptPlugin, EditorPlugin); 13 | 14 | enum MenuItem { 15 | ITEM_GEN_DECLARE_FILE, 16 | ITEM_GEN_ENUM_BINDING_SCRIPT, 17 | }; 18 | 19 | EditorFileDialog *declaration_file_dialog; 20 | EditorFileDialog *enumberation_file_dialog; 21 | const Dictionary *modified_api; 22 | 23 | protected: 24 | /* Strings will be generated by ./SCsub from misc directory */ 25 | static String BUILTIN_DECLARATION_TEXT; 26 | 27 | /* Missing declarations, ignoring*/ 28 | static Dictionary DECLARATION_CONSTRUCTORS; 29 | static Dictionary DECLARATION_ENUMS; 30 | static Array IGNORE_METHODS; 31 | 32 | static void _bind_methods(); 33 | 34 | void _notification(int p_what); 35 | void _on_menu_item_pressed(int item); 36 | void _export_typescript_declare_file(const String &p_path); 37 | void _export_enumeration_binding_file(const String &p_path); 38 | 39 | public: 40 | virtual String get_name() const override { return "JavaScriptPlugin"; } 41 | JavaScriptPlugin(EditorNode *p_node); 42 | }; 43 | 44 | #endif // EDITOR_TOOLS_H 45 | -------------------------------------------------------------------------------- /editor/workarounds/ignore-methods.cpp: -------------------------------------------------------------------------------- 1 | /* All types are generated in editor_tools, but some getters and setters are obsolete we need to ignore them. */ 2 | 3 | #include "../editor_tools.h" 4 | 5 | Array create_ignore_methods() { 6 | Array array = Array(); 7 | array.push_back("get_flag"); 8 | array.push_back("set_flag"); 9 | array.push_back("set_play_area_mode"); 10 | return array; 11 | } 12 | 13 | Array JavaScriptPlugin::IGNORE_METHODS = create_ignore_methods(); 14 | -------------------------------------------------------------------------------- /editor/workarounds/missing-constructors.cpp: -------------------------------------------------------------------------------- 1 | /* All types are generated in editor_tools, but constructors are missing we need to add them manually. */ 2 | 3 | #include "../editor_tools.h" 4 | 5 | Dictionary create_missing_constructors() { 6 | Dictionary dict; 7 | dict["Vector2"] = "\t\tconstructor(x?: number, y?: number);\n" 8 | "\t\tconstructor(v: Vector2);\n"; 9 | dict["Rect2"] = "\t\tconstructor(from: Rect2);\n" 10 | "\t\tconstructor(x?: number, y?: number, w?: number, h?: number);\n" 11 | "\t\tconstructor(pos: Vector2, size: Vector2)\n"; 12 | dict["Vector3"] = "\t\tconstructor(x?: number, y?: number, z?: number);\n" 13 | "\t\tconstructor(v: Vector3);\n"; 14 | dict["Basis"] = "\t\tconstructor();\n" 15 | "\t\tconstructor(from: Basis);\n" 16 | "\t\tconstructor(from: Quaternion);\n" 17 | "\t\tconstructor(from: Vector3);\n" 18 | "\t\tconstructor(axis: Vector3, phi: number);\n" 19 | "\t\tconstructor(x_axis: Vector3, y_axis: Vector3, z_axis: Vector3);\n"; 20 | dict["Transform3D"] = "\t\tconstructor(from: Transform3D);\n" 21 | "\t\tconstructor(from: Basis);\n" 22 | "\t\tconstructor(from: Quaternion);\n" 23 | "\t\tconstructor(from: Transform2D);\n" 24 | "\t\tconstructor(basis: Basis, origin: Vector3);\n" 25 | "\t\tconstructor(x_axis?: Vector3, y_axis?: Vector3, z_axis?: Vector3, origin?: Vector3);\n"; 26 | dict["Basis"] = "\t\tconstructor();\n" 27 | "\t\tconstructor(from: Transform2D);\n" 28 | "\t\tconstructor(from: Transform3D);\n" 29 | "\t\tconstructor(x_axis: Vector2, y_axis: Vector2, origin: Vector2);\n" 30 | "\t\tconstructor(rotation: number, position: Vector2);\n"; 31 | dict["Color"] = "\t\tconstructor(from: Color);\n" 32 | "\t\tconstructor(from: string);\n" 33 | "\t\tconstructor(from: number);\n" 34 | "\t\tconstructor(r?: number, g?: number, b?: number, a?: number);\n"; 35 | dict["Plane"] = "\t\tconstructor(from: Plane);\n" 36 | "\t\tconstructor(v1: Vector3, d: number);\n" 37 | "\t\tconstructor(v1: Vector3, v2: Vector3, v3: Vector3);\n" 38 | "\t\tconstructor(a?: number, b?: number, c?: number, d?: number);\n"; 39 | dict["Quaternion"] = 40 | "\t\tconstructor(from: Quaternion);\n" 41 | "\t\tconstructor(from: Basis);\n" 42 | "\t\tconstructor(euler: Vector3);\n" 43 | "\t\tconstructor(axis: Vector3, angle: number);\n" 44 | "\t\tconstructor(x?: number, y?: number, z?: number, w?: number);\n"; 45 | dict["AABB"] = 46 | "\t\tconstructor(from: AABB);\n" 47 | "\t\tconstructor(position?: Vector3, size?: Vector3);\n"; 48 | dict["PackedByteArray"] = 49 | "\t\tconstructor(source?: number[]);\n" 50 | "\t\tconstructor(from: PackedByteArray);\n" 51 | "\t\tconstructor(from: ArrayBuffer);\n" 52 | "\t\tconstructor(from: DataView);\n" 53 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 54 | dict["PackedColorArray"] = 55 | "\t\tconstructor(source?: Color[]);\n" 56 | "\t\tconstructor(from: PackedColorArray);\n" 57 | "\t\tconstructor(from: ArrayBuffer);\n" 58 | "\t\tconstructor(from: DataView);\n" 59 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 60 | dict["PackedInt32Array"] = 61 | "\t\tconstructor(source?: number[]);\n" 62 | "\t\tconstructor(from: PackedInt32Array);\n" 63 | "\t\tconstructor(from: ArrayBuffer);\n" 64 | "\t\tconstructor(from: DataView);\n" 65 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 66 | dict["PackedFloat32Array"] = 67 | "\t\tconstructor(source?: number[]);\n" 68 | "\t\tconstructor(from: PackedFloat32Array);\n" 69 | "\t\tconstructor(from: ArrayBuffer);\n" 70 | "\t\tconstructor(from: DataView);\n" 71 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 72 | dict["PackedStringArray"] = 73 | "\t\tconstructor(source?: string[]);\n" 74 | "\t\tconstructor(from: PackedStringArray);\n" 75 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 76 | dict["PackedVector2Array"] = 77 | "\t\tconstructor(source?: Vector2[]);\n" 78 | "\t\tconstructor(from: PackedVector2Array);\n" 79 | "\t\tconstructor(from: ArrayBuffer);\n" 80 | "\t\tconstructor(from: DataView);\n" 81 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 82 | dict["PackedVector3Array"] = 83 | "\t\tconstructor(source?: Vector3[]);\n" 84 | "\t\tconstructor(from: PackedVector3Array);\n" 85 | "\t\tconstructor(from: ArrayBuffer);\n" 86 | "\t\tconstructor(from: DataView);\n" 87 | "\t\t[Symbol.iterator](): IterableIterator;\n"; 88 | return dict; 89 | } 90 | 91 | Dictionary JavaScriptPlugin::DECLARATION_CONSTRUCTORS = create_missing_constructors(); 92 | -------------------------------------------------------------------------------- /editor/workarounds/missing-enums.cpp: -------------------------------------------------------------------------------- 1 | /* All types are generated in editor_tools, but some enums are missing we need to add them manually. */ 2 | 3 | #include "../editor_tools.h" 4 | 5 | Dictionary create_missing_enums() { 6 | Dictionary dict; 7 | dict["Vector3"] = "\t\tenum Axis {\n" 8 | "\t\t\tAXIS_X = 0,\n" 9 | "\t\t\tAXIS_Y = 1,\n" 10 | "\t\t\tAXIS_Z = 2,\n" 11 | "\t\t}\n"; 12 | return dict; 13 | } 14 | 15 | Dictionary JavaScriptPlugin::DECLARATION_ENUMS = create_missing_enums(); 16 | -------------------------------------------------------------------------------- /generate_builtin_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import json, os, sys 3 | import xml.etree.ElementTree as ET 4 | 5 | BUILTIN_CLASSES = [ 6 | "Vector2", 7 | "Rect2", 8 | "Color", 9 | "Vector3", 10 | "Basis", 11 | "Quaternion", 12 | "RID", 13 | "Transform2D", 14 | "Plane", 15 | "AABB", 16 | "Transform3D", 17 | "PackedByteArray", 18 | "PackedInt32Array", 19 | "PackedInt64Array", 20 | "PackedFloat32Array", 21 | "PackedFloat64Array", 22 | "PackedStringArray", 23 | "PackedVector2Array", 24 | "PackedVector3Array", 25 | "PackedColorArray", 26 | ] 27 | 28 | MAX_CONSTRUCTOR_ARGC = { 29 | "Vector2": 2, 30 | "Rect2": 4, 31 | "Color": 4, 32 | "Vector3": 3, 33 | "Basis": 0, 34 | "Quaternion": 0, 35 | "RID": 0, 36 | "Transform2D": 0, 37 | "Plane": 0, 38 | "AABB": 0, 39 | "Transform3D": 0, 40 | "PackedByteArray": 0, 41 | "PackedInt32Array": 0, 42 | "PackedInt64Array": 0, 43 | "PackedFloat32Array": 0, 44 | "PackedFloat64Array": 0, 45 | "PackedStringArray": 0, 46 | "PackedVector2Array": 0, 47 | "PackedVector3Array": 0, 48 | "PackedColorArray": 0, 49 | } 50 | 51 | TYPE_MAP = { 52 | "int": "number", 53 | "float": "number", 54 | "bool": "boolean", 55 | "String": "string", 56 | "NodePath": "string", 57 | } 58 | 59 | METHOD_OP_EQUALS = { 60 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 61 | "name": "equals", 62 | "native_method": "operator==", 63 | "return": "boolean", 64 | } 65 | 66 | METHOD_OP_ADD = { 67 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 68 | "name": "add", 69 | "native_method": "operator+", 70 | "return": "${class_name}", 71 | } 72 | 73 | METHOD_OP_ADD_ASSIGN = { 74 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 75 | "name": "add_assign", 76 | "native_method": "operator+=", 77 | "return": "this", 78 | } 79 | 80 | METHOD_OP_SUB = { 81 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 82 | "name": "subtract", 83 | "native_method": "operator-", 84 | "return": "${class_name}", 85 | } 86 | 87 | METHOD_OP_SUB_ASSIGN = { 88 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 89 | "name": "subtract_assign", 90 | "native_method": "operator-=", 91 | "return": "this", 92 | } 93 | 94 | METHOD_OP_MUL = { 95 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 96 | "name": "multiply", 97 | "native_method": "operator*", 98 | "return": "${class_name}", 99 | } 100 | 101 | METHOD_OP_MUL_ASSIGN = { 102 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 103 | "name": "multiply_assign", 104 | "native_method": "operator*=", 105 | "return": "this", 106 | } 107 | 108 | METHOD_OP_DIV = { 109 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 110 | "name": "multiply", 111 | "native_method": "operator/", 112 | "return": "${class_name}", 113 | } 114 | 115 | METHOD_OP_DIV_ASSIGN = { 116 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 117 | "name": "multiply_assign", 118 | "native_method": "operator/=", 119 | "return": "this", 120 | } 121 | 122 | METHOD_OP_NEG = { 123 | "arguments": [], 124 | "name": "negate", 125 | "native_method": "operator-", 126 | "return": "${class_name}", 127 | } 128 | 129 | METHOD_OP_LESS = { 130 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 131 | "name": "less", 132 | "native_method": "operator<", 133 | "return": "boolean", 134 | } 135 | 136 | 137 | METHOD_OP_LESS_EQAUL = { 138 | "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], 139 | "name": "less_equal", 140 | "native_method": "operator<=", 141 | "return": "boolean", 142 | } 143 | 144 | METHOD_PACKED_ARRAY_GET = { 145 | "arguments": [{"default_value": None, "has_default_value": False, "type": "number"}], 146 | "name": "get", 147 | "native_method": "operator[]", 148 | "return": "Variant", 149 | } 150 | 151 | IGNORED_PROPS = { 152 | "Rect2": ["end", "grow_side"], 153 | "Color": ["h", "s", "v", "r8", "g8", "b8", "a8"], 154 | "Transform2D": ["xform", "xform_inv"], 155 | "Quaternion": ["get_euler"], 156 | "Basis": ["is_equal_approx", "get_euler", "from_euler"], 157 | "Plane": ["intersects_segment", "intersects_ray", "intersect_3"], 158 | "AABB": ["end"], 159 | "Transform3D": ["xform", "xform_inv"], 160 | "PackedByteArray": [ 161 | "compress", 162 | "decompress", 163 | "decompress_dynamic", 164 | "get_string_from_ascii", 165 | "get_string_from_utf8", 166 | "get_string_from_utf16", 167 | "get_string_from_utf32", 168 | "hex_encode", 169 | "to_float32_array", 170 | "to_float64_array", 171 | "to_int32_array", 172 | "to_int64_array", 173 | "has_encoded_var", 174 | ], 175 | } 176 | 177 | PROPERTY_REMAP = { 178 | "Transform2D": { 179 | "x": "columns[0]", 180 | "y": "columns[1]", 181 | "origin": "columns[2]", 182 | }, 183 | "Basis": { 184 | "x": "rows[0]", 185 | "y": "rows[1]", 186 | "z": "rows[2]", 187 | }, 188 | "Plane": { 189 | "x": "normal.x", 190 | "y": "normal.y", 191 | "z": "normal.z", 192 | }, 193 | } 194 | 195 | OPERATOR_METHODS = { 196 | "Vector2": [ 197 | METHOD_OP_NEG, 198 | METHOD_OP_EQUALS, 199 | METHOD_OP_LESS, 200 | METHOD_OP_LESS_EQAUL, 201 | METHOD_OP_ADD, 202 | METHOD_OP_ADD_ASSIGN, 203 | METHOD_OP_SUB, 204 | METHOD_OP_SUB_ASSIGN, 205 | METHOD_OP_MUL, 206 | METHOD_OP_MUL_ASSIGN, 207 | METHOD_OP_DIV, 208 | METHOD_OP_DIV_ASSIGN, 209 | ], 210 | "Vector3": [ 211 | METHOD_OP_NEG, 212 | METHOD_OP_EQUALS, 213 | METHOD_OP_LESS, 214 | METHOD_OP_LESS_EQAUL, 215 | METHOD_OP_ADD, 216 | METHOD_OP_ADD_ASSIGN, 217 | METHOD_OP_SUB, 218 | METHOD_OP_SUB_ASSIGN, 219 | METHOD_OP_MUL, 220 | METHOD_OP_MUL_ASSIGN, 221 | METHOD_OP_DIV, 222 | METHOD_OP_DIV_ASSIGN, 223 | ], 224 | "Basis": [ 225 | METHOD_OP_EQUALS, 226 | METHOD_OP_ADD, 227 | METHOD_OP_ADD_ASSIGN, 228 | METHOD_OP_SUB, 229 | METHOD_OP_SUB_ASSIGN, 230 | METHOD_OP_MUL, 231 | METHOD_OP_MUL_ASSIGN, 232 | ], 233 | "Quaternion": [ 234 | METHOD_OP_NEG, 235 | METHOD_OP_EQUALS, 236 | METHOD_OP_ADD, 237 | METHOD_OP_ADD_ASSIGN, 238 | METHOD_OP_SUB, 239 | METHOD_OP_SUB_ASSIGN, 240 | ], 241 | "Rect2": [METHOD_OP_EQUALS], 242 | "Transform2D": [ 243 | METHOD_OP_EQUALS, 244 | METHOD_OP_MUL, 245 | METHOD_OP_MUL_ASSIGN, 246 | ], 247 | "Color": [ 248 | METHOD_OP_NEG, 249 | METHOD_OP_EQUALS, 250 | METHOD_OP_LESS, 251 | METHOD_OP_ADD, 252 | METHOD_OP_ADD_ASSIGN, 253 | METHOD_OP_SUB, 254 | METHOD_OP_SUB_ASSIGN, 255 | METHOD_OP_MUL, 256 | METHOD_OP_MUL_ASSIGN, 257 | METHOD_OP_DIV, 258 | METHOD_OP_DIV_ASSIGN, 259 | ], 260 | "RID": [ 261 | METHOD_OP_EQUALS, 262 | METHOD_OP_LESS, 263 | METHOD_OP_LESS_EQAUL, 264 | ], 265 | "Plane": [ 266 | METHOD_OP_NEG, 267 | METHOD_OP_EQUALS, 268 | ], 269 | "AABB": [ 270 | METHOD_OP_EQUALS, 271 | ], 272 | "Transform3D": [ 273 | METHOD_OP_EQUALS, 274 | METHOD_OP_MUL, 275 | METHOD_OP_MUL_ASSIGN, 276 | ], 277 | } 278 | 279 | 280 | def apply_pattern(template, values): 281 | for key in values: 282 | template = template.replace("${" + key + "}", values[key]) 283 | return template 284 | 285 | 286 | def parse_class(cls): 287 | class_name = cls.get("name") 288 | ret = {"name": class_name} 289 | members = [] 290 | methods = [] 291 | operators = [] 292 | constants = [] 293 | ret["properties"] = members 294 | ret["methods"] = methods 295 | ret["operators"] = operators 296 | ret["constants"] = constants 297 | ret["constructor_argc"] = MAX_CONSTRUCTOR_ARGC[class_name] 298 | 299 | for m in cls.find("members") if cls.find("members") is not None else []: 300 | m_dict = dict(m.attrib) 301 | type = m_dict["type"] 302 | name = m_dict["name"] 303 | if (class_name in IGNORED_PROPS) and (name in IGNORED_PROPS[class_name]): 304 | continue 305 | if type in TYPE_MAP: 306 | type = TYPE_MAP[type] 307 | native_prop = name 308 | if class_name in PROPERTY_REMAP: 309 | if name in PROPERTY_REMAP[class_name]: 310 | native_prop = PROPERTY_REMAP[class_name][name] 311 | members.append({"name": name, "type": type, "native": native_prop}) 312 | 313 | for m in cls.find("methods") if cls.find("methods") is not None else []: 314 | m_dict = dict(m.attrib) 315 | method_name = m_dict["name"] 316 | if method_name == class_name: 317 | continue # ignore constructors 318 | if class_name in IGNORED_PROPS and method_name in IGNORED_PROPS[class_name]: 319 | continue # ignored methods 320 | if class_name == "PackedByteArray" and method_name.startswith("encode_") or method_name.startswith("decode_"): 321 | continue # ignore decode/encode methods 322 | if class_name == "PackedByteArray" and method_name == "get_string_from_wchar": 323 | continue 324 | return_type = m.find("return").attrib["type"] if m.find("return") != None else "void" 325 | if return_type in TYPE_MAP: 326 | return_type = TYPE_MAP[return_type] 327 | arguments = [] 328 | for arg in m.iter("param"): 329 | dictArg = dict(arg.attrib) 330 | if "dictArg" in dictArg: 331 | dictArg.pop("index") 332 | dictArg["default_value"] = dictArg["default"] if "default" in dictArg else None 333 | if "default" in dictArg: 334 | dictArg.pop("default") 335 | type = dictArg["type"] 336 | if type in TYPE_MAP: 337 | type = TYPE_MAP[type] 338 | arguments.append( 339 | { 340 | "type": type, 341 | "default_value": dictArg["default_value"], 342 | "has_default_value": "default" in dictArg, 343 | } 344 | ) 345 | methods.append( 346 | { 347 | "name": method_name, 348 | "native_method": method_name, 349 | "return": return_type, 350 | "arguments": arguments, 351 | } 352 | ) 353 | if class_name.startswith("Packed") and class_name.endswith("Array"): 354 | methods.append(METHOD_PACKED_ARRAY_GET) 355 | # add operator methods 356 | if class_name in OPERATOR_METHODS: 357 | for em in OPERATOR_METHODS[class_name]: 358 | operators.append(em) 359 | 360 | for c in cls.find("constants") if cls.find("constants") is not None else []: 361 | const_name = c.get("name") 362 | if class_name in IGNORED_PROPS and const_name in IGNORED_PROPS[class_name]: 363 | continue 364 | constants.append(dict(c.attrib)) 365 | return json.loads( 366 | apply_pattern( 367 | json.dumps(ret), 368 | { 369 | "class_name": class_name, 370 | }, 371 | ) 372 | ) 373 | 374 | 375 | def generate_api_json(MODULES_DIR): 376 | DOCS_DIR = os.path.abspath(os.path.join(MODULES_DIR, "../../doc/classes")) 377 | if not os.path.isdir(DOCS_DIR) and len(sys.argv) > 1: 378 | DOCS_DIR = sys.argv[-1] 379 | OUTPUT_FILE = os.path.join(MODULES_DIR, "builtin_api.gen.json") 380 | 381 | classes = [] 382 | for cls in BUILTIN_CLASSES: 383 | tree = ET.parse(open(os.path.join(DOCS_DIR, cls + ".xml"), "r")) 384 | data = tree.getroot() 385 | classes.append(parse_class(data)) 386 | json.dump(classes, open(OUTPUT_FILE, "w"), ensure_ascii=False, indent=2, sort_keys=True) 387 | 388 | 389 | if __name__ == "__main__": 390 | generate_api_json(".") 391 | -------------------------------------------------------------------------------- /icons/JavaScript.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /icons/JavaScriptModule.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /javascript.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef JAVASCRIPT_H 3 | #define JAVASCRIPT_H 4 | 5 | #include "core/io/resource_loader.h" 6 | #include "core/io/resource_saver.h" 7 | #include "core/object/script_language.h" 8 | #include "scene/resources/text_file.h" 9 | 10 | #include "javascript_binder.h" 11 | 12 | #define EXT_NAME "JavaScript" 13 | #define EXT_JSCLASS "mjs" 14 | #define EXT_TSCLASS "ts" 15 | #define EXT_JSMODULE "js" 16 | #define EXT_JSON "json" 17 | #define EXT_GENERATE "//generatedPath=" 18 | 19 | class JavaScript : public Script { 20 | GDCLASS(JavaScript, Script); 21 | 22 | private: 23 | friend class JavaScriptInstance; 24 | friend class QuickJSBinder; 25 | friend class ResourceFormatLoaderJavaScript; 26 | 27 | HashSet instances; 28 | StringName class_name; 29 | String code; 30 | String script_path; 31 | Vector bytecode; 32 | const BasicJavaScriptClassInfo *javascript_class; 33 | 34 | #ifdef TOOLS_ENABLED 35 | HashSet placeholders; 36 | virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; 37 | #endif 38 | 39 | Dictionary rpc_config; 40 | 41 | protected: 42 | void _notification(int p_what) {} 43 | static void _bind_methods(); 44 | 45 | public: 46 | virtual bool can_instantiate() const override; 47 | 48 | virtual Ref