Compare commits

..

136 Commits

Author SHA1 Message Date
David Snopek
e83fd0904c gdextension: Sync with upstream commit 876b290332ec6f2e6d173d08162a02aa7e6ca46d (4.5-stable) 2025-09-15 16:33:30 -05:00
David Snopek
d884bb1001 Merge pull request #1840 from dementive/no-std-string
Remove <string> includes in headers to improve build time
2025-09-15 11:04:51 -05:00
David Snopek
5f1a8177a5 gdextension: Sync with upstream commit 2dd26a027a99633231184616d4dd287bbdd1c0a3 (4.5-rc2) 2025-09-11 10:11:23 -05:00
dementive
e36e81ac86 Remove <string> includes in headers 2025-09-08 20:45:13 -05:00
David Snopek
24d79abcfa gdextension: Sync with upstream commit 4ebf67c12dcdffcb69242569c118a371a654b6ae (4.5-beta7) 2025-08-29 10:38:01 -05:00
David Snopek
4c78d30822 gdextension: Sync with upstream commit d5ad0556a2c04c50694b5c04dc1b3bf03ecd7113 (4.5-beta6) 2025-08-28 10:16:42 -05:00
David Snopek
449e37fa21 Merge pull request #1814 from enetheru/suffix.fix
CMake: Remove starting `.` from GODOTCPP_SUFFIX
2025-08-21 08:45:26 -05:00
David Snopek
21b73421c6 Merge pull request #1834 from dsnopek/wrapped-stringname-reference
Take reference in `Wrapped(const StringName &)`
2025-08-21 07:20:12 -05:00
David Snopek
b192b880d3 Take reference in Wrapped(const StringName &) 2025-08-20 11:13:28 -05:00
David Snopek
fd708f429b Merge pull request #1828 from BenLubar/guard-unaligned-access
Only check for Godot 4.0 if the pointer is aligned how it would be for the legacy interface.
2025-08-14 10:12:14 -05:00
David Snopek
3830fe4a40 Merge pull request #1829 from BenLubar/web-debug-symbols
Fix debug symbols logic on `platform=web` to match Godot core.
2025-08-11 07:23:53 -05:00
Ben Lubar
9ea9b4797c Fix debug symbols logic on platform=web to match Godot core. 2025-08-09 17:36:34 -05:00
Ben Lubar
05d2ce3006 Only check for Godot 4.0 if the pointer is aligned how it would be for the legacy interface. 2025-08-09 12:19:21 -05:00
David Snopek
1421ba26ad gdextension: Sync with upstream commit c81fd6c51233a727da528cf7f74137d56b5d6efe (4.5-beta5) 2025-08-08 06:50:17 -05:00
David Snopek
e0c0c566a6 Merge pull request #1826 from bruvzg/sync_android_vers
Sync Android SDK and NDK versions with the engine.
2025-08-07 08:11:50 -05:00
Pāvels Nadtočajevs
8646cd31b5 Sync Android SDK and NDK versions with the engine. 2025-08-06 22:48:13 +03:00
David Snopek
e53489bbbe Merge pull request #1824 from Klaim/patch-1
fix: missing `type_traits` include
2025-08-05 08:39:37 -05:00
Klaim (Joël Lamotte)
fbe5262d7b fix: missing type_traits include
Usage of `std::is_trivially_constructible` in `defs.hpp` requires including `type_traits`. This missing include leads to errors about that type not being found when building with clang++-22 with libc++-22.
2025-08-04 15:49:36 +02:00
David Snopek
cb3ad55873 gdextension: Sync with upstream commit 2d113cc224cb9be07866d003819fcef2226a52ea (4.5-beta4) 2025-08-01 09:52:19 -05:00
David Snopek
4f80491c8c Merge pull request #1818 from dsnopek/test-internal-classes
Test that internal classes work as expected
2025-07-23 16:52:19 -05:00
David Snopek
a2b6f91dbc Merge pull request #1817 from Naros/GH-1816
Reintroduce Math_INF and Math_NAN defines
2025-07-23 14:12:56 -05:00
David Snopek
309b17b6eb Test that internal classes work as expected 2025-07-23 13:53:52 -05:00
David Snopek
134e8b756d Merge pull request #1819 from dsnopek/fix-custom-api-file-scons-401
Fix `custom_api_file` with SCons 4.0.1
2025-07-19 06:57:30 -05:00
David Snopek
8e7dfbc71a Fix custom_api_file with SCons 4.0.1 2025-07-17 09:03:11 -05:00
Chris Cranford
6a21f76c4d Reintroduce Math_INF and Math_NAN defines 2025-07-13 00:08:50 -04:00
Samuel Nicholas
b64b941adf CMake: Add GODOTCPP_SUFFIX_GENEX variable
This is the same as GODOTCPP_SUFFIX but without the leading '.'
GODOTCPP_SUFFIX is  then based on the above.
2025-07-11 11:30:34 +09:30
David Snopek
8bb931c6a9 gdextension: Sync with upstream commit 4d1f26e1fd1fa46f2223fe0b6ac300744bf79b88 (4.5-beta3) 2025-07-10 15:40:04 -05:00
David Snopek
6a870949a5 Merge pull request #1669 from Ivorforce/scons-variant_dir-support
Add SCons variant_dir support
2025-07-03 12:17:32 -05:00
David Snopek
f129db3e3d gdextension: Sync with upstream commit e1b4101e3460dd9c6ba0b7f8d88e9751b8383f5b (4.5-beta2) 2025-07-02 06:42:30 -05:00
David Snopek
c943beb4f4 Merge pull request #1795 from dsnopek/scons-dependency-on-build-profile
Files generated by SCons should depend on the `build_profile` (if given)
2025-06-25 08:57:38 -05:00
David Snopek
c45c4aa667 Merge pull request #1804 from dsnopek/github-actions-windows-2019
Update CI to use `windows-2022`
2025-06-24 16:30:44 -05:00
David Snopek
8938e7e4e3 Update CI to use windows-2022 2025-06-24 14:47:40 -05:00
David Snopek
75f95ffbcb Merge pull request #1792 from dsnopek/gdextension-interface-45
Update for GDExtension interface changes in Godot 4.5
2025-06-24 12:27:34 -05:00
David Snopek
7f5f02940d Update for GDExtension interface changes in Godot 4.5 2025-06-23 16:40:43 -05:00
David Snopek
3afe0d53c4 Merge pull request #1799 from dsnopek/disable-double-precision-in-ci
Disable double precisions builds in CI for now
2025-06-22 07:27:29 -05:00
David Snopek
b46c31a50e Disable double precisions builds in CI 2025-06-20 12:23:49 -05:00
David Snopek
61f52cb328 gdextension: Sync with upstream commit 46c495ca21f40f57a7fb9c7cde6143738f1652d4 (4.5-beta1) 2025-06-20 12:04:19 -05:00
David Snopek
835a3abeea Merge pull request #1796 from enetheru/ci-change_detection
[GitHub CI] Fix source detection, added missing include .hpp and .inc to detection rules.
2025-06-20 12:01:56 -05:00
David Snopek
e17a5a78d1 Merge pull request #1794 from bruvzg/fix_typed_dict_ref
Fix binding generation for `TypedArray`/`TypedDictionary` with refcounted elements.
2025-06-20 12:01:45 -05:00
David Snopek
5a0d6565d1 Merge pull request #1773 from tomfull123/method-bind-clean-up
Clean up the MethodBind class
2025-06-20 12:01:26 -05:00
Samuel Nicholas
6d11a780bf added missing include .hpp and .inc detection
removed redundant .py detection.
2025-06-19 10:24:48 +09:30
David Snopek
646ccdf470 Files generated by SCons should depend on the build_profile (if given) 2025-06-18 14:43:12 -05:00
Pāvels Nadtočajevs
ed53a70e71 Fix binding generation for TypedArray/TypedDictionary with refcounted elements. 2025-06-18 13:18:37 +03:00
David Snopek
5cbffab4c6 Merge pull request #1780 from piiertho/expose-object-set-script-instance
Expose gdextension_object_get_script_instance method from engine
2025-06-16 08:25:44 -05:00
David Snopek
86e32cef4a Merge pull request #1786 from marcmarmir/CMake-message-improvement
Fix: Add STATUS to CMake message commands missing them
2025-06-10 07:02:37 -05:00
David Snopek
c8053dfa34 Merge pull request #1790 from MJacred/patch-2
Fix URL to gdextension cpp example in the official docs
2025-06-09 07:23:47 -05:00
MJacred
f25c4df5c4 Fix URL to gdextension cpp example in the official docs 2025-06-09 11:49:03 +02:00
David Snopek
fef59ff89a Merge pull request #1779 from Ivorforce/ndk-version
Make ndk version configurable as a command-like argument.
2025-06-07 14:26:45 -05:00
David Snopek
a7127d3ec7 Merge pull request #1771 from tomfull123/array-constructor-crash
Fix array constructor crash
2025-06-07 14:20:01 -05:00
David Snopek
dde6663d33 Merge pull request #1785 from dgcole/master
Fix CMake double precision builds
2025-06-07 14:14:20 -05:00
David Snopek
dc9ac508f4 Merge pull request #1777 from Repiteo/ci/windows-utf8
CI: Ensure utf-8 support on Windows GHA
2025-06-07 14:13:30 -05:00
David Snopek
d5baa7071e Merge pull request #1757 from Repiteo/ci/version-bumps
CI: Various version bumps; sync with main repo
2025-06-07 14:13:14 -05:00
marcin.mirski
0c2e66e414 Improve CMAKE_BUILD_PARALLEL_LEVEL message 2025-06-05 11:48:03 -07:00
marcin.mirski
8eac097c37 Fix: Add STATUS to CMake message commands missing them 2025-06-04 16:54:45 -07:00
Dyllan Cole
4824aa41e8 Fix incorrect binding_generator_generate_bindings variable names 2025-05-31 19:23:50 -04:00
David Snopek
af4f05ec7e Merge pull request #1783 from Faless/fix/ios_sdk_version_link_flags
fix: Add iOS min SDK version link flags
2025-05-27 16:25:19 -05:00
Fabio Alessandrelli
4879eb7bd0 fix: Add iOS min SDK version link flags
This is required when publishing to the App Store, and consistent with
what we already do for the macOS deployment target.
2025-05-21 16:34:27 +02:00
Pierre-Thomas Meisels
0871c7a93a Expose gdextension_object_get_script_instance and gdextension_object_set_script_instance methods from engine 2025-05-05 18:55:59 +02:00
David Snopek
681fb04f7a Merge pull request #1755 from dsnopek/not-experimental-any-more
Stop referring to GDExtension as experimental in the README
2025-05-02 12:13:13 -05:00
Lukas Tenbrink
16e47d7ae5 Make ndk version configurable as a command-like argument. 2025-05-02 17:12:32 +02:00
David Snopek
543c1f7156 Merge pull request #1774 from BenLubar/unintended-copy
Fix ClassDB iterators making unintended copies
2025-04-29 16:19:58 -05:00
David Snopek
5a16059512 Merge pull request #1776 from dsnopek/fix-default-to-string
Fix classes without `_to_string()` always returning `"[Wrapped:0]"`
2025-04-26 13:39:59 -05:00
Thaddeus Crews
42f6dc6d49 CI: Ensure utf-8 support on Windows GHA 2025-04-26 12:29:50 -05:00
Thaddeus Crews
64cdf089d9 CI: Various version bumps; sync with main repo 2025-04-26 12:23:07 -05:00
David Snopek
f38c056b67 Fix classes without _to_string() always returning "[Wrapped:0]" 2025-04-25 15:54:41 -05:00
Ben Lubar
7fd0999b3c fix iterators making unintended copies 2025-04-21 18:45:05 -05:00
Tom
ca5af3c861 Cleaned up the MethodBind class 2025-04-20 20:47:06 +01:00
David Snopek
08fd033a9e Merge pull request #1743 from dsnopek/get-used-classes
Register the classes used with the Godot editor
2025-04-18 06:56:23 -05:00
David Snopek
195188f321 Merge pull request #1769 from enetheru/defs
CMake: Match #1758 move of DEBUG_METHODS_ENABLED from build options to defs.hpp
2025-04-17 07:41:48 -05:00
Samuel Nicholas
b195a51c6c Match #1758 build option changes
d634a5f8c4 (diff-e2225522e55739f1533a3ce9eee58324ac9c192c8ba30065067964347d22fdacL471)
2025-04-17 08:46:58 +09:30
David Snopek
2a8d218f12 Merge pull request #1756 from Repiteo/scons/external-includes
SCons: Add `CPPEXTPATH` for external includes
2025-04-16 16:10:45 -05:00
David Snopek
70d8ff0c47 Merge pull request #1770 from Zylann/basis_abs
Use Math::abs to avoid ambiguity with integer abs
2025-04-16 16:10:07 -05:00
Tom
ddd4f2513c Fixed a crash with an Array constructor 2025-04-16 20:30:15 +01:00
Marc Gilleron
7670de814f Use Math::abs to avoid ambiguity with integer abs 2025-04-16 20:37:19 +02:00
David Snopek
321af5b827 Merge pull request #1768 from enetheru/sccache_update
CI: bump of mozilla-sccache action to 0.0.9
2025-04-16 08:33:20 -05:00
Samuel Nicholas
bbbcc6adc7 version bump of mozilla-sccache action to 0.0.9
https://github.blog/changelog/2025-03-20-notification-of-upcoming-breaking-changes-in-github-actions/#decommissioned-cache-service-brownouts
2025-04-16 10:31:50 +09:30
David Snopek
62a5c609d3 Merge pull request #1763 from Grublady/typeddict
Fix TypedDictionary binding generation
2025-04-15 11:21:40 -05:00
David Snopek
97ad05beeb Merge pull request #1758 from tomfull123/sync-defs
Sync defs
2025-04-15 11:02:10 -05:00
David Snopek
94a8fad88c Merge pull request #1767 from Zylann/quaterion_abs
Use Math::abs to avoid ambiguity with integer abs
2025-04-15 08:12:53 -05:00
Marc Gilleron
7e6c9c9370 Use Math::abs to avoid ambiguity with integer abs 2025-04-14 23:46:47 +02:00
Grublady
26201dd27a Fix TypedDictionary binding generation 2025-04-08 20:34:29 -04:00
Tom
d634a5f8c4 Synced defs.hpp with godot's typedefs.h 2025-04-07 17:30:55 +01:00
David Snopek
c173cc0159 Merge pull request #1761 from enetheru/CI_compat_fix
Fix compatibility break for CI action 'setup-godot-cpp'
2025-04-07 07:09:36 -05:00
Samuel Nicholas
38e517b98b Fix compatibility break for CI 2025-04-07 08:10:16 +09:30
David Snopek
478e2637bd Merge pull request #1716 from tomfull123/master
Add support for `initializer_list` to Array and TypedArray
2025-04-05 10:32:18 -05:00
David Snopek
1163d1b4a8 Merge pull request #1750 from tomfull123/typed-dictionary-initializer-support
Typed dictionary initializer support
2025-04-05 10:32:06 -05:00
David Snopek
096d9056f0 Merge pull request #1760 from Calinou/update-test-project-4.4
Update test project to Godot 4.4
2025-04-05 10:31:50 -05:00
David Snopek
7888c15233 Merge pull request #1726 from enetheru/continuous_integration
Update CI with new CMake builds.
2025-04-05 10:03:49 -05:00
Samuel Nicholas
b6c0251296 CMake: Update CI
- Duplicated the ci.yml into ci-scons.yml and ci-cmake.yml
- Replaced some manual shell commands to detect changes with  tj-actions/changed-files@v45
- Conditionally run the CI depending on what files change.
- Add ios toolchain from leetal/ios-cmake
- Added a cmake-minimum of 3.10 to silence errors from ios toolchain
2025-04-05 13:31:52 +10:30
Thaddeus Crews
30bfa6f215 SCons: Add CPPEXTPATH for external includes 2025-04-04 09:39:47 -05:00
David Snopek
7660dd28b3 Stop referring to GDExtension as experimental in the README 2025-04-04 09:11:54 -05:00
Tom
335b490061 Added initialiser list support to TypedDictionary 2025-04-03 23:16:12 +01:00
Hugo Locurcio
552a74c96e Update test project to Godot 4.4 2025-04-03 16:40:19 +02:00
Tom
946a693859 . 2025-04-02 19:58:05 +01:00
David Snopek
da064d84d2 Merge pull request #1717 from tomfull123/typed-array-range-based-loop-support
Add support for range based loops for Array
2025-04-02 13:00:38 -05:00
David Snopek
c26e7c9734 Merge pull request #1754 from tomfull123/typed-dictionary-compilation-errors
Add method_ptrcall header include to type_info to fix compiler errors
2025-04-02 12:59:51 -05:00
David Snopek
d72baf192d Merge pull request #1742 from aaronfranke/projection-construct
Add missing Projection constructor with 16 `real_t` values
2025-04-02 12:59:14 -05:00
David Snopek
c2d688bae6 Merge pull request #1747 from unvermuthet/linux-use-static-cpp
Implement `use_static_cpp` flag for Linux
2025-04-02 12:59:04 -05:00
unvermuthet
b0f41909e0 Implement use_static_cpp flag for Linux 2025-04-01 22:35:40 +02:00
Tom
a2c37f8a16 Made the Array's ptr and ptrw methods private 2025-04-01 20:47:35 +01:00
Tom
7ffaecce8c Add method_ptrcall header include to type_info to fix compiler errors 2025-04-01 20:35:19 +01:00
David Snopek
f3deed0270 Merge pull request #1753 from dsnopek/stack-smashing-char-types
Fix stack smashing when Godot methods return `char32_t`, `char16_t` or `wchar_t`
2025-04-01 09:26:42 -05:00
David Snopek
035add9d4f Fix stack smashing when Godot methods return char32_t, char16_t or wchar_t 2025-03-28 07:41:25 -05:00
David Snopek
f088bc9b25 Merge pull request #1752 from bruvzg/rem_libs
[macOS] Remove unnecessary Cocoa reference.
2025-03-28 07:17:53 -05:00
Pāvels Nadtočajevs
d239da3221 [macOS] Remove unnecessary Cocoa reference. 2025-03-28 08:45:43 +02:00
David Snopek
aed195f6dc Register the classes used with the Godot editor 2025-03-17 13:23:32 -05:00
David Snopek
f08e781b0b Merge pull request #1718 from dsnopek/godot-sync-pre44-templates
Synchronize most shared template code with Godot 4.4
2025-03-14 14:13:31 -05:00
David Snopek
2b4802d0a8 Merge pull request #1715 from dsnopek/godot-sync-pre44
Synchronize most shared variant code with Godot 4.4
2025-03-14 14:13:21 -05:00
David Snopek
075b517d96 Synchronize most shared variant code with Godot 4.4 2025-03-14 11:39:56 -05:00
David Snopek
1edfca295b Synchronize most shared template code with Godot 4.4 2025-03-14 11:33:10 -05:00
David Snopek
67ca2fbbad Merge pull request #1740 from enetheru/privatise
CMake: public/private flags
2025-03-14 09:20:46 -05:00
David Snopek
654de13b5c Merge pull request #1702 from zhmt/master
binding_generator.py: Don't error if directory already exists
2025-03-14 08:56:30 -05:00
David Snopek
e4bd867056 Merge pull request #1730 from enetheru/XCode
CMake: XCode dependency chain fixes
2025-03-14 07:34:36 -05:00
Aaron Franke
aa03c32b3e Add missing Projection constructor with 16 real_t values 2025-03-14 02:46:23 -07:00
zhmt
d79959c79e binding_generator.py: Don't error if directory already exists
It should be ok when folders exist. Exception shouldn't be thrown.

Update binding_generator.py

It should be ok when folds exist. It will fail to build without this patch,  in vs code on windows with compiler ( visual studio community 2022 amd 64) .

Co-Authored-By: Chris Cranford <ccranfor@redhat.com>
2025-03-14 14:02:53 +08:00
Samuel Nicholas
5eb16d0c5b CMake: public/private flags
Made all warnings private.
Warning as error private
Consistency in  generator expressions
2025-03-14 11:11:15 +10:30
Samuel Nicholas
f83f364144 CMake: XCode dependency chain fixes - remastered
When attempting to generate XCode projects it would fail due to the target dependency chain not meeting expectations.

This PR, adds the required dependency infomation so that the XCode generator works.
2025-03-14 10:10:33 +10:30
David Snopek
6f981b33cc Merge pull request #1704 from BenLubar/missing-braces
Fix -Wmissing-braces warning (included in -Wall) in array constructor for generated function call bindings
2025-03-13 12:45:03 -05:00
David Snopek
d8807a10d6 Merge pull request #1734 from Repiteo/style/pragma-once
Replace header guards style with `#pragma once`
2025-03-13 11:47:14 -05:00
David Snopek
a5db125d2e Merge pull request #1714 from dsnopek/extension-api-precision
Check that precision of `extension_api.json` matches build options
2025-03-13 11:43:30 -05:00
David Snopek
9f02db1eb8 Merge pull request #1733 from enetheru/single_target_test
CMake: Revert to single cmake target
2025-03-13 11:42:15 -05:00
David Snopek
0b6350dd29 Merge pull request #1738 from ytnuf/exception
Remove unnecessary forced -fno-exceptions for web builds
2025-03-13 11:40:40 -05:00
Samuel Nicholas
89abe15268 CMake: Target as configuration option
Add GODOTCPP_TARGET configuration option
Remove loop to generate the godot-cpp.<target> CMake Targets

Rename test bindings target
Update documentation
2025-03-12 08:58:59 +10:30
ytnuf
43690cb60b Remove unnecessary forced -fno-exceptions for web builds
The SCons build doesn't do this, so neither should CMake
Excpetions are already handled by DISABLE_EXCEPTIONS option
2025-03-10 13:33:56 +00:00
Thaddeus Crews
c963321cdd Ignore #pragma once commit 2025-03-07 17:58:27 -06:00
Thaddeus Crews
7056c996dd Style: Replace header guards with #pragma once 2025-03-07 17:58:10 -06:00
Thaddeus Crews
107cb1da5e Style: Integrate #pragma once in builders/checks 2025-03-07 17:57:16 -06:00
David Snopek
a3f89217df Merge pull request #1723 from enetheru/comments
CMake: Comment Cleanup
2025-03-06 08:21:53 -06:00
David Snopek
55cbea7435 Merge pull request #1728 from enetheru/default_target
CMake: template_debug as default target when godot-cpp is top level
2025-03-06 08:21:29 -06:00
Samuel Nicholas
8b33e73353 CMake: default target when godot-cpp is top level
People seem to want to build godot-cpp without any arguments, not even specifying a target.

We have to detect if we are top level though because it conflicts with being consumed.
2025-03-07 00:04:36 +10:30
Samuel Nicholas
671e309cfa Updating commenting to be consistent 2025-03-06 23:57:02 +10:30
David Snopek
05f5d73876 Merge pull request #1722 from enetheru/gersemi
CMake: Pre-Commit Hook to Gersemi for auto-formatting
2025-03-06 06:42:51 -06:00
Samuel Nicholas
2f6d7f2dad add gersemi to pre-commit hooks for CMake formatting like black 2025-03-04 13:58:39 +10:30
David Snopek
0a73df5f53 Check that precision of extension_api.json matches build options 2025-02-27 13:27:11 -06:00
Ben Lubar
a353be57d8 Fix -Wmissing-braces warning (included in -Wall) in array constructor for generated function call bindings 2025-02-09 17:20:06 -06:00
Cedric Shock
1345c46650 Add SCons variant_dir support, which allows specifying a target build directory. 2025-01-12 18:32:59 +01:00
35 changed files with 15128 additions and 1743 deletions

View File

@@ -20,7 +20,7 @@ inputs:
default: 12.2.0
description: MinGW version.
ndk-version:
default: r23c
default: r28b
description: Android NDK version.
buildtool:
default: scons

View File

@@ -73,8 +73,8 @@ jobs:
platform: android
config-flags:
-G Ninja -DCMAKE_BUILD_TYPE=Release
--toolchain ${ANDROID_HOME}/ndk/23.2.8568313/build/cmake/android.toolchain.cmake
-DANDROID_PLATFORM=21 -DANDROID_ABI=arm64-v8a
--toolchain ${ANDROID_HOME}/ndk/28.1.13356709/build/cmake/android.toolchain.cmake
-DANDROID_PLATFORM=24 -DANDROID_ABI=arm64-v8a
artifact-name: godot-cpp-android-arm64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64

View File

@@ -21,8 +21,7 @@ compromises need to be made to resolve those differences.
As we are attempting to maintain feature parity, and ease of maintenance, these
CMake scripts are built to resemble the SCons build system wherever possible.
Where they are not, we will attempt to document common difference in
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
and platform specific differences in their respective
doc/cmake.rst and platform specific differences in their respective
cmake/<platform>.cmake file.
The file structure and file content are made to match, if not in content then

View File

@@ -7,7 +7,6 @@
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.5`](https://github.com/godotengine/godot-cpp/tree/4.5)
> - [`4.4`](https://github.com/godotengine/godot-cpp/tree/4.4)
> - [`4.3`](https://github.com/godotengine/godot-cpp/tree/4.3)
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
@@ -63,11 +62,15 @@ See [Updating your GDExtension for 4.1](https://docs.godotengine.org/en/latest/t
## Contributing
We greatly appreciate help in maintaining and extending this project. If you
wish to help out, please visit the [godot-cpp section of the Contributing docs](https://contributing.godotengine.org/en/latest/other/godot-cpp.html).
wish to help out, ensure you have an account on GitHub and create a "fork" of
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
for instructions.
Please install clang-format and the [pre-commit](https://pre-commit.com/) Python framework so formatting is done before your changes are submitted. See the [code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#pre-commit-hook) for instructions.
## Getting started
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/engine_details/development/compiling/index.html).
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/index.html#building-for-target-platforms).
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.

View File

@@ -97,7 +97,7 @@ def generate_virtual_version(argcount, const=False, returns=False, required=Fals
sproto = str(argcount)
method_info = ""
method_flags = "::godot::MethodFlags::METHOD_FLAG_VIRTUAL"
method_flags = "METHOD_FLAG_VIRTUAL"
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret,")
@@ -110,14 +110,14 @@ def generate_virtual_version(argcount, const=False, returns=False, required=Fals
if const:
sproto += "C"
method_flags += " | ::godot::MethodFlags::METHOD_FLAG_CONST"
method_flags += " | METHOD_FLAG_CONST"
s = s.replace("$CONST", "const")
else:
s = s.replace("$CONST ", "")
if required:
sproto += "_REQUIRED"
method_flags += " | ::godot::MethodFlags::METHOD_FLAG_VIRTUAL_REQUIRED"
method_flags += " | METHOD_FLAG_VIRTUAL_REQUIRED"
s = s.replace(
"$REQCHECK",
'ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");',
@@ -911,7 +911,6 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("\tconst Variant &operator[](int64_t p_index) const;")
result.append("\tVariant &operator[](int64_t p_index);")
result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);")
result.append("\tvoid _ref(const Array &p_from) const;")
result.append("""
struct Iterator {
_FORCE_INLINE_ Variant &operator*() const;
@@ -2503,7 +2502,7 @@ def make_varargs_template(
function_signature += " {"
result.append(function_signature)
args_array = f"\tstd::array<Variant, {len(method_arguments)} + sizeof...(Args)> variant_args{{ "
args_array = f"\tstd::array<Variant, {len(method_arguments)} + sizeof...(Args)> variant_args{{{{ "
for argument in method_arguments:
if argument["type"] == "Variant":
args_array += escape_argument(argument["name"])
@@ -2511,7 +2510,7 @@ def make_varargs_template(
args_array += f"Variant({escape_argument(argument['name'])})"
args_array += ", "
args_array += "Variant(p_args)... };"
args_array += "Variant(p_args)... }};"
result.append(args_array)
result.append(f"\tstd::array<const Variant *, {len(method_arguments)} + sizeof...(Args)> call_args;")
result.append("\tfor (size_t i = 0; i < variant_args.size(); i++) {")
@@ -2746,12 +2745,12 @@ def correct_typed_dictionary(type_name):
def correct_type(type_name, meta=None, use_alias=True):
type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"}
if meta is not None:
if meta in ["int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"]:
if "int" in meta:
return f"{meta}_t"
elif meta in ["float", "double"]:
elif "char" in meta:
return f"{meta}_t"
else:
return meta
elif meta in ["char16", "char32"]:
return f"{meta}_t"
if type_name in type_conversion:
return type_conversion[type_name]
if type_name.startswith("typedarray::"):

View File

@@ -22,7 +22,7 @@ Android platforms.
.. _built-in support:https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android
There is further information and examples in the docs: https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
There is further information and examples in the doc/cmake.rst file.
]=======================================================================]
@@ -30,11 +30,11 @@ There is further information and examples in the docs: https://docs.godotengine.
function(android_options)
#[[ Options from SCons
The options below are managed by CMake toolchain files, the docs have more information:
https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
The options below are managed by CMake toolchain files, doc.cmake.rst has
more information
android_api_level : Target Android API level.
Default = 21
Default = 24
ANDROID_HOME : Path to your Android SDK installation.
Default = os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")

View File

@@ -66,6 +66,9 @@ function(common_compiler_flags)
# The public flag tells CMake that the following options are transient,
# and will propagate to consumers.
PUBLIC
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
$<${DISABLE_EXCEPTIONS}:$<${NOT_MSVC}:-fno-exceptions>>
# Enabling Debug Symbols
$<${DEBUG_SYMBOLS}:
@@ -92,9 +95,6 @@ function(common_compiler_flags)
# Warnings below, these do not need to propagate to consumers.
PRIVATE
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
$<${DISABLE_EXCEPTIONS}:$<${NOT_MSVC}:-fno-exceptions>>
$<${IS_MSVC}:
/W4 # Warning level 4 (informational) warnings that aren't off by default.

View File

@@ -12,10 +12,9 @@ function(linux_options)
#[[ Options from SCons
use_llvm : Use the LLVM compiler
Not implemented as compiler selection is managed by CMake. Look to
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
doc/cmake.rst for examples.
]]
option(GODOTCPP_USE_STATIC_CPP "Link libgcc and libstdc++ statically for better portability" OFF)
option(GODOTCPP_USE_STATIC_CPP "Link libgcc and libstdc++ statically for better portability" ON)
endfunction()
#[===========================[ Target Generation ]===========================]

View File

@@ -21,7 +21,7 @@ function(web_generate)
target_compile_options(
godot-cpp
PUBLIC #
-sSIDE_MODULE=1
-sSIDE_MODULE
-sSUPPORT_LONGJMP=wasm
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
@@ -33,7 +33,6 @@ function(web_generate)
-sSUPPORT_LONGJMP=wasm
-fvisibility=hidden
-shared
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
common_compiler_flags()

View File

@@ -62,9 +62,7 @@ function(windows_options)
Default: True
These three options will not implemented as compiler selection is managed
by CMake toolchain files. Look to the docs
(https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
by CMake toolchain files. Look to doc/cmake.rst for examples.
use_mingw: Use the MinGW compiler instead of MSVC - only effective on Windows
use_llvm: Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag
mingw_prefix: MinGW prefix

353
doc/cmake.rst Normal file
View File

@@ -0,0 +1,353 @@
CMake
=====
.. warning::
The CMake scripts do not have feature parity with the SCons ones at this
stage and are still a work in progress. There are a number of people who
have been working on alternative CMake solutions that are frequently
referenced in the discord chats: Ivan's cmake-rewrite_ branch and
Vorlac's godot-roguelite_ Project
.. _cmake-rewrite: https://github.com/IvanInventor/godot-cpp/tree/cmake-rewrite
.. _godot-roguelite: https://github.com/vorlac/godot-roguelite
Introduction
------------
Compiling godot-cpp independently of an extension project is mainly for
godot-cpp developers, package maintainers, and CI/CD. Look to the
godot-cpp-template_ for a practical example on how to consume the godot-cpp
library as part of a Godot extension.
Configuration examples are listed at the bottom of the page.
.. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template
Debug vs template_debug
-----------------------
Something I've seen come up many times is the conflation of a compilation of c++
source code with debug symbols enabled, and compiling a Godot extension with
debug features enabled. The two concepts are not mutually inclusive.
- debug_features
Enables a pre-processor definition to selectively compile code to help
users of a Godot extension with their own project.
debug features are enabled in editor and template_debug builds, which can be specified during the configure phase like so
``cmake -S . -B cmake-build -DGODOTCPP_TARGET=<target choice>``
- Debug
Sets compiler flags so that debug symbols are generated to help godot
extension developers debug their extension.
``Debug`` is the default build type for CMake projects, to select another it depends on the generator used
For single configuration generators, add to the configure command:
``-DCMAKE_BUILD_TYPE=<type>``
For multi-config generators add to the build command:
``--config <type>``
where ``<type>`` is one of ``Debug``, ``Release``, ``RelWithDebInfo``, ``MinSizeRel``
SCons Deviations
----------------
Not everything from SCons can be perfectly representable in CMake, here are
the notable differences.
- debug_symbols
No longer has an explicit option, and is enabled via Debug-like CMake
build configurations; ``Debug``, ``RelWithDebInfo``.
- dev_build
Does not define ``NDEBUG`` when disabled, ``NDEBUG`` is set via Release-like
CMake build configurations; ``Release``, ``MinSizeRel``.
- arch
CMake sets the architecture via the toolchain files, macos universal is controlled vua the ``CMAKE_OSX_ARCHITECTURES``
property which is copied to targets when they are defined.
- debug_crt
CMake controls linking to windows runtime libraries by copying the value of ``CMAKE_MSVC_RUNTIME_LIBRARIES`` to targets as they are defined.
godot-cpp will set this variable if it isn't already set. so include it before other dependencies to have the value propagate across the projects.
Testing Integration
-------------------
The testing target ``godot-cpp-test`` is guarded by ``GODOTCPP_ENABLE_TESTING`` which is off by default.
To configure and build the godot-cpp project to enable the integration
testing targets the command will look something like:
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build -DGODOTCPP_ENABLE_TESTING=YES
cmake --build cmake-build --target godot-cpp-test
Basic walkthrough
-----------------
.. topic:: Clone the git repository
.. code-block::
git clone https://github.com/godotengine/godot-cpp.git
Cloning into 'godot-cpp'...
...
cd godot-cpp
.. topic:: Options
To list the available options CMake use the ``-L[AH]`` option. ``A`` is for
advanced, and ``H`` is for help strings.
.. code-block::
cmake .. -LH
Options are specified on the command line when configuring eg.
.. code-block::
cmake .. -DGODOTCPP_USE_HOT_RELOAD:BOOL=ON \
-DGODOTCPP_PRECISION:STRING=double \
-DCMAKE_BUILD_TYPE:STRING=Debug
Review setting-build-variables_ and build-configurations_ for more information.
.. _setting-build-variables: https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables
.. _build-configurations: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations
A non-exhaustive list of options:
.. code-block::
// Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )
`GODOTCPP_CUSTOM_API_FILE:FILEPATH=`
// Force disabling exception handling code (ON|OFF)
GODOTCPP_DISABLE_EXCEPTIONS:BOOL=ON
// Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )
GODOTCPP_GDEXTENSION_DIR:PATH=gdextension
// Set the floating-point precision level (single|double)
GODOTCPP_PRECISION:STRING=single
// Enable the extra accounting required to support hot reload. (ON|OFF)
GODOTCPP_USE_HOT_RELOAD:BOOL=
.. topic:: Configure the build
.. code-block::
cmake -S . -B cmake-build -G Ninja
``-S .`` Specifies the source directory
``-B cmake-build`` Specifies the build directory
``-G Ninja`` Specifies the Generator
The source directory in this example is the source code for godot-cpp.
The build directory is so that generated files do not clutter up the source tree.
CMake doesn't build the code, it generates the files that another tool uses
to build the code, in this case Ninja.
To see the list of generators run ``cmake --help``.
.. topic:: Compiling
Tell cmake to invoke the build system it generated in the specified directory.
The default target is template_debug and the default build configuration is Debug.
.. code-block::
cmake --build cmake-build
Examples
--------
Windows and MSVC - Release
~~~~~~~~~~~~~~~~~~~~~~~~~~
So long as CMake is installed from the `CMake Downloads`_ page and in the PATH,
and Microsoft Visual Studio is installed with c++ support, CMake will detect
the MSVC compiler.
Note that Visual Studio is a Multi-Config Generator so the build configuration
needs to be specified at build time ie ``--config Release``
.. _CMake downloads: https://cmake.org/download/
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build -DGODOTCPP_ENABLE_TESTING=YES
cmake --build cmake-build -t godot-cpp-test --config Release
MSys2/clang64, "Ninja" - Debug
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assumes the ming-w64-clang-x86_64-toolchain is installed
Note that Ninja is a Single-Config Generator so the build type
needs to be specified at Configure time.
Using the msys2/clang64 shell
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build -G"Ninja" -DGODOTCPP_ENABLE_TESTING=YES -DCMAKE_BUILD_TYPE=Release
cmake --build cmake-build -t godot-cpp-test
MSys2/clang64, "Ninja Multi-Config" - dev_build, Debug Symbols
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assumes the ming-w64-clang-x86_64-toolchain is installed
This time we are choosing the 'Ninja Multi-Config' generator, so the build
type is specified at build time.
Using the msys2/clang64 shell
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build -G"Ninja Multi-Config" -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_DEV_BUILD:BOOL=ON
cmake --build cmake-build -t godot-cpp-test --config Debug
Emscripten for web platform
~~~~~~~~~~~~~~~~~~~~~~~~~~~
I've only tested this on windows so far.
I cloned and installed the latest Emscripten tools to ``c:\emsdk``
At the time of writing that was v3.1.69
I've been using ``C:\emsdk\emsdk.ps1 activate latest`` to enable the
environment from powershell in the current shell.
The ``emcmake.bat`` utility adds the emscripten toolchain to the CMake command
It can also be added manually, the location is listed inside the emcmake.bat file
.. code-block::
# Assuming our current directory is the godot-cpp source root
C:\emsdk\emsdk.ps1 activate latest
emcmake.bat cmake -S . -B cmake-build-web -DCMAKE_BUILD_TYPE=Release
cmake --build cmake-build-web
Android Cross Compile from Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are two separate paths you can choose when configuring for android.
Use the ``CMAKE_ANDROID_*`` variables specified on the commandline or in your
own toolchain file as listed in the cmake-toolchains_ documentation
.. _cmake-toolchains: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk
Or use the toolchain and scripts provided by the Android SDK and make changes
using the ``ANDROID_*`` variables listed there. Where ``<version>`` is whatever
ndk version you have installed (tested with `28.1.13356709`) and ``<platform>``
is for android sdk platform, (tested with ``android-29``)
.. warning::
The Android SDK website explicitly states that they do not support using
the CMake built-in method, and recommends you stick with their toolchain
files.
.. topic:: Using your own toolchain file as described in the CMake documentation
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build --toolchain my_toolchain.cmake
cmake --build cmake-build -t template_release
Doing the equivalent on just using the command line
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=<platform> \
-DCMAKE_ANDROID_ARCH_ABI=<arch> \
-DCMAKE_ANDROID_NDK=/path/to/android-ndk
cmake --build cmake-build
.. topic:: Using the toolchain file from the Android SDK
Defaults to minimum supported version( android-16 in my case) and armv7-a.
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build --toolchain $ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake
cmake --build cmake-build
Specify Android platform and ABI
.. code-block::
# Assuming our current directory is the godot-cpp source root
cmake -S . -B cmake-build --toolchain $ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake \
-DANDROID_PLATFORM:STRING=android-29 \
-DANDROID_ABI:STRING=armeabi-v7a
cmake --build cmake-build
Toolchains
----------
This section attempts to list the host and target combinations that have been
at tested.
Linux Host
~~~~~~~~~~
Macos Host
~~~~~~~~~~
:System: Mac Mini
:OS Name: Sequoia 15.0.1
:Processor: Apple M2
* AppleClang
Windows Host
~~~~~~~~~~~~
:OS Name: Windows 11
:Processor: AMD Ryzen 7 6800HS Creator Edition
* `Microsoft Visual Studio 17 2022 <https://visualstudio.microsoft.com/vs/>`_
* `LLVM <https://llvm.org/>`_
* `LLVM-MinGW <https://github.com/mstorsjo/llvm-mingw/releases>`_
* aarch64-w64-mingw32
* armv7-w64-mingw32
* i686-w64-mingw32
* x86_64-w64-mingw32
* `AndroidSDK <https://developer.android.com/studio/#command-tools>`_
* `Emscripten <https://emscripten.org/>`_
* `MinGW-W64-builds <https://github.com/niXman/mingw-builds-binaries/releases>`_
* `Jetbrains-CLion <https://www.jetbrains.com/clion/>`_
Jetbrains builtin compiler is just the MingW64 above.
* `MSYS2 <https://www.msys2.org/>`_
Necessary reading about MSYS2 `environments <https://www.msys2.org/docs/environments/>`_
* ucrt64
* clang64
* mingw32
* mingw64
* clangarm64

File diff suppressed because it is too large Load Diff

View File

@@ -28,22 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDEXTENSION_INTERFACE_H
#define GDEXTENSION_INTERFACE_H
#pragma once
/* This is a C class header, you can copy it and use it directly in your own binders.
* Together with the JSON file, you should be able to generate any binder.
*/
#ifndef __cplusplus
#include <stddef.h>
#include <stdint.h>
#ifndef __cplusplus
typedef uint32_t char32_t;
typedef uint16_t char16_t;
#endif
#else
#include <cstddef>
#include <cstdint>
#ifdef __cplusplus
extern "C" {
#endif
@@ -399,8 +399,13 @@ typedef struct {
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo4;
typedef GDExtensionClassCreationInfo4 GDExtensionClassCreationInfo5;
typedef void *GDExtensionClassLibraryPtr;
/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */
typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array);
/* Method */
typedef enum {
@@ -721,6 +726,9 @@ typedef struct {
} GDExtensionScriptInstanceInfo3;
typedef void (*GDExtensionWorkerThreadPoolGroupTask)(void *, uint32_t);
typedef void (*GDExtensionWorkerThreadPoolTask)(void *);
/* INITIALIZATION */
typedef enum {
@@ -731,6 +739,9 @@ typedef enum {
GDEXTENSION_MAX_INITIALIZATION_LEVEL,
} GDExtensionInitializationLevel;
typedef void (*GDExtensionInitializeCallback)(void *p_userdata, GDExtensionInitializationLevel p_level);
typedef void (*GDExtensionDeinitializeCallback)(void *p_userdata, GDExtensionInitializationLevel p_level);
typedef struct {
/* Minimum initialization level required.
* If Core or Servers, the extension needs editor or game restart to take effect */
@@ -738,8 +749,8 @@ typedef struct {
/* Up to the user to supply when initializing */
void *userdata;
/* This function will be called multiple times for each initialization level. */
void (*initialize)(void *userdata, GDExtensionInitializationLevel p_level);
void (*deinitialize)(void *userdata, GDExtensionInitializationLevel p_level);
GDExtensionInitializeCallback initialize;
GDExtensionDeinitializeCallback deinitialize;
} GDExtensionInitialization;
typedef void (*GDExtensionInterfaceFunctionPtr)();
@@ -790,9 +801,41 @@ typedef struct {
const char *string;
} GDExtensionGodotVersion;
typedef struct {
uint32_t major;
uint32_t minor;
uint32_t patch;
uint32_t hex; // Full version encoded as hexadecimal with one byte (2 hex digits) per number (e.g. for "3.1.12" it would be 0x03010C)
const char *status; // (e.g. "stable", "beta", "rc1", "rc2")
const char *build; // (e.g. "custom_build")
const char *hash; // Full Git commit hash.
uint64_t timestamp; // Git commit date UNIX timestamp in seconds, or 0 if unavailable.
const char *string; // (e.g. "Godot v3.1.4.stable.official.mono")
} GDExtensionGodotVersion2;
/* Called when starting the main loop. */
typedef void (*GDExtensionMainLoopStartupCallback)();
/* Called when shutting down the main loop. */
typedef void (*GDExtensionMainLoopShutdownCallback)();
/* Called for every frame iteration of the main loop. */
typedef void (*GDExtensionMainLoopFrameCallback)();
typedef struct {
// Will be called after Godot is started and is fully initialized.
GDExtensionMainLoopStartupCallback startup_func;
// Will be called before Godot is shutdown when it is still fully initialized.
GDExtensionMainLoopShutdownCallback shutdown_func;
// Will be called for each process frame. This will run after all `_process()` methods on Node, and before `ScriptServer::frame()`.
// This is intended to be the equivalent of `ScriptLanguage::frame()` for GDExtension language bindings that don't use the script API.
GDExtensionMainLoopFrameCallback frame_func;
} GDExtensionMainLoopCallbacks;
/**
* @name get_godot_version
* @since 4.1
* @deprecated in Godot 4.5. Use `get_godot_version2` instead.
*
* Gets the Godot version that the GDExtension was loaded into.
*
@@ -800,6 +843,16 @@ typedef struct {
*/
typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version);
/**
* @name get_godot_version2
* @since 4.5
*
* Gets the Godot version that the GDExtension was loaded into.
*
* @param r_godot_version A pointer to the structure to write the version information into.
*/
typedef void (*GDExtensionInterfaceGetGodotVersion2)(GDExtensionGodotVersion2 *r_godot_version);
/* INTERFACE: Memory */
/**
@@ -994,7 +1047,7 @@ typedef void (*GDExtensionInterfaceVariantCall)(GDExtensionVariantPtr p_self, GD
*
* Calls a static method on a Variant.
*
* @param p_self A pointer to the Variant.
* @param p_type The variant type.
* @param p_method A pointer to a StringName identifying the method.
* @param p_args A pointer to a C array of Variant.
* @param p_argument_count The number of arguments.
@@ -1280,7 +1333,7 @@ typedef GDExtensionVariantType (*GDExtensionInterfaceVariantGetType)(GDExtension
* @param p_self A pointer to the Variant.
* @param p_method A pointer to a StringName with the method name.
*
* @return
* @return true if the variant has the given method; otherwise false.
*/
typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMethod)(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_method);
@@ -1293,7 +1346,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMethod)(GDExtensionConst
* @param p_type The Variant type.
* @param p_member A pointer to a StringName with the member name.
*
* @return
* @return true if the variant has the given method; otherwise false.
*/
typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member);
@@ -1464,7 +1517,7 @@ typedef GDExtensionPtrDestructor (*GDExtensionInterfaceVariantGetPtrDestructor)(
* Constructs a Variant of the given type, using the first constructor that matches the given arguments.
*
* @param p_type The Variant type.
* @param p_base A pointer to a Variant to store the constructed value.
* @param r_base A pointer to a Variant to store the constructed value.
* @param p_args A pointer to a C array of Variant pointers representing the arguments for the constructor.
* @param p_argument_count The number of arguments to pass to the constructor.
* @param r_error A pointer the structure which will be updated with error information.
@@ -1687,7 +1740,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen2)(GDEx
*
* @param r_dest A pointer to a Variant to hold the newly created String.
* @param p_contents A pointer to a UTF-16 encoded C string.
* @param p_size The number of characters (not bytes).
* @param p_char_count The number of characters (not bytes).
*/
typedef void (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen)(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count);
@@ -1699,7 +1752,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen)(GDExtensionUni
*
* @param r_dest A pointer to a Variant to hold the newly created String.
* @param p_contents A pointer to a UTF-16 encoded C string.
* @param p_size The number of characters (not bytes).
* @param p_char_count The number of characters (not bytes).
* @param p_default_little_endian If true, UTF-16 use little endian.
*
* @return Error code signifying if the operation successful.
@@ -1714,7 +1767,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen2)(GDE
*
* @param r_dest A pointer to a Variant to hold the newly created String.
* @param p_contents A pointer to a UTF-32 encoded C string.
* @param p_size The number of characters (not bytes).
* @param p_char_count The number of characters (not bytes).
*/
typedef void (*GDExtensionInterfaceStringNewWithUtf32CharsAndLen)(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_char_count);
@@ -1726,7 +1779,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf32CharsAndLen)(GDExtensionUni
*
* @param r_dest A pointer to a Variant to hold the newly created String.
* @param p_contents A pointer to a wide C string.
* @param p_size The number of characters (not bytes).
* @param p_char_count The number of characters (not bytes).
*/
typedef void (*GDExtensionInterfaceStringNewWithWideCharsAndLen)(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_char_count);
@@ -2043,6 +2096,7 @@ typedef const uint8_t *(*GDExtensionInterfaceImagePtr)(GDExtensionObjectPtr p_in
* @param p_instance A pointer to a WorkerThreadPool object.
* @param p_func A pointer to a function to run in the thread pool.
* @param p_userdata A pointer to arbitrary data which will be passed to p_func.
* @param p_elements The number of element needed in the group.
* @param p_tasks The number of tasks needed in the group.
* @param p_high_priority Whether or not this is a high priority task.
* @param p_description A pointer to a String with the task description.
@@ -2051,7 +2105,7 @@ typedef const uint8_t *(*GDExtensionInterfaceImagePtr)(GDExtensionObjectPtr p_in
*
* @see WorkerThreadPool::add_group_task()
*/
typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask)(GDExtensionObjectPtr p_instance, GDExtensionWorkerThreadPoolGroupTask p_func, void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
/**
* @name worker_thread_pool_add_native_task
@@ -2067,7 +2121,7 @@ typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask)(GDExte
*
* @return The task ID.
*/
typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeTask)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeTask)(GDExtensionObjectPtr p_instance, GDExtensionWorkerThreadPoolTask p_func, void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
/* INTERFACE: Packed Array */
@@ -2360,6 +2414,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceArrayOperatorIndexConst)(GDE
/**
* @name array_ref
* @since 4.1
* @deprecated in Godot 4.5. use `Array::operator=` instead.
*
* Sets an Array to be a reference to another Array object.
*
@@ -2484,10 +2539,10 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceGlobalGetSingleton)(GDExtensi
* Gets a pointer representing an Object's instance binding.
*
* @param p_o A pointer to the Object.
* @param p_library A token the library received by the GDExtension's entry point function.
* @param p_token A token the library received by the GDExtension's entry point function.
* @param p_callbacks A pointer to a GDExtensionInstanceBindingCallbacks struct.
*
* @return
* @return A pointer to the instance binding.
*/
typedef void *(*GDExtensionInterfaceObjectGetInstanceBinding)(GDExtensionObjectPtr p_o, void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks);
@@ -2498,7 +2553,7 @@ typedef void *(*GDExtensionInterfaceObjectGetInstanceBinding)(GDExtensionObjectP
* Sets an Object's instance binding.
*
* @param p_o A pointer to the Object.
* @param p_library A token the library received by the GDExtension's entry point function.
* @param p_token A token the library received by the GDExtension's entry point function.
* @param p_binding A pointer to the instance binding.
* @param p_callbacks A pointer to a GDExtensionInstanceBindingCallbacks struct.
*/
@@ -2511,7 +2566,7 @@ typedef void (*GDExtensionInterfaceObjectSetInstanceBinding)(GDExtensionObjectPt
* Free an Object's instance binding.
*
* @param p_o A pointer to the Object.
* @param p_library A token the library received by the GDExtension's entry point function.
* @param p_token A token the library received by the GDExtension's entry point function.
*/
typedef void (*GDExtensionInterfaceObjectFreeInstanceBinding)(GDExtensionObjectPtr p_o, void *p_token);
@@ -2521,11 +2576,13 @@ typedef void (*GDExtensionInterfaceObjectFreeInstanceBinding)(GDExtensionObjectP
*
* Sets an extension class instance on a Object.
*
* `p_classname` should be a registered extension class and should extend the `p_o` Object's class.
*
* @param p_o A pointer to the Object.
* @param p_classname A pointer to a StringName with the registered extension class's name.
* @param p_instance A pointer to the extension class instance.
*/
typedef void (*GDExtensionInterfaceObjectSetInstance)(GDExtensionObjectPtr p_o, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
typedef void (*GDExtensionInterfaceObjectSetInstance)(GDExtensionObjectPtr p_o, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance);
/**
* @name object_get_class_name
@@ -2590,7 +2647,7 @@ typedef GDObjectInstanceID (*GDExtensionInterfaceObjectGetInstanceId)(GDExtensio
* @param p_object A pointer to the Object.
* @param p_method A pointer to a StringName identifying the method.
*
* @returns true if the object has a script and that script has a method with the given name. Returns false if the object has no script.
* @return true if the object has a script and that script has a method with the given name. Returns false if the object has no script.
*/
typedef GDExtensionBool (*GDExtensionInterfaceObjectHasScriptMethod)(GDExtensionConstObjectPtr p_object, GDExtensionConstStringNamePtr p_method);
@@ -2721,6 +2778,17 @@ typedef void (*GDExtensionInterfacePlaceHolderScriptInstanceUpdate)(GDExtensionS
*/
typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language);
/**
* @name object_set_script_instance
* @since 4.5
*
* Set the script instance data attached to this object.
*
* @param p_object A pointer to the Object.
* @param p_script_instance A pointer to the script instance data to attach to this object.
*/
typedef void (*GDExtensionInterfaceObjectSetScriptInstance)(GDExtensionObjectPtr p_object, GDExtensionScriptInstanceDataPtr p_script_instance);
/* INTERFACE: Callable */
/**
@@ -2760,6 +2828,8 @@ typedef void (*GDExtensionInterfaceCallableCustomCreate2)(GDExtensionUninitializ
*
* @param p_callable A pointer to a Callable.
* @param p_token A pointer to an address that uniquely identifies the GDExtension.
*
* @return The userdata pointer given when creating this custom Callable.
*/
typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstTypePtr p_callable, void *p_token);
@@ -2868,13 +2938,14 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_parent_class_name A pointer to a StringName with the parent class name.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo3 struct.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
/**
* @name classdb_register_extension_class4
* @since 4.4
* @deprecated in Godot 4.5. Use `classdb_register_extension_class5` instead.
*
* Registers an extension class in the ClassDB.
*
@@ -2883,10 +2954,25 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionCl
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_parent_class_name A pointer to a StringName with the parent class name.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo4 struct.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass4)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
/**
* @name classdb_register_extension_class5
* @since 4.5
*
* Registers an extension class in the ClassDB.
*
* Provided struct can be safely freed once the function returns.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_parent_class_name A pointer to a StringName with the parent class name.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo5 struct.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass5)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs);
/**
* @name classdb_register_extension_class_method
* @since 4.1
@@ -3015,10 +3101,12 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassSignal)(GDExtens
*
* Unregisters an extension class in the ClassDB.
*
* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
*/
typedef void (*GDExtensionInterfaceClassdbUnregisterExtensionClass)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
typedef void (*GDExtensionInterfaceClassdbUnregisterExtensionClass)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
/**
* @name get_library_path
@@ -3078,8 +3166,33 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *
*/
typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size);
/**
* @name editor_register_get_classes_used_callback
* @since 4.5
*
* Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension.
*
* This is used by the editor to generate a build profile (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"),
* in order to recompile Godot with only the classes used.
* In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter.
* If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_callback The callback to retrieve the list of classes used.
*/
typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
/**
* @name register_main_loop_callbacks
* @since 4.5
*
* Registers callbacks to be called at different phases of the main loop.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_callbacks A pointer to the structure that contains the callbacks.
*/
typedef void (*GDExtensionInterfaceRegisterMainLoopCallbacks)(GDExtensionClassLibraryPtr p_library, const GDExtensionMainLoopCallbacks *p_callbacks);
#ifdef __cplusplus
}
#endif
#endif // GDEXTENSION_INTERFACE_H

View File

@@ -37,6 +37,7 @@
#include <godot_cpp/core/type_info.hpp>
#include <array>
#include <vector>
namespace godot {
@@ -261,7 +262,6 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args; // Avoid warning.
}
template <typename T, typename R, typename... P, size_t... Is>
@@ -273,7 +273,7 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args; // Avoid warning.
(void)p_args;
}
template <typename T, typename... P>
@@ -331,7 +331,7 @@ void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, co
}
template <typename T, typename... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
@@ -366,7 +366,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
}
template <typename T, typename... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
@@ -401,7 +401,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
}
template <typename T, typename R, typename... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
@@ -436,7 +436,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
}
template <typename T, typename R, typename... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
@@ -548,7 +548,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
}
template <typename... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
@@ -640,7 +640,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
}
template <typename R, typename... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;

View File

@@ -44,10 +44,19 @@
// Needs to come after method_bind and object have been included.
#include <godot_cpp/variant/callable_method_pointer.hpp>
#include <godot_cpp/templates/a_hash_map.hpp>
#include <list>
#include <mutex>
#include <set>
#include <unordered_map>
#include <vector>
// Needed to use StringName as key in `std::unordered_map`
template <>
struct std::hash<godot::StringName> {
std::size_t operator()(godot::StringName const &s) const noexcept {
return s.hash();
}
};
namespace godot {
@@ -85,9 +94,9 @@ public:
StringName name;
StringName parent_name;
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
AHashMap<StringName, MethodBind *> method_map;
std::unordered_map<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
AHashMap<StringName, VirtualMethod> virtual_methods;
std::unordered_map<StringName, VirtualMethod> virtual_methods;
std::set<StringName> property_names;
std::set<StringName> constant_names;
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
@@ -96,11 +105,11 @@ public:
private:
// This may only contain custom classes, not Godot classes
static HashMap<StringName, ClassInfo> classes;
static AHashMap<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
static std::unordered_map<StringName, ClassInfo> classes;
static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
// Used to remember the custom class registration order.
static LocalVector<StringName> class_register_order;
static AHashMap<StringName, Object *> engine_singletons;
static std::vector<StringName> class_register_order;
static std::unordered_map<StringName, Object *> engine_singletons;
static std::mutex engine_singletons_mutex;
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
@@ -157,11 +166,13 @@ public:
instance_binding_callbacks[p_name] = p_callbacks;
}
static void _editor_get_classes_used_callback(GDExtensionTypePtr p_packed_string_array);
static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
AHashMap<StringName, Object *>::ConstIterator i = engine_singletons.find(p_class_name);
std::unordered_map<StringName, Object *>::const_iterator i = engine_singletons.find(p_class_name);
if (i != engine_singletons.end()) {
ERR_FAIL_COND((*i).value != p_singleton);
ERR_FAIL_COND((*i).second != p_singleton);
return;
}
engine_singletons[p_class_name] = p_singleton;
@@ -179,7 +190,7 @@ public:
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const LocalVector<Variant> &p_default_args = LocalVector<Variant>{}, bool p_return_nil_is_variant = true);
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
@@ -231,16 +242,16 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
cl.name = T::get_class_static();
cl.parent_name = T::get_parent_class_static();
cl.level = current_level;
HashMap<StringName, ClassInfo>::Iterator parent_it = classes.find(cl.parent_name);
std::unordered_map<StringName, ClassInfo>::iterator parent_it = classes.find(cl.parent_name);
if (parent_it != classes.end()) {
// Assign parent if it is also a custom class
cl.parent_ptr = &parent_it->value;
cl.parent_ptr = &parent_it->second;
}
classes[cl.name] = cl;
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo4 class_info = {
GDExtensionClassCreationInfo5 class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
@@ -266,7 +277,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gdextension_interface_classdb_register_extension_class4(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
internal::gdextension_interface_classdb_register_extension_class5(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();
@@ -319,7 +330,7 @@ MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p
}
template <typename M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const LocalVector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr);
@@ -328,13 +339,13 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
StringName instance_type = bind->get_instance_class();
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(instance_type);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
if (type_it == classes.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
}
ClassInfo &type = type_it->value;
ClassInfo &type = type_it->second;
if (type.method_map.find(p_name) != type.method_map.end()) {
memdelete(bind);

View File

@@ -38,7 +38,8 @@
#include <gdextension_interface.h>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/templates/local_vector.hpp>
#include <vector>
namespace godot {
@@ -53,9 +54,9 @@ class MethodBind {
bool _returns = false;
bool _vararg = false;
LocalVector<StringName> argument_names;
std::vector<StringName> argument_names;
GDExtensionVariantType *argument_types = nullptr;
LocalVector<Variant> default_arguments;
std::vector<Variant> default_arguments;
protected:
void _set_const(bool p_const);
@@ -69,7 +70,7 @@ protected:
void set_argument_count(int p_count) { argument_count = p_count; }
public:
_FORCE_INLINE_ const LocalVector<Variant> &get_default_arguments() const { return default_arguments; }
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
_FORCE_INLINE_ int get_default_argument_count() const { return (int)default_arguments.size(); }
_FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
@@ -100,8 +101,8 @@ public:
PropertyInfo get_argument_info(int p_argument) const;
LocalVector<PropertyInfo> get_arguments_info_list() const {
LocalVector<PropertyInfo> vec;
std::vector<PropertyInfo> get_arguments_info_list() const {
std::vector<PropertyInfo> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count + 1; i++) {
@@ -110,8 +111,8 @@ public:
return vec;
}
void set_argument_names(const LocalVector<StringName> &p_names);
LocalVector<StringName> get_argument_names() const;
void set_argument_names(const std::vector<StringName> &p_names);
std::vector<StringName> get_argument_names() const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
@@ -132,10 +133,10 @@ public:
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _returns; }
void set_default_arguments(const LocalVector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
LocalVector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
LocalVector<GDExtensionClassMethodArgumentMetadata> vec;
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count + 1; i++) {
@@ -154,7 +155,7 @@ template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R (T::*method)(const Variant **, GDExtensionInt, GDExtensionCallError &);
LocalVector<PropertyInfo> arguments;
std::vector<PropertyInfo> arguments;
public:
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
@@ -190,7 +191,7 @@ public:
if (p_method_info.arguments.size()) {
arguments = p_method_info.arguments;
LocalVector<StringName> names;
std::vector<StringName> names;
names.reserve(p_method_info.arguments.size());
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
names.push_back(p_method_info.arguments[i].name);

View File

@@ -38,14 +38,14 @@
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/templates/local_vector.hpp>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/godot.hpp>
#include <gdextension_interface.h>
#include <vector>
#define ADD_SIGNAL(m_signal) ::godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) ::godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) ::godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
@@ -65,10 +65,10 @@ struct MethodInfo {
PropertyInfo return_val;
uint32_t flags;
int id = 0;
LocalVector<PropertyInfo> arguments;
LocalVector<Variant> default_arguments;
std::vector<PropertyInfo> arguments;
std::vector<Variant> default_arguments;
GDExtensionClassMethodArgumentMetadata return_val_metadata;
LocalVector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
std::vector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
@@ -92,17 +92,21 @@ struct MethodInfo {
template <typename... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {}
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
template <typename... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
arguments = { args... };
}
template <typename... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
class ObjectDB {

View File

@@ -40,10 +40,10 @@ extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_add
extern "C" GDExtensionClassLibraryPtr library;
extern "C" void *token;
extern "C" GDExtensionGodotVersion godot_version;
extern "C" GDExtensionGodotVersion2 godot_version;
// All of the GDExtension interface functions.
extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version;
extern "C" GDExtensionInterfaceGetGodotVersion2 gdextension_interface_get_godot_version2;
extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc;
extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc;
extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free;
@@ -155,7 +155,6 @@ extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_inter
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
@@ -181,10 +180,12 @@ extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object
extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
extern "C" GDExtensionInterfaceObjectGetScriptInstance gdextension_interface_object_get_script_instance;
extern "C" GDExtensionInterfaceObjectSetScriptInstance gdextension_interface_object_set_script_instance;
extern "C" GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2;
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass5 gdextension_interface_classdb_register_extension_class5;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
@@ -197,10 +198,12 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
extern "C" GDExtensionInterfaceEditorRegisterGetClassesUsedCallback gdextension_interface_editor_register_get_classes_used_callback;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len;
extern "C" GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw;
extern "C" GDExtensionInterfaceImagePtr gdextension_interface_image_ptr;
extern "C" GDExtensionInterfaceRegisterMainLoopCallbacks gdextension_interface_register_main_loop_callbacks;
class DocDataRegistration {
public:
@@ -225,6 +228,11 @@ public:
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
Callback init_callback = nullptr;
Callback terminate_callback = nullptr;
GDExtensionMainLoopCallbacks main_loop_callbacks = {};
inline bool has_main_loop_callbacks() const {
return main_loop_callbacks.frame_func || main_loop_callbacks.startup_func || main_loop_callbacks.shutdown_func;
}
};
class InitDataList {
@@ -259,6 +267,13 @@ public:
void register_terminator(Callback p_init) const;
void set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const;
// Register a callback that is called after all initialization levels when Godot is fully initialized.
void register_startup_callback(GDExtensionMainLoopStartupCallback p_callback) const;
// Register a callback that is called for every process frame. This will run after all `_process()` methods on Node, and before `ScriptServer::frame()`.
void register_frame_callback(GDExtensionMainLoopFrameCallback p_callback) const;
// Register a callback that is called before Godot is shutdown when it is still fully initialized.
void register_shutdown_callback(GDExtensionMainLoopShutdownCallback p_callback) const;
GDExtensionBool init() const;
};
};

View File

@@ -1,734 +0,0 @@
/**************************************************************************/
/* a_hash_map.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include <godot_cpp/templates/hash_map.hpp>
namespace godot {
struct HashMapData {
union {
uint64_t data;
struct
{
uint32_t hash;
uint32_t hash_to_key;
};
};
};
static_assert(sizeof(HashMapData) == 8);
/**
* An array-based implementation of a hash map. It is very efficient in terms of performance and
* memory usage. Works like a dynamic array, adding elements to the end of the array, and
* allows you to access array elements by their index by using `get_by_index` method.
* Example:
* ```
* AHashMap<int, Object *> map;
*
* int get_object_id_by_number(int p_number) {
* int id = map.get_index(p_number);
* return id;
* }
*
* Object *get_object_by_id(int p_id) {
* map.get_by_index(p_id).value;
* }
* ```
* Still, don`t erase the elements because ID can break.
*
* When an element erase, its place is taken by the element from the end.
*
* <-------------
* | |
* 6 8 X 9 32 -1 5 -10 7 X X X
* 6 8 7 9 32 -1 5 -10 X X X X
*
*
* Use RBMap if you need to iterate over sorted elements.
*
* Use HashMap if:
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
* - You need to preserve the insertion order when using erase.
*
* It is recommended to use `HashMap` if `KeyValue` size is very large.
*/
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>>
class AHashMap {
public:
// Must be a power of two.
static constexpr uint32_t INITIAL_CAPACITY = 16;
static constexpr uint32_t EMPTY_HASH = 0;
static_assert(EMPTY_HASH == 0, "EMPTY_HASH must always be 0 for the memcpy() optimization.");
private:
typedef KeyValue<TKey, TValue> MapKeyValue;
MapKeyValue *elements = nullptr;
HashMapData *map_data = nullptr;
// Due to optimization, this is `capacity - 1`. Use + 1 to get normal capacity.
uint32_t capacity = 0;
uint32_t num_elements = 0;
uint32_t _hash(const TKey &p_key) const {
uint32_t hash = Hasher::hash(p_key);
if (unlikely(hash == EMPTY_HASH)) {
hash = EMPTY_HASH + 1;
}
return hash;
}
static _FORCE_INLINE_ uint32_t _get_resize_count(uint32_t p_capacity) {
return p_capacity ^ (p_capacity + 1) >> 2; // = get_capacity() * 0.75 - 1; Works only if p_capacity = 2^n - 1.
}
static _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_local_capacity) {
const uint32_t original_pos = p_hash & p_local_capacity;
return (p_pos - original_pos + p_local_capacity + 1) & p_local_capacity;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
return _lookup_pos_with_hash(p_key, r_pos, r_hash_pos, _hash(p_key));
}
bool _lookup_pos_with_hash(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos, uint32_t p_hash) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
uint32_t pos = p_hash & capacity;
HashMapData data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
// A collision occurred.
pos = (pos + 1) & capacity;
uint32_t distance = 1;
while (true) {
data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, data.hash, capacity)) {
return false;
}
pos = (pos + 1) & capacity;
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
uint32_t pos = p_hash & capacity;
if (map_data[pos].data == EMPTY_HASH) {
uint64_t data = ((uint64_t)p_index << 32) | p_hash;
map_data[pos].data = data;
return pos;
}
uint32_t distance = 1;
pos = (pos + 1) & capacity;
HashMapData c_data;
c_data.hash = p_hash;
c_data.hash_to_key = p_index;
while (true) {
if (map_data[pos].data == EMPTY_HASH) {
#ifdef DEV_ENABLED
if (unlikely(distance > 12)) {
WARN_PRINT("Excessive collision count (" +
itos(distance) + "), is the right hash function being used?");
}
#endif
map_data[pos] = c_data;
return pos;
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, map_data[pos].hash, capacity);
if (existing_probe_len < distance) {
SWAP(c_data, map_data[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) & capacity;
distance++;
}
}
void _resize_and_rehash(uint32_t p_new_capacity) {
uint32_t real_old_capacity = capacity + 1;
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_new_capacity);
uint32_t real_capacity = next_power_of_2(capacity);
capacity = real_capacity - 1;
HashMapData *old_map_data = map_data;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::realloc_static(elements, sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if (num_elements != 0) {
for (uint32_t i = 0; i < real_old_capacity; i++) {
HashMapData data = old_map_data[i];
if (data.data != EMPTY_HASH) {
_insert_with_hash(data.hash, data.hash_to_key);
}
}
}
Memory::free_static(old_map_data);
}
int32_t _insert_element(const TKey &p_key, const TValue &p_value, uint32_t p_hash) {
if (unlikely(elements == nullptr)) {
// Allocate on demand to save memory.
uint32_t real_capacity = capacity + 1;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
}
if (unlikely(num_elements > _get_resize_count(capacity))) {
_resize_and_rehash(capacity * 2);
}
memnew_placement(&elements[num_elements], MapKeyValue(p_key, p_value));
_insert_with_hash(p_hash, num_elements);
num_elements++;
return num_elements - 1;
}
void _init_from(const AHashMap &p_other) {
capacity = p_other.capacity;
uint32_t real_capacity = capacity + 1;
num_elements = p_other.num_elements;
if (p_other.num_elements == 0) {
return;
}
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if constexpr (std::is_trivially_copyable_v<TKey> && std::is_trivially_copyable_v<TValue>) {
void *destination = elements;
const void *source = p_other.elements;
memcpy(destination, source, sizeof(MapKeyValue) * num_elements);
} else {
for (uint32_t i = 0; i < num_elements; i++) {
memnew_placement(&elements[i], MapKeyValue(p_other.elements[i]));
}
}
memcpy(map_data, p_other.map_data, sizeof(HashMapData) * real_capacity);
}
public:
/* Standard Godot Container API */
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity + 1; }
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
_FORCE_INLINE_ bool is_empty() const {
return num_elements == 0;
}
void clear() {
if (elements == nullptr || num_elements == 0) {
return;
}
memset(map_data, EMPTY_HASH, (capacity + 1) * sizeof(HashMapData));
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
num_elements = 0;
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue &get(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue *getptr(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
TValue *getptr(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
bool has(const TKey &p_key) const {
uint32_t _pos = 0;
uint32_t h_pos = 0;
return _lookup_pos(p_key, _pos, h_pos);
}
bool erase(const TKey &p_key) {
uint32_t pos = 0;
uint32_t element_pos = 0;
bool exists = _lookup_pos(p_key, element_pos, pos);
if (!exists) {
return false;
}
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
elements[element_pos].key.~TKey();
elements[element_pos].value.~TValue();
num_elements--;
if (element_pos < num_elements) {
void *destination = &elements[element_pos];
const void *source = &elements[num_elements];
memcpy(destination, source, sizeof(MapKeyValue));
uint32_t h_pos = 0;
_lookup_pos(elements[num_elements].key, pos, h_pos);
map_data[h_pos].hash_to_key = element_pos;
}
return true;
}
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
if (p_old_key == p_new_key) {
return true;
}
uint32_t pos = 0;
uint32_t element_pos = 0;
ERR_FAIL_COND_V(_lookup_pos(p_new_key, element_pos, pos), false);
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, element_pos, pos), false);
MapKeyValue &element = elements[element_pos];
const_cast<TKey &>(element.key) = p_new_key;
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
uint32_t hash = _hash(p_new_key);
_insert_with_hash(hash, element_pos);
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
ERR_FAIL_COND_MSG(p_new_capacity < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
if (elements == nullptr) {
capacity = MAX(4u, p_new_capacity);
capacity = next_power_of_2(capacity) - 1;
return; // Unallocated yet.
}
if (p_new_capacity <= get_capacity()) {
return;
}
_resize_and_rehash(p_new_capacity);
}
/** Iterator API **/
struct ConstIterator {
_FORCE_INLINE_ const MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ const MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ ConstIterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ ConstIterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
struct Iterator {
_FORCE_INLINE_ MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ Iterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ Iterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ Iterator() {}
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
operator ConstIterator() const {
return ConstIterator(pair, begin, end);
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator end() {
return Iterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator last() {
if (unlikely(num_elements == 0)) {
return Iterator(nullptr, nullptr, nullptr);
}
return Iterator(elements + num_elements - 1, elements, elements + num_elements);
}
Iterator find(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return Iterator(elements + pos, elements, elements + num_elements);
}
void remove(const Iterator &p_iter) {
if (p_iter) {
erase(p_iter->key);
}
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator last() const {
if (unlikely(num_elements == 0)) {
return ConstIterator(nullptr, nullptr, nullptr);
}
return ConstIterator(elements + num_elements - 1, elements, elements + num_elements);
}
ConstIterator find(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return ConstIterator(elements + pos, elements, elements + num_elements);
}
/* Indexing */
const TValue &operator[](const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
CRASH_COND(!exists);
return elements[pos].value;
}
TValue &operator[](const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (exists) {
return elements[pos].value;
} else {
pos = _insert_element(p_key, TValue(), hash);
return elements[pos].value;
}
}
/* Insert */
Iterator insert(const TKey &p_key, const TValue &p_value) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (!exists) {
pos = _insert_element(p_key, p_value, hash);
} else {
elements[pos].value = p_value;
}
return Iterator(elements + pos, elements, elements + num_elements);
}
// Inserts an element without checking if it already exists.
Iterator insert_new(const TKey &p_key, const TValue &p_value) {
DEV_ASSERT(!has(p_key));
uint32_t hash = _hash(p_key);
uint32_t pos = _insert_element(p_key, p_value, hash);
return Iterator(elements + pos, elements, elements + num_elements);
}
/* Array methods. */
// Unsafe. Changing keys and going outside the bounds of an array can lead to undefined behavior.
KeyValue<TKey, TValue> *get_elements_ptr() {
return elements;
}
// Returns the element index. If not found, returns -1.
int get_index(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return -1;
}
return pos;
}
KeyValue<TKey, TValue> &get_by_index(uint32_t p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, num_elements);
return elements[p_index];
}
bool erase_by_index(uint32_t p_index) {
if (p_index >= size()) {
return false;
}
return erase(elements[p_index].key);
}
/* Constructors */
AHashMap(const AHashMap &p_other) {
_init_from(p_other);
}
AHashMap(const HashMap<TKey, TValue> &p_other) {
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
void operator=(const AHashMap &p_other) {
if (this == &p_other) {
return; // Ignore self assignment.
}
reset();
_init_from(p_other);
}
void operator=(const HashMap<TKey, TValue> &p_other) {
reset();
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
AHashMap(uint32_t p_initial_capacity) {
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_initial_capacity);
capacity = next_power_of_2(capacity) - 1;
}
AHashMap() :
capacity(INITIAL_CAPACITY - 1) {
}
AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
reserve(p_init.size());
for (const KeyValue<TKey, TValue> &E : p_init) {
insert(E.key, E.value);
}
}
void reset() {
if (elements != nullptr) {
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
Memory::free_static(elements);
Memory::free_static(map_data);
elements = nullptr;
}
capacity = INITIAL_CAPACITY - 1;
num_elements = 0;
}
~AHashMap() {
reset();
}
};
} //namespace godot

View File

@@ -37,7 +37,6 @@
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/pair.hpp>
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/rect2.hpp>
@@ -320,13 +319,6 @@ struct HashMapHasherDefault {
template <typename T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
template <typename F, typename S>
static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) {
uint64_t h1 = hash(p_pair.first);
uint64_t h2 = hash(p_pair.second);
return hash_one_uint64((h1 << 32) | h2);
}
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); }
@@ -337,7 +329,6 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); }
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
@@ -385,13 +376,6 @@ struct HashMapHasherDefault {
h = hash_murmur3_one_real(p_vec.w, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) {
uint32_t h = hash_murmur3_one_float(p_vec.r);
h = hash_murmur3_one_float(p_vec.g, h);
h = hash_murmur3_one_float(p_vec.b, h);
h = hash_murmur3_one_float(p_vec.a, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);

View File

@@ -30,70 +30,86 @@
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/templates/hashfuncs.hpp>
namespace godot {
template <typename F, typename S>
struct Pair {
F first{};
S second{};
F first;
S second;
constexpr Pair() = default;
constexpr Pair(const F &p_first, const S &p_second) :
first(p_first), second(p_second) {}
Pair() :
first(),
second() {
}
constexpr bool operator==(const Pair &p_other) const { return first == p_other.first && second == p_other.second; }
constexpr bool operator!=(const Pair &p_other) const { return first != p_other.first || second != p_other.second; }
constexpr bool operator<(const Pair &p_other) const { return first == p_other.first ? (second < p_other.second) : (first < p_other.first); }
constexpr bool operator<=(const Pair &p_other) const { return first == p_other.first ? (second <= p_other.second) : (first < p_other.first); }
constexpr bool operator>(const Pair &p_other) const { return first == p_other.first ? (second > p_other.second) : (first > p_other.first); }
constexpr bool operator>=(const Pair &p_other) const { return first == p_other.first ? (second >= p_other.second) : (first > p_other.first); }
Pair(F p_first, const S &p_second) :
first(p_first),
second(p_second) {
}
};
template <typename F, typename S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
template <typename F, typename S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
template <typename F, typename S>
struct PairSort {
constexpr bool operator()(const Pair<F, S> &p_lhs, const Pair<F, S> &p_rhs) const {
return p_lhs < p_rhs;
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) {
return A.first < B.first;
}
return A.second < B.second;
}
};
// Pair is zero-constructible if and only if both constrained types are zero-constructible.
template <typename F, typename S>
struct is_zero_constructible<Pair<F, S>> : std::conjunction<is_zero_constructible<F>, is_zero_constructible<S>> {};
struct PairHash {
static uint32_t hash(const Pair<F, S> &P) {
uint64_t h1 = HashMapHasherDefault::hash(P.first);
uint64_t h2 = HashMapHasherDefault::hash(P.second);
return hash_one_uint64((h1 << 32) | h2);
}
};
template <typename K, typename V>
struct KeyValue {
const K key{};
V value{};
const K key;
V value;
KeyValue &operator=(const KeyValue &p_kv) = delete;
KeyValue &operator=(KeyValue &&p_kv) = delete;
constexpr KeyValue(const KeyValue &p_kv) = default;
constexpr KeyValue(KeyValue &&p_kv) = default;
constexpr KeyValue(const K &p_key, const V &p_value) :
key(p_key), value(p_value) {}
constexpr KeyValue(const Pair<K, V> &p_pair) :
key(p_pair.first), value(p_pair.second) {}
constexpr bool operator==(const KeyValue &p_other) const { return key == p_other.key && value == p_other.value; }
constexpr bool operator!=(const KeyValue &p_other) const { return key != p_other.key || value != p_other.value; }
constexpr bool operator<(const KeyValue &p_other) const { return key == p_other.key ? (value < p_other.value) : (key < p_other.key); }
constexpr bool operator<=(const KeyValue &p_other) const { return key == p_other.key ? (value <= p_other.value) : (key < p_other.key); }
constexpr bool operator>(const KeyValue &p_other) const { return key == p_other.key ? (value > p_other.value) : (key > p_other.key); }
constexpr bool operator>=(const KeyValue &p_other) const { return key == p_other.key ? (value >= p_other.value) : (key > p_other.key); }
};
template <typename K, typename V>
struct KeyValueSort {
constexpr bool operator()(const KeyValue<K, V> &p_lhs, const KeyValue<K, V> &p_rhs) const {
return p_lhs.key < p_rhs.key;
void operator=(const KeyValue &p_kv) = delete;
_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
key(p_kv.key),
value(p_kv.value) {
}
_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
key(p_key),
value(p_value) {
}
};
// KeyValue is zero-constructible if and only if both constrained types are zero-constructible.
template <typename K, typename V>
struct is_zero_constructible<KeyValue<K, V>> : std::conjunction<is_zero_constructible<K>, is_zero_constructible<V>> {};
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
template <typename K, typename V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
template <typename K, typename V>
struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key;
}
};
} // namespace godot

View File

@@ -40,7 +40,7 @@ class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type.");
_ref(p_array);
Array::operator=(p_array);
}
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
TypedArray(Array(p_variant)) {
@@ -48,7 +48,7 @@ public:
_FORCE_INLINE_ TypedArray(const Array &p_array) {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
if (is_same_typed(p_array)) {
_ref(p_array);
Array::operator=(p_array);
} else {
assign(p_array);
}
@@ -68,7 +68,7 @@ public:
public: \
_FORCE_INLINE_ void operator=(const Array &p_array) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type."); \
_ref(p_array); \
Array::operator=(p_array); \
} \
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) : \
Array(Array(p_init), m_variant_type, StringName(), Variant()) { \
@@ -79,7 +79,7 @@ public:
_FORCE_INLINE_ TypedArray(const Array &p_array) { \
set_typed(m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_array)) { \
_ref(p_array); \
Array::operator=(p_array); \
} else { \
assign(p_array); \
} \

View File

@@ -36,12 +36,14 @@
#include <godot_cpp/core/memory.hpp>
#include <algorithm>
namespace godot {
HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
AHashMap<StringName, const GDExtensionInstanceBindingCallbacks *> ClassDB::instance_binding_callbacks;
LocalVector<StringName> ClassDB::class_register_order;
AHashMap<StringName, Object *> ClassDB::engine_singletons;
std::unordered_map<StringName, ClassDB::ClassInfo> ClassDB::classes;
std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> ClassDB::instance_binding_callbacks;
std::vector<StringName> ClassDB::class_register_order;
std::unordered_map<StringName, Object *> ClassDB::engine_singletons;
std::mutex ClassDB::engine_singletons_mutex;
GDExtensionInitializationLevel ClassDB::current_level = GDEXTENSION_INITIALIZATION_CORE;
@@ -114,9 +116,9 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_m
ClassInfo *type = &classes[p_class];
while (type) {
AHashMap<StringName, MethodBind *>::Iterator method = type->method_map.find(p_method);
std::unordered_map<StringName, MethodBind *>::iterator method = type->method_map.find(p_method);
if (method != type->method_map.end()) {
return method->value;
return method->second;
}
type = type->parent_ptr;
continue;
@@ -128,13 +130,13 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_m
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount) {
StringName instance_type = p_bind->get_instance_class();
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(instance_type);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
if (type_it == classes.end()) {
memdelete(p_bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
}
ClassInfo &type = type_it->value;
ClassInfo &type = type_it->second;
if (type.method_map.find(method_name.name) != type.method_map.end()) {
memdelete(p_bind);
@@ -155,7 +157,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M
p_bind->set_hint_flags(p_flags);
LocalVector<StringName> args;
std::vector<StringName> args;
args.resize(method_name.args.size());
size_t arg_index = 0;
for (StringName arg : method_name.args) {
@@ -164,7 +166,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M
p_bind->set_argument_names(args);
LocalVector<Variant> defvals;
std::vector<Variant> defvals;
defvals.resize(p_defcount);
for (int i = 0; i < p_defcount; i++) {
@@ -184,34 +186,34 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M
}
void ClassDB::bind_method_godot(const StringName &p_class_name, MethodBind *p_method) {
LocalVector<GDExtensionVariantPtr> def_args;
const LocalVector<Variant> &def_args_val = p_method->get_default_arguments();
std::vector<GDExtensionVariantPtr> def_args;
const std::vector<Variant> &def_args_val = p_method->get_default_arguments();
def_args.resize(def_args_val.size());
for (size_t i = 0; i < def_args_val.size(); i++) {
def_args[i] = (GDExtensionVariantPtr)&def_args_val[i];
}
LocalVector<PropertyInfo> return_value_and_arguments_info = p_method->get_arguments_info_list();
LocalVector<GDExtensionClassMethodArgumentMetadata> return_value_and_arguments_metadata = p_method->get_arguments_metadata_list();
std::vector<PropertyInfo> return_value_and_arguments_info = p_method->get_arguments_info_list();
std::vector<GDExtensionClassMethodArgumentMetadata> return_value_and_arguments_metadata = p_method->get_arguments_metadata_list();
LocalVector<GDExtensionPropertyInfo> return_value_and_arguments_gdextension_info;
std::vector<GDExtensionPropertyInfo> return_value_and_arguments_gdextension_info;
return_value_and_arguments_gdextension_info.reserve(return_value_and_arguments_info.size());
for (const PropertyInfo &info : return_value_and_arguments_info) {
for (std::vector<PropertyInfo>::iterator it = return_value_and_arguments_info.begin(); it != return_value_and_arguments_info.end(); it++) {
return_value_and_arguments_gdextension_info.push_back(
GDExtensionPropertyInfo{
static_cast<GDExtensionVariantType>(info.type), // GDExtensionVariantType type;
info.name._native_ptr(), // GDExtensionStringNamePtr name;
info.class_name._native_ptr(), // GDExtensionStringNamePtr class_name;
info.hint, // uint32_t hint;
info.hint_string._native_ptr(), // GDExtensionStringPtr hint_string;
info.usage, // uint32_t usage;
static_cast<GDExtensionVariantType>(it->type), // GDExtensionVariantType type;
it->name._native_ptr(), // GDExtensionStringNamePtr name;
it->class_name._native_ptr(), // GDExtensionStringNamePtr class_name;
it->hint, // uint32_t hint;
it->hint_string._native_ptr(), // GDExtensionStringPtr hint_string;
it->usage, // uint32_t usage;
});
}
GDExtensionPropertyInfo *return_value_info = return_value_and_arguments_gdextension_info.ptr();
GDExtensionClassMethodArgumentMetadata *return_value_metadata = return_value_and_arguments_metadata.ptr();
GDExtensionPropertyInfo *arguments_info = return_value_and_arguments_gdextension_info.ptr() + 1;
GDExtensionClassMethodArgumentMetadata *arguments_metadata = return_value_and_arguments_metadata.ptr() + 1;
GDExtensionPropertyInfo *return_value_info = return_value_and_arguments_gdextension_info.data();
GDExtensionClassMethodArgumentMetadata *return_value_metadata = return_value_and_arguments_metadata.data();
GDExtensionPropertyInfo *arguments_info = return_value_and_arguments_gdextension_info.data() + 1;
GDExtensionClassMethodArgumentMetadata *arguments_metadata = return_value_and_arguments_metadata.data() + 1;
StringName name = p_method->get_name();
GDExtensionClassMethodInfo method_info = {
@@ -227,17 +229,17 @@ void ClassDB::bind_method_godot(const StringName &p_class_name, MethodBind *p_me
arguments_info, // GDExtensionPropertyInfo *
arguments_metadata, // GDExtensionClassMethodArgumentMetadata *
(uint32_t)p_method->get_default_argument_count(), // uint32_t default_argument_count;
def_args.ptr(), // GDExtensionVariantPtr *default_arguments;
def_args.data(), // GDExtensionVariantPtr *default_arguments;
};
internal::gdextension_interface_classdb_register_extension_class_method(internal::library, p_class_name._native_ptr(), &method_info);
}
void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(p_class);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
ClassInfo &cl = type_it->value;
ClassInfo &cl = type_it->second;
// Check if this signal is already register
ClassInfo *check = &cl;
@@ -250,7 +252,7 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal)
cl.signal_names.insert(p_signal.name);
// register our signal in godot
LocalVector<GDExtensionPropertyInfo> parameters;
std::vector<GDExtensionPropertyInfo> parameters;
parameters.reserve(p_signal.arguments.size());
for (const PropertyInfo &par : p_signal.arguments) {
@@ -264,15 +266,15 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal)
});
}
internal::gdextension_interface_classdb_register_extension_class_signal(internal::library, cl.name._native_ptr(), p_signal.name._native_ptr(), parameters.ptr(), parameters.size());
internal::gdextension_interface_classdb_register_extension_class_signal(internal::library, cl.name._native_ptr(), p_signal.name._native_ptr(), parameters.data(), parameters.size());
}
void ClassDB::bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield) {
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(p_class_name);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class_name);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class_name)));
ClassInfo &type = type_it->value;
ClassInfo &type = type_it->second;
// check if it already exists
ERR_FAIL_COND_MSG(type.constant_names.find(p_constant_name) != type.constant_names.end(), String("Constant '{0}::{1}' already registered.").format(Array::make(p_class_name, p_constant_name)));
@@ -290,17 +292,17 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens
const StringName *class_name = reinterpret_cast<const StringName *>(p_userdata);
const StringName *name = reinterpret_cast<const StringName *>(p_name);
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(*class_name);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(*class_name);
ERR_FAIL_COND_V_MSG(type_it == classes.end(), nullptr, String("Class '{0}' doesn't exist.").format(Array::make(*class_name)));
const ClassInfo *type = &type_it->value;
const ClassInfo *type = &type_it->second;
// Find method in current class, or any of its parent classes (Godot classes not included)
while (type != nullptr) {
AHashMap<StringName, ClassInfo::VirtualMethod>::ConstIterator method_it = type->virtual_methods.find(*name);
std::unordered_map<StringName, ClassInfo::VirtualMethod>::const_iterator method_it = type->virtual_methods.find(*name);
if (method_it != type->virtual_methods.end() && method_it->value.hash == p_hash) {
return method_it->value.func;
if (method_it != type->virtual_methods.end() && method_it->second.hash == p_hash) {
return method_it->second.func;
}
type = type->parent_ptr;
@@ -310,9 +312,9 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens
}
const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbacks(const StringName &p_class) {
AHashMap<StringName, const GDExtensionInstanceBindingCallbacks *>::Iterator callbacks_it = instance_binding_callbacks.find(p_class);
std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *>::iterator callbacks_it = instance_binding_callbacks.find(p_class);
if (likely(callbacks_it != instance_binding_callbacks.end())) {
return callbacks_it->value;
return callbacks_it->second;
}
// If we don't have an instance binding callback for the given class, find the closest parent where we do.
@@ -323,14 +325,14 @@ const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbac
callbacks_it = instance_binding_callbacks.find(class_name);
} while (callbacks_it == instance_binding_callbacks.end());
return callbacks_it->value;
return callbacks_it->second;
}
void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call, uint32_t p_hash) {
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(p_class);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
ClassInfo &type = type_it->value;
ClassInfo &type = type_it->second;
ERR_FAIL_COND_MSG(type.method_map.find(p_method) != type.method_map.end(), String("Method '{0}::{1}()' already registered as non-virtual.").format(Array::make(p_class, p_method)));
ERR_FAIL_COND_MSG(type.virtual_methods.find(p_method) != type.virtual_methods.end(), String("Virtual '{0}::{1}()' method already registered.").format(Array::make(p_class, p_method)));
@@ -342,7 +344,7 @@ void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p
}
void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names) {
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(p_class);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
GDExtensionClassVirtualMethodInfo mi;
@@ -386,12 +388,21 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
}
}
void ClassDB::_editor_get_classes_used_callback(GDExtensionTypePtr p_packed_string_array) {
PackedStringArray *arr = reinterpret_cast<PackedStringArray *>(p_packed_string_array);
arr->resize(instance_binding_callbacks.size());
int index = 0;
for (const std::pair<const StringName, const GDExtensionInstanceBindingCallbacks *> &pair : instance_binding_callbacks) {
(*arr)[index++] = pair.first;
}
}
void ClassDB::initialize_class(const ClassInfo &p_cl) {
}
void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
for (const KeyValue<StringName, ClassInfo> &pair : classes) {
const ClassInfo &cl = pair.value;
for (const std::pair<const StringName, ClassInfo> &pair : classes) {
const ClassInfo &cl = pair.second;
if (cl.level != p_level) {
continue;
}
@@ -402,8 +413,8 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
std::set<StringName> to_erase;
for (int i = class_register_order.size() - 1; i >= 0; --i) {
const StringName &name = class_register_order[i];
for (std::vector<StringName>::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) {
const StringName &name = *i;
const ClassInfo &cl = classes[name];
if (cl.level != p_level) {
@@ -412,8 +423,8 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
internal::gdextension_interface_classdb_unregister_extension_class(internal::library, name._native_ptr());
for (const KeyValue<StringName, MethodBind *> &method : cl.method_map) {
memdelete(method.value);
for (const std::pair<const StringName, MethodBind *> &method : cl.method_map) {
memdelete(method.second);
}
classes.erase(name);
@@ -421,24 +432,26 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
}
{
for (const StringName &x : to_erase) {
class_register_order.erase(x);
}
// The following is equivalent to c++20 `std::erase_if(class_register_order, [&](const StringName& name){ return to_erase.contains(name); });`
std::vector<StringName>::iterator it = std::remove_if(class_register_order.begin(), class_register_order.end(), [&](const StringName &p_name) {
return to_erase.count(p_name) > 0;
});
class_register_order.erase(it, class_register_order.end());
}
if (p_level == GDEXTENSION_INITIALIZATION_CORE) {
// Make a new list of the singleton objects, since freeing the instance bindings will lead to
// elements getting removed from engine_singletons.
LocalVector<Object *> singleton_objects;
std::vector<Object *> singleton_objects;
{
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
singleton_objects.reserve(engine_singletons.size());
for (const KeyValue<StringName, Object *> &pair : engine_singletons) {
singleton_objects.push_back(pair.value);
for (const std::pair<const StringName, Object *> &pair : engine_singletons) {
singleton_objects.push_back(pair.second);
}
}
for (const Object *i : singleton_objects) {
internal::gdextension_interface_object_free_instance_binding((*i)._owner, internal::token);
for (std::vector<Object *>::iterator i = singleton_objects.begin(); i != singleton_objects.end(); i++) {
internal::gdextension_interface_object_free_instance_binding((*i)->_owner, internal::token);
}
}
}

View File

@@ -56,11 +56,11 @@ void MethodBind::set_name(const StringName &p_name) {
name = p_name;
}
void MethodBind::set_argument_names(const LocalVector<StringName> &p_names) {
void MethodBind::set_argument_names(const std::vector<StringName> &p_names) {
argument_names = p_names;
}
LocalVector<StringName> MethodBind::get_argument_names() const {
std::vector<StringName> MethodBind::get_argument_names() const {
return argument_names;
}

View File

@@ -60,7 +60,7 @@ Object *get_object_instance_binding(GodotObject *p_engine_object) {
return reinterpret_cast<Object *>(gdextension_interface_object_get_instance_binding(p_engine_object, token, binding_callbacks));
}
TypedArray<Dictionary> convert_property_list(const LocalVector<PropertyInfo> &p_list) {
TypedArray<Dictionary> convert_property_list(const std::vector<PropertyInfo> &p_list) {
TypedArray<Dictionary> va;
for (const PropertyInfo &pi : p_list) {
va.push_back(Dictionary(pi));

View File

@@ -49,10 +49,10 @@ GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_address = null
GDExtensionClassLibraryPtr library = nullptr;
void *token = nullptr;
GDExtensionGodotVersion godot_version = { 0, 0, 0, nullptr };
GDExtensionGodotVersion2 godot_version = {};
// All of the GDExtension interface functions.
GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version = nullptr;
GDExtensionInterfaceGetGodotVersion2 gdextension_interface_get_godot_version2 = nullptr;
GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc = nullptr;
GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc = nullptr;
GDExtensionInterfaceMemFree gdextension_interface_mem_free = nullptr;
@@ -164,7 +164,6 @@ GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed
GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const = nullptr;
GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index = nullptr;
GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const = nullptr;
GDExtensionInterfaceArrayRef gdextension_interface_array_ref = nullptr;
GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed = nullptr;
GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index = nullptr;
GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const = nullptr;
@@ -190,10 +189,12 @@ GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr;
GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3 = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update = nullptr;
GDExtensionInterfaceObjectGetScriptInstance gdextension_interface_object_get_script_instance = nullptr;
GDExtensionInterfaceObjectSetScriptInstance gdextension_interface_object_set_script_instance = nullptr;
GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2 = nullptr;
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClass5 gdextension_interface_classdb_register_extension_class5 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
@@ -206,10 +207,12 @@ GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classd
GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path = nullptr;
GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin = nullptr;
GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin = nullptr;
GDExtensionInterfaceEditorRegisterGetClassesUsedCallback gdextension_interface_editor_register_get_classes_used_callback = nullptr;
GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars = nullptr;
GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len = nullptr;
GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw = nullptr;
GDExtensionInterfaceImagePtr gdextension_interface_image_ptr = nullptr;
GDExtensionInterfaceRegisterMainLoopCallbacks gdextension_interface_register_main_loop_callbacks = nullptr;
struct DocData {
const char *hash = nullptr;
@@ -307,8 +310,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
internal::library = p_library;
internal::token = p_library;
LOAD_PROC_ADDRESS(get_godot_version, GDExtensionInterfaceGetGodotVersion);
internal::gdextension_interface_get_godot_version(&internal::godot_version);
LOAD_PROC_ADDRESS(get_godot_version2, GDExtensionInterfaceGetGodotVersion2);
internal::gdextension_interface_get_godot_version2(&internal::godot_version);
// Check that godot-cpp was compiled using an extension_api.json older or at the
// same version as the Godot that is loading it.
@@ -446,7 +449,6 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(packed_vector4_array_operator_index_const, GDExtensionInterfacePackedVector4ArrayOperatorIndexConst);
LOAD_PROC_ADDRESS(array_operator_index, GDExtensionInterfaceArrayOperatorIndex);
LOAD_PROC_ADDRESS(array_operator_index_const, GDExtensionInterfaceArrayOperatorIndexConst);
LOAD_PROC_ADDRESS(array_ref, GDExtensionInterfaceArrayRef);
LOAD_PROC_ADDRESS(array_set_typed, GDExtensionInterfaceArraySetTyped);
LOAD_PROC_ADDRESS(dictionary_operator_index, GDExtensionInterfaceDictionaryOperatorIndex);
LOAD_PROC_ADDRESS(dictionary_operator_index_const, GDExtensionInterfaceDictionaryOperatorIndexConst);
@@ -472,10 +474,12 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(script_instance_create3, GDExtensionInterfaceScriptInstanceCreate3);
LOAD_PROC_ADDRESS(placeholder_script_instance_create, GDExtensionInterfacePlaceHolderScriptInstanceCreate);
LOAD_PROC_ADDRESS(placeholder_script_instance_update, GDExtensionInterfacePlaceHolderScriptInstanceUpdate);
LOAD_PROC_ADDRESS(object_get_script_instance, GDExtensionInterfaceObjectGetScriptInstance);
LOAD_PROC_ADDRESS(object_set_script_instance, GDExtensionInterfaceObjectSetScriptInstance);
LOAD_PROC_ADDRESS(classdb_construct_object2, GDExtensionInterfaceClassdbConstructObject2);
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
LOAD_PROC_ADDRESS(classdb_register_extension_class4, GDExtensionInterfaceClassdbRegisterExtensionClass4);
LOAD_PROC_ADDRESS(classdb_register_extension_class5, GDExtensionInterfaceClassdbRegisterExtensionClass5);
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_virtual_method, GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
@@ -488,10 +492,12 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(get_library_path, GDExtensionInterfaceGetLibraryPath);
LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
LOAD_PROC_ADDRESS(editor_register_get_classes_used_callback, GDExtensionInterfaceEditorRegisterGetClassesUsedCallback);
LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars);
LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars_and_len, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen);
LOAD_PROC_ADDRESS(image_ptrw, GDExtensionInterfaceImagePtrw);
LOAD_PROC_ADDRESS(image_ptr, GDExtensionInterfaceImagePtr);
LOAD_PROC_ADDRESS(register_main_loop_callbacks, GDExtensionInterfaceRegisterMainLoopCallbacks);
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
@@ -522,7 +528,13 @@ void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializ
}
level_initialized[p_level]++;
if ((ModuleInitializationLevel)p_level == MODULE_INITIALIZATION_LEVEL_CORE && init_data && init_data->has_main_loop_callbacks()) {
internal::gdextension_interface_register_main_loop_callbacks(internal::library, &init_data->main_loop_callbacks);
}
if ((ModuleInitializationLevel)p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
internal::gdextension_interface_editor_register_get_classes_used_callback(internal::library, &ClassDB::_editor_get_classes_used_callback);
const internal::DocData &doc_data = internal::get_doc_data();
if (doc_data.is_valid()) {
doc_data.load_data();
@@ -590,6 +602,18 @@ void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(Mo
init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
}
void GDExtensionBinding::InitObject::register_startup_callback(GDExtensionMainLoopStartupCallback p_callback) const {
init_data->main_loop_callbacks.startup_func = p_callback;
}
void GDExtensionBinding::InitObject::register_frame_callback(GDExtensionMainLoopFrameCallback p_callback) const {
init_data->main_loop_callbacks.frame_func = p_callback;
}
void GDExtensionBinding::InitObject::register_shutdown_callback(GDExtensionMainLoopShutdownCallback p_callback) const {
init_data->main_loop_callbacks.shutdown_func = p_callback;
}
GDExtensionBool GDExtensionBinding::InitObject::init() const {
return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
}

View File

@@ -232,10 +232,6 @@ void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Var
internal::gdextension_interface_array_set_typed((GDExtensionTypePtr *)this, (GDExtensionVariantType)p_type, (GDExtensionConstStringNamePtr)&p_class_name, (GDExtensionConstVariantPtr)&p_script);
}
void Array::_ref(const Array &p_from) const {
internal::gdextension_interface_array_ref((GDExtensionTypePtr *)this, (GDExtensionConstTypePtr *)&p_from);
}
const Variant *Array::ptr() const {
return (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}

View File

@@ -287,6 +287,13 @@ func _ready():
assert_equal(library_path, ProjectSettings.globalize_path(library_path))
assert_equal(FileAccess.file_exists(library_path), true)
# Test that internal classes work as expected (at least for Godot 4.5+).
assert_equal(ClassDB.can_instantiate("ExampleInternal"), false)
assert_equal(ClassDB.instantiate("ExampleInternal"), null)
var internal_class = example.test_get_internal_class()
assert_equal(internal_class.get_the_answer(), 42)
assert_equal(internal_class.get_class(), "ExampleInternal")
# Test a class with a unicode name.
var przykład = ExamplePrzykład.new()
assert_equal(przykład.get_the_word(), "słowo to przykład")

View File

@@ -252,6 +252,8 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_use_engine_singleton"), &Example::test_use_engine_singleton);
ClassDB::bind_method(D_METHOD("test_get_internal_class"), &Example::test_get_internal_class);
ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static);
ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
@@ -744,6 +746,12 @@ String Example::test_library_path() {
return library_path;
}
Ref<RefCounted> Example::test_get_internal_class() const {
Ref<ExampleInternal> it;
it.instantiate();
return it;
}
int64_t Example::test_get_internal(const Variant &p_input) const {
if (p_input.get_type() != Variant::INT) {
return -1;
@@ -779,3 +787,11 @@ void ExamplePrzykład::_bind_methods() {
String ExamplePrzykład::get_the_word() const {
return U"słowo to przykład";
}
void ExampleInternal::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_the_answer"), &ExampleInternal::get_the_answer);
}
int ExampleInternal::get_the_answer() const {
return 42;
}

View File

@@ -29,6 +29,8 @@
using namespace godot;
class ExampleInternal;
class ExampleRef : public RefCounted {
GDCLASS(ExampleRef, RefCounted);
@@ -203,6 +205,8 @@ public:
String test_use_engine_singleton() const;
static String test_library_path();
Ref<RefCounted> test_get_internal_class() const;
};
VARIANT_ENUM_CAST(Example::Constants);
@@ -288,3 +292,13 @@ protected:
public:
String get_the_word() const;
};
class ExampleInternal : public RefCounted {
GDCLASS(ExampleInternal, RefCounted);
protected:
static void _bind_methods();
public:
int get_the_answer() const;
};

View File

@@ -31,6 +31,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(ExampleChild);
GDREGISTER_RUNTIME_CLASS(ExampleRuntime);
GDREGISTER_CLASS(ExamplePrzykład);
GDREGISTER_INTERNAL_CLASS(ExampleInternal);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {

View File

@@ -9,12 +9,12 @@ def options(opts):
opts.Add(
"android_api_level",
"Target Android API level",
"21",
"24",
)
opts.Add(
"ndk_version",
"Fully qualified version of ndk to use for compilation.",
"23.2.8568313",
"28.1.13356709",
)
opts.Add(
"ANDROID_HOME",
@@ -48,9 +48,9 @@ def generate(env):
my_spawn.configure(env)
# Validate API level
if int(env["android_api_level"]) < 21:
print("WARNING: minimum supported Android target api is 21. Forcing target api 21.")
env["android_api_level"] = "21"
if int(env["android_api_level"]) < 24:
print("WARNING: minimum supported Android target api is 24. Forcing target api 24.")
env["android_api_level"] = "24"
# Setup toolchain
toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"

View File

@@ -2,7 +2,6 @@ import os
import platform
import sys
import header_builders
from SCons import __version__ as scons_raw_version
from SCons.Action import Action
from SCons.Builder import Builder
@@ -530,10 +529,6 @@ def generate(env):
BUILDERS={
"GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files),
"GodotCPPDocData": Builder(action=scons_generate_doc_source),
"GLSL_HEADER": Builder(
action=header_builders.build_raw_headers_action,
suffix="glsl.gen.h",
),
}
)
env.AddMethod(_godot_cpp, "GodotCPP")

View File

@@ -1,69 +0,0 @@
import os.path
## See https://github.com/godotengine/godot/blob/master/glsl_builders.py
def build_raw_header(source_filename: str, constant_name: str) -> None:
# Read the source file content.
with open(source_filename, "r") as source_file:
source_content = source_file.read()
constant_name = constant_name.replace(".", "_")
# Build header content using a C raw string literal.
header_content = (
"/* THIS FILE IS GENERATED. EDITS WILL BE LOST. */\n\n"
"#pragma once\n\n"
f"inline constexpr const char *{constant_name}"
" = "
f'R"<!>({source_content})<!>"'
";\n"
)
# Write the header to the provided file name with a ".gen.h" suffix.
header_filename = f"{source_filename}.gen.h"
with open(header_filename, "w") as header_file:
header_file.write(header_content)
def build_raw_headers_action(target, source, env):
env.NoCache(target)
for src in source:
source_filename = str(src)
# To match Godot, replace ".glsl" with "_shader_glsl". Does nothing for non-GLSL files.
constant_name = os.path.basename(source_filename).replace(".glsl", "_shader_glsl")
build_raw_header(source_filename, constant_name)
def escape_svg(filename: str) -> str:
with open(filename, encoding="utf-8", newline="\n") as svg_file:
svg_content = svg_file.read()
return f'R"<!>({svg_content})<!>"'
## See https://github.com/godotengine/godot/blob/master/editor/icons/editor_icons_builders.py
## See https://github.com/godotengine/godot/blob/master/scene/theme/icons/default_theme_icons_builders.py
def make_svg_icons_action(target, source, env):
destination = str(target[0])
constant_prefix = os.path.basename(destination).replace(".gen.h", "")
svg_icons = [str(x) for x in source]
# Convert the SVG icons to escaped strings and convert their names to C strings.
icon_names = [f'"{os.path.basename(fname)[:-4]}"' for fname in svg_icons]
icon_sources = [escape_svg(fname) for fname in svg_icons]
# Join them as indented comma-separated items for use in an array initializer.
icon_names_str = ",\n\t".join(icon_names)
icon_sources_str = ",\n\t".join(icon_sources)
# Write the file to disk.
with open(destination, "w", encoding="utf-8", newline="\n") as destination_file:
destination_file.write(
f"""\
/* THIS FILE IS GENERATED. EDITS WILL BE LOST. */
#pragma once
inline constexpr int {constant_prefix}_count = {len(icon_names)};
inline constexpr const char *{constant_prefix}_sources[] = {{
{icon_sources_str}
}};
inline constexpr const char *{constant_prefix}_names[] = {{
{icon_names_str}
}};
"""
)

View File

@@ -5,7 +5,7 @@ from SCons.Variables import BoolVariable
def options(opts):
opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler - only effective when targeting Linux", False))
opts.Add(BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False))
opts.Add(BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True))
def exists(env):