Compare commits

..

703 Commits

Author SHA1 Message Date
Serhii Snitsaruk 1a192b6129
Port BBParam editor to GDExtension (#287) 2025-02-18 12:39:47 +01:00
Serhii Snitsaruk 8e3f37d46a
GHA: Update Godot version used in GDExtension workflow 2025-02-16 14:27:29 +01:00
Serhii Snitsaruk 98778c1645
GHA: Test with `strict_checks=yes` 2025-02-16 13:06:13 +01:00
Serhii Snitsaruk 7ca4c63191
Update demo due to 4.4 changes 2025-02-16 13:01:39 +01:00
Serhii Snitsaruk 8788d8bf12
Bump version to 1.4.0-dev 2025-02-16 12:59:26 +01:00
Serhii Snitsaruk f31d722320
Merge pull request #223 from Rubonnek/support-godot-4.4
Support Godot 4.4
2025-02-16 12:52:15 +01:00
Wilson E. Alvarez bbb4512437
Add guards around PROPERTY_HINT_NO_NODEPATH which is not available in GDExtension 2025-02-15 11:29:36 -05:00
Wilson E. Alvarez 43ec612949
Fix broken conversion: Ref<Script> to const String 2025-02-15 09:48:16 -05:00
Wilson E. Alvarez 998bf212b7
Fix unhandled PROPERTY_HINT_NO_NODEPATH warning
Due to upstream change:

	6f7525c396
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez ec8eb4bf91
Override renamed EditorPlugin::get_name() method
Due to upstream change:

	0ab3dc273e
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez 05cd3e67b0
Refactor EditorHelpBit usage
Due to upstream change:

	4e19ab8afe
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez ed9762e62f
Fix unhandled PROPERTY_HINT_ONESHOT warning
Due to upstream change:

	761a20f7a7
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez ac0b68aa13
Fix forbidden comparisons between Ref and nullptr.
Necessary when compiling with strict_checks=yes.

Due to upstream change:

	df29cc696f
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez c3da26caba
Fix internal Button set_icon calls to set_button_icon
Due to upstream change:

    562c666e3d
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez e9f6a6fea5
Fix unhandled PROPERTY_HINT_TOOL_BUTTON warning
Due to upstream change:

	85dfd89653
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez c3144875df
Fix unhandled PROPERTY_HINT_DICTIONARY_TYPE warning
Due to upstream change:

	9853a69144
2025-02-15 09:48:16 -05:00
Wilson E. Alvarez e37ff39641
Update EditorMainScreen calls after its extraction
Due to upstream change:

	5e1c9d68aa
2025-02-15 09:48:16 -05:00
Serhii Snitsaruk 6292ee4404
chore: Move `update_rst` to `scripts/` dir 2025-02-15 13:40:54 +01:00
Serhii Snitsaruk 77dc9b3b85
GHA: Build editor targets for iOS & web GDExtension libs (#285)
Compile iOS & Web GDExtension libs with editor support.
2025-02-13 11:58:03 +01:00
Serhii Snitsaruk 88701e9f20
GDExtension: Build Android libs with editor features (#284)
Also, fix the macOS Vulkan SDK installation step in CI.

Resolves GH-282.
2025-02-12 12:05:50 +01:00
Serhii Snitsaruk 576df4092a
Bump version to 1.3.1 2025-02-02 21:22:51 +01:00
Serhii Snitsaruk b8f266588a
Fix duplicate UI banners (#279)
During the editor launch, duplicate UI banners may appear in the LimboAI tab. Maybe in some other instances too. This PR fixes this issue.
2025-02-02 21:19:58 +01:00
Serhii Snitsaruk eac7e56f42
Doc: Mention pre-built templates (#280) 2025-02-02 19:45:54 +01:00
namelessvoid 7aebed5897
Update Readme to accomodate new documentation structure
(cherry picked from commit fe87a87759)
2025-01-22 01:18:37 +01:00
Steven Schoen a6613c32f9
Navigate to subtree resource when clicked in editor (#276)
Co-authored-by: Steven Schoen <digisteve5@gmail.com>
2025-01-22 01:05:51 +01:00
Serhii Snitsaruk 76e02a75e5
Fix BTInstance not registered with debugger on BTPlayer.set_bt_instance() (#275) 2025-01-21 23:43:52 +01:00
Serhii Snitsaruk 1b9cf17339
Fix BTPlayer.set_behavior_tree() not populating Blackboard (#274) 2025-01-21 23:35:28 +01:00
Serhii Snitsaruk 0584b0401f
Bump version to 1.4.0-dev 2025-01-21 12:00:35 +01:00
Serhii Snitsaruk 98917a2055
Bump version to 1.3.0 2025-01-21 03:18:11 +01:00
Serhii Snitsaruk 10defe21a5
Update copyright notices across the project files & in LICENSE.md (#272)
* Include LimboAI contributors in the notice
* Clarify first year of publication as copyright year
2025-01-21 02:18:59 +01:00
Laurent Senta 3dcbee829c
doc: clarify scoping for BTState (#271) 2025-01-10 16:42:09 +01:00
Serhii Snitsaruk e3be34670e
Doc: Clarify how to access objects on the blackboard that may be freed 2025-01-05 20:53:53 +01:00
Dave Palais e3262108d7
Amend logic error in `BlackboardPlan` variable listing (#269) 2025-01-03 02:33:29 +01:00
Dave Palais b144ebc7bc
Do not show warning for NIL type BlackboardPlan variables on BBParam. (#267)
Enable variable mapping for NIL type public BlackboardPlan variables.
2025-01-01 18:14:39 +01:00
Serhii Snitsaruk 672f92c87b
Update doc 2024-12-30 01:24:52 +01:00
Serhii Snitsaruk e2e42b90a8 Fix documentation links in the editor 2024-12-29 16:03:21 -08:00
Serhii Snitsaruk a952009293
Add `Blackboard.print_state()` (#264)
Method that prints values of all variables in each scope.
2024-12-29 23:45:59 +01:00
Pheubel 0982804a86
Remove arbitrary limit on user task directories (#263)
Resolves GH-256
2024-12-28 19:03:51 +01:00
Serhii Snitsaruk dd427c25e2
Revert "Update Readme to accomodate new documentation structure"
This reverts commit fe87a87759.
2024-12-18 21:18:08 +01:00
Serhii Snitsaruk dddc713a3a
Merge pull request #261 from limbonaut/fix-crash-with-vscode-and-gdextension
Fix crash with VSCode and GDExtension
2024-12-17 23:54:21 +01:00
Serhii Snitsaruk 6fecc1e4b5
Merge pull request #262 from namelessvoid/re-arrange-documentation
Suggestion on re-arranging the docs
2024-12-17 23:35:56 +01:00
namelessvoid fe87a87759 Update Readme to accomodate new documentation structure 2024-12-17 20:14:51 +01:00
Simon Kerler 0e0a4685f9
De-duplicated info about pros/cons of GDExtension vs Module
Co-authored-by: Serhii Snitsaruk <limbonaut@pm.me>
2024-12-17 19:47:45 +01:00
Simon Kerler 955da07652
Remove outdated info about built-in documentation
Co-authored-by: Serhii Snitsaruk <limbonaut@pm.me>
2024-12-17 19:42:27 +01:00
namelessvoid 90c0a9a4f6 Merge remote-tracking branch 'origin/master' into re-arrange-documentation 2024-12-17 00:51:05 +01:00
namelessvoid 1359f1e606 Merge BT debugging docs into 'Creating BT' chapter 2024-12-17 00:33:47 +01:00
namelessvoid 0d65c1117a Remove now redundant page from documentation 2024-12-17 00:23:32 +01:00
Serhii Snitsaruk a5118ebc1b
Fix crash while using callable_mp in GDExtension 2024-12-17 00:11:16 +01:00
Serhii Snitsaruk 17872e7048
Fix broken syntax in docs 2024-12-16 22:19:54 +01:00
Serhii Snitsaruk f7a63ca673
Merge pull request #260 from limbonaut/doc-contributing
Doc: Add Contributing page
2024-12-16 22:04:00 +01:00
Serhii Snitsaruk 691208016c
Doc: Add Contributing page 2024-12-16 22:03:59 +01:00
namelessvoid 35a2cbac56 Re-arrange documentation 2024-12-16 21:47:20 +01:00
Serhii Snitsaruk db827a8d30
Merge pull request #258 from namelessvoid/fix-typo-in-example
Add missing 'not' in HSM state example
2024-12-16 12:36:22 +01:00
namelessvoid 360e24c330 Add missing 'not' in HSM state example 2024-12-16 00:43:46 +01:00
Serhii Snitsaruk e9884589a8
Doc: Add offline formats 2024-12-11 20:28:42 +01:00
Serhii Snitsaruk 9cfdabca3f
Merge pull request #255 from limbonaut/fix-setting-bt-crash
Fix: Keep `BTInstance` alive until update is finished (fixes #254)
2024-12-04 18:15:55 +01:00
Serhii Snitsaruk 23a6e5fdfe
Fix: Keep `BTInstance` alive until update is finished
Fixes #254
2024-12-04 17:57:11 +01:00
Serhii Snitsaruk 6644f191ca
Merge pull request #252 from limbonaut/gha-mingw-windows
GHA: Improve Windows builds: MinGW/GCC with LTO, D3D12, ANGLE
2024-12-01 22:35:44 +01:00
Serhii Snitsaruk 8b0b15fce4
GHA: Fix scons cache in test builds 2024-12-01 18:44:31 +01:00
Serhii Snitsaruk 11548c51f0
GHA: Fix build name missing in Windows builds 2024-12-01 18:35:21 +01:00
Serhii Snitsaruk 62a142f188
GHA: Compile with D3D12 support and Mesa libs 2024-12-01 16:46:27 +01:00
Serhii Snitsaruk 7a3d5bc6a2
GHA: Compile Windows builds with statically linked ANGLE 2024-12-01 16:46:21 +01:00
Serhii Snitsaruk 6d79b7474e
GHA: Don't use SCons cache in release builds 2024-12-01 16:28:10 +01:00
Serhii Snitsaruk 44040dda06
GHA: Build Windows binaries using MinGW/GCC in a docker container 2024-12-01 16:28:03 +01:00
Serhii Snitsaruk ba90deaa6a
Merge pull request #245 from limbonaut/editor-prop-binding
Feature: Bind `BlackboardPlan` variables to node properties in the Inspector
2024-11-15 11:35:13 -08:00
Serhii Snitsaruk 08d8fcdf92
Don't show binding/mapping for hidden variables 2024-11-15 18:50:42 +01:00
Serhii Snitsaruk 51878e4b6e
Limit a variable to either binding or mapping, but not both at once 2024-11-15 18:15:40 +01:00
Serhii Snitsaruk 008702b1e4
Fix template compilation 2024-11-11 11:43:26 +01:00
Serhii Snitsaruk 6e8c22d598
Clean up & strengthen code 2024-11-11 10:24:14 +01:00
Serhii Snitsaruk 0b3b11a383
Enable binding in BehaviorTree-owned blackboard plan 2024-11-11 10:13:41 +01:00
Serhii Snitsaruk 4cac6276aa
Fix GDExtension issues 2024-11-11 10:01:20 +01:00
Serhii Snitsaruk ea671dd54b
Improve binding presentation within inspector, fix compilation issues 2024-11-11 09:49:01 +01:00
Serhii Snitsaruk bc7f677810
Specialized inspector property editor for NodePath 2024-11-11 08:24:54 +01:00
Serhii Snitsaruk 057d4e669c
Bind variables to scene node properties upon runtime Blackboard creation 2024-11-10 19:58:35 +01:00
Serhii Snitsaruk f600d633a3
Store property bindings in BlackboardPlan 2024-11-10 19:08:56 +01:00
Serhii Snitsaruk ae61d551c0
Doc: Clarify when `LimboState::_exit` is called 2024-11-05 19:41:16 +01:00
Serhii Snitsaruk a14cc4cc68
GHA: Use 4.3-stable in "All builds" 2024-11-05 19:16:41 +01:00
Serhii Snitsaruk d304f957ef
Merge pull request #244 from limbonaut/save-builtin-bt-on-ctrls
Improve workflow with built-in BT resources
2024-11-05 01:40:51 -08:00
Serhii Snitsaruk bf85350260
Open the owner scene when switching to a built-in BT 2024-11-04 19:45:54 +01:00
Serhii Snitsaruk 03476721d9
Change shortcut for "Jump to Owner"
Ctrl+J is no longer available by default
2024-11-04 15:52:42 +01:00
Serhii Snitsaruk bebd6a15eb
Save edited built-in BT resource on `Ctrl+S` 2024-11-04 14:52:35 +01:00
Serhii Snitsaruk 4c9028fc66
Merge pull request #243 from limbonaut/fix-builtin-resource-save
Improve saving for built-in BTs attached to scenes
2024-11-03 01:59:52 -08:00
Serhii Snitsaruk e21156df35
Save external BTs on plugin callback
Also fixes dirty state handling, however it's currently unused.
2024-11-02 15:41:34 +01:00
Serhii Snitsaruk 591a1fe672
Improve saving for built-in BTs attached to scenes 2024-11-01 22:22:23 +01:00
Serhii Snitsaruk f90c48eb81
Merge pull request #242 from limbonaut/fix-hsm-reparenting-saga-episode-three
Fix re-parenting an agent interrupts its state machine
2024-11-01 11:11:45 -07:00
Serhii Snitsaruk 162de0f868
Fix re-parenting agent interrupts its state machine 2024-11-01 18:47:36 +01:00
Serhii Snitsaruk 423c4ce7a4
Merge pull request #241 from limbonaut/hsm-transition-guards
`LimboHSM`: Ability to specify per-transition guard function
2024-11-01 07:49:20 -07:00
Serhii Snitsaruk a5d59a0a51
Update docs 2024-11-01 15:24:32 +01:00
Serhii Snitsaruk 85eda3c804
Tests for per-transition guards 2024-11-01 14:59:10 +01:00
Serhii Snitsaruk 6de8b9e4c4
Merge pull request #227 from limbonaut/fix-bttask-setup-overriding
Call both native and script `_setup/_enter/_exit` in BTTask
2024-11-01 06:19:13 -07:00
Serhii Snitsaruk bbe71bb378
Add transition guards 2024-11-01 14:00:30 +01:00
Serhii Snitsaruk 7feff38d6b
Call both native and script _enter/_exit in BTTask 2024-11-01 13:50:08 +01:00
Serhii Snitsaruk 632e26c922
Call both native and script's `_setup()` in BTTask
Current behavior is overriding, which is not correct as it's an initializer function.
2024-11-01 13:42:49 +01:00
Serhii Snitsaruk 106608aca9
Merge pull request #239 from limbonaut/fix-clone-bttask-and-arrays
Duplicate `BBParam` instances in typed arrays in `BTTask::clone()`
2024-10-28 09:17:39 -07:00
Serhii Snitsaruk d5bc62830a
Duplicate BBParam instances inside arrays in `BTTask::clone()`
Fixes issue with `CallMethod` arguments being shared between tasks after duplication.
2024-10-28 15:06:29 +01:00
Serhii Snitsaruk 3b15abf2c9
GHA: Fix vulkan sdk in ios packaging 2024-10-19 22:09:03 +02:00
Serhii Snitsaruk 6d049a3701
Merge pull request #237 from limbonaut/gha-ios-vulkan
GHA: Fix Vulkan SDK on iOS
2024-10-19 11:35:28 -07:00
Serhii Snitsaruk 65454c36a8
GHA: Fix Vulkan SDK on iOS 2024-10-19 20:04:48 +02:00
Serhii Snitsaruk e0e15b0ec4
Merge pull request #163 from limbonaut/gha-gdext-ios
GHA: Build iOS GDExtension libraries
2024-10-17 06:23:06 -07:00
Serhii Snitsaruk ee8c773e71
GHA: Build with ios_simulator=yes flag 2024-10-16 14:32:39 +02:00
Serhii Snitsaruk 7f38fe2b8b
GHA: Change iOS arch to arm64 & build simulator libs 2024-10-16 14:32:39 +02:00
Serhii Snitsaruk 500775eb14
Add iOS builds to the GDExtension manifest 2024-10-16 14:32:39 +02:00
Serhii Snitsaruk 1cdde4d5a9
GHA: Add iOS builds to GDExtension workflow 2024-10-16 14:31:56 +02:00
Serhii Snitsaruk eaa43020f5
Merge pull request #235 from limbonaut/doc-get-var-fix
Doc: Clarify `Blackboard.get_var()` and `set_var()`
2024-10-13 12:27:12 -07:00
Serhii Snitsaruk b5b1ac7289
Doc: Clarify `Blackboard.get_var()` and `set_var()` 2024-10-13 21:04:59 +02:00
Serhii Snitsaruk ece17d68d9
Merge pull request #234 from limbonaut/doc-fixes
GHA: Code style checks for PRs and commits
2024-10-13 12:03:17 -07:00
Serhii Snitsaruk 85787616e7
GHA: Add code style check for PRs and direct commits 2024-10-13 20:43:59 +02:00
Serhii Snitsaruk 11abf36c99
Clang format 2024-10-13 20:25:03 +02:00
Serhii Snitsaruk 19d771fef2
Merge pull request #229 from monxa/tasktree-search
Implement Tree Search Functionality with Highlighting and Filtering
2024-10-13 11:18:37 -07:00
Serhii Snitsaruk 2b89d1d23e
Merge pull request #233 from limbonaut/gha-fix-macos-vulkan
GHA: Fix Vulkan SDK installation step
2024-10-13 10:48:31 -07:00
Serhii Snitsaruk 6f318b83b8
GHA: Fix Vulkan SDK installation step 2024-10-13 18:25:54 +02:00
Serhii Snitsaruk 7a1b56f9c8
GHA: Switch workflows to Godot 4.3 branch 2024-10-13 17:06:25 +02:00
Alexander Montag 2b86928737
Add tooltip to explain case sensitivity behavior 2024-10-13 07:02:59 +00:00
Alexander Montag 8c557f87f7
Address 2. review for TreeSearch
Remove redundant comment

Prune tab_search_context

Fix restore tab on `_tab_closed`

Add break statement

Pass callable by reference in _draw_highlight_item

Refactor _initialize_controls into constructor

Remove redundant if (!line_edit_search)-check
2024-10-13 07:31:35 +02:00
Alexander Montag 6776319472
Implement Tree Search Functionality with Highlighting and Filtering
This commit introduces a comprehensive Tree Search feature, including:
- Tree highlighting: Highlights items that match the search query.
- Tree filtering: Filters items so only matches and descendants are
  shown.
- Counting descendants: Shows the number of matching items within collapsed branches.
- Jump to next match: on enter.
- (Limbo-)Shortcut: Default CTRL-F.
- Menu entry: Misc->Search Tree.
- Remember separate SearchInfo for each tab.

Key implementation details:
- Optimized performance for large trees
- Implemented recursive filtering for efficiency
- Added UI elements including next/previous match buttons

Development History:
- Initial implementation of highlighting and filtering
- Multiple rounds of performance optimization
- Bug fixes and refactoring for correctness
- UI enhancements and polish
- Code cleanup and style improvements
2024-10-06 06:57:11 +02:00
Serhii Snitsaruk 760af804c0
Merge pull request #230 from limbonaut/fix-docs
Fix and update docs
2024-09-30 12:36:57 +02:00
Serhii Snitsaruk c49e5142a5
Fix and update docs 2024-09-30 11:17:01 +02:00
Serhii Snitsaruk 60a767032e
Merge pull request #226 from limbonaut/fix-hsm-exit-crash
Fix invalid access errors on exit in LimboHSM
2024-09-26 16:54:31 +02:00
Serhii Snitsaruk 60142b191d
Fix invalid access crash on exit in LimboHSM
Since #131, `LimboState::_exit()` became a source of potential crashes
if object references are used without a validity check. It's too easy
to miss this, which can lead to game crashing during runtime.

This fix reverts #131 change and proposes alternative approach of
re-activating root HSM upon tree entering if it was previously active.
Note that it's not an ideal solution, as some state will be lost upon
re-parenting: HSM exits and then re-activates and enters its initial state.
2024-09-22 13:57:15 +02:00
Serhii Snitsaruk 134bb3214a
Merge pull request #225 from ydeltastar/remember-last-session
Remember loaded `BehaviorTree`s of last session
2024-09-22 13:32:56 +02:00
yds db7c990f51 Remember loaded BehaviorTrees of last session 2024-09-21 16:23:13 -03:00
Serhii Snitsaruk 08884e6180
Merge pull request #219 from monxa/fix-miscmenu-layout-duplicates
Fix duplicate entries in Misc->Layout
2024-09-17 14:42:01 +02:00
Alexander Montag c2130a7b2f Fix duplicate entries in Misc->layout
Fixes #218
2024-09-17 02:16:47 +02:00
Serhii Snitsaruk 5ddc43fe94
Merge pull request #215 from limbonaut/prefetch-with-base-plan
Prefetch nodes set directly in the BehaviorTree's BlackboardPlan
2024-09-15 17:06:55 +02:00
Serhii Snitsaruk 601aed3684
Merge pull request #216 from limbonaut/gha-debug-builds
GHA: Add an option to create GDExtension debug builds
2024-09-15 16:23:08 +02:00
Serhii Snitsaruk 0e4c06f3b8
Update class docs 2024-09-15 15:47:22 +02:00
Serhii Snitsaruk ac2d734122
Use different prefetch root for the base plan in BTPlayer and BTState 2024-09-15 15:47:11 +02:00
Serhii Snitsaruk 1ca1154cd0
Merge pull request #214 from limbonaut/fix-warnings
Fix loop variables used as copy
2024-09-15 14:36:36 +02:00
Serhii Snitsaruk a8a0f24492
BlackboardPlan: Allow passing different prefetch root for the base plan 2024-09-15 14:16:54 +02:00
Serhii Snitsaruk 50e9e570dd
Fix loop variables used as copy 2024-09-15 13:32:58 +02:00
Serhii Snitsaruk d72c2e0648
Merge pull request #213 from limbonaut/fix-setagentprop-name
Fix `BTSetAgentProperty` name generation
2024-09-14 20:23:58 +02:00
Serhii Snitsaruk da2bc5e3bb
Fix `BTSetAgentProperty` name generation 2024-09-14 19:56:31 +02:00
Serhii Snitsaruk c4481d8bed
Merge pull request #212 from limbonaut/fix-bbnode-getvalue-crash
Fix `BBNode::get_value()` crash with a freed object using GDExtension
2024-09-14 19:49:29 +02:00
Serhii Snitsaruk 689c8fab6f
Fix `BBNode::get_value()` crash with a freed object in GDExtension
It may be a bug in GDExtension. I optimized the code, and, as a workaround, removed casting to Object* from Variant. This fixed the issue. The same code worked well using module.
2024-09-14 19:30:28 +02:00
Serhii Snitsaruk fd0eb34b4e
Merge pull request #211 from limbonaut/fix-bt-for-each
Fix `BTForEach` crash if elements are removed from the array during iteration
2024-09-14 17:00:10 +02:00
Serhii Snitsaruk bfcc2f8e1b
Merge pull request #210 from ydeltastar/multi-select
Implement task multiple selection and drag and drop
2024-09-14 16:54:07 +02:00
Serhii Snitsaruk b8c9db0d44
Fix BTForEach crash if elements are removed from the array during iteration 2024-09-14 16:42:30 +02:00
yds 4df6647a75 Improve multiple drag and drop 2024-09-14 11:22:52 -03:00
Serhii Snitsaruk d78adabf7c
Bump version to 1.3-dev 2024-09-13 14:13:00 +02:00
yds 1742018696 Preserve selection after drop 2024-09-13 09:04:18 -03:00
yds a460c7898b Add drag preview 2024-09-13 09:04:18 -03:00
yds 8ee3688da2 Implement task multiple selection and drag and drop 2024-09-13 09:04:18 -03:00
Serhii Snitsaruk 9032ca0c7b
GHA: Add an option to create GDExtension debug builds 2024-09-09 13:53:42 +02:00
Serhii Snitsaruk 1cb85807dd
Fix mem leaks in the demo 2024-09-09 10:22:32 +02:00
Serhii Snitsaruk 78396708d4
Bump version to 1.2.1 2024-09-05 13:52:42 +02:00
Serhii Snitsaruk 6c86ce566c
Merge pull request #206 from limbonaut/gdextension-print-workaround
Override _to_string() to give useful info about objects in GDExtension
2024-09-05 13:48:57 +02:00
Serhii Snitsaruk 16a3bb0273
Override _to_string() to print useful info about objects in GDExtension 2024-09-05 13:39:47 +02:00
Serhii Snitsaruk ac209e7fc3
Update .gitignore 2024-09-05 11:37:18 +02:00
Serhii Snitsaruk 49b3a0ad6f
Merge pull request #205 from monxa/fix-editor-setting-gdextension
Generalize EDITOR_DEF macro to fix potential editor setting issues
2024-09-03 17:18:46 +02:00
Alexander Montag ad11f401b1 Generalize EDITOR_DEF macro to fix potential editor setting issues
This commit provides a generalized solution to ensure editor settings are
properly initialized and available in both module and GDExtension versions.
While #204 fixed the specific issue with 'limbo_ai/editor/layout', this change
aims to prevent similar problems for all editor settings.

In particular, `limbo_ai/editor/prefer_online_documentation` was also not
available.

Changes:
- Updated EDITOR_DEF macro to handle both module and GDExtension cases
- Remove special case for `limbo_ai/editor/layout` in
  LimboAiEditorPlugin from earlier fix.
2024-09-03 16:37:54 +02:00
Serhii Snitsaruk d972b2e7ff
Merge pull request #204 from monxa/fix-editor-setting-gdextension
Fix editor setting initialization for GDExtensions
2024-09-03 02:23:28 +02:00
Alexander Montag a5517313d2 Fix editor setting initialization for GDExtensions
This commit addresses an issue where editor settings were not properly
initialized when using GDExtensions. The problem manifested as an error
message: "Condition '!props.has(pinfo.name)' is true" when trying to
access the "limbo_ai/editor/layout" setting.

Changes:
- Replace Dictionary with PropertyInfo for adding property information
- Add a safeguard to ensure the setting is explicitly set if not present
2024-09-02 10:27:22 +02:00
Serhii Snitsaruk f694980c6d
Merge pull request #202 from limbonaut/fix-custom-scene-root
Fix custom scene root is not used in BTPlayer and BTState
2024-08-31 20:00:47 +02:00
Serhii Snitsaruk b981d430f1
Fix custom scene root is not used in BTPlayer and BTState 2024-08-31 19:37:44 +02:00
Serhii Snitsaruk c0bc484f0c
README: Link to stable documentation instead of latest 2024-08-25 15:24:13 +02:00
Serhii Snitsaruk af68b1eebc
Update README.md 2024-08-22 17:28:02 +02:00
Serhii Snitsaruk f83cf659e8
GHA: Fix error building .NET assemblies for Windows 2024-08-22 14:23:20 +02:00
Serhii Snitsaruk bd0dcb3184
GHA: Add action to build .NET assemblies 2024-08-22 13:07:16 +02:00
Serhii Snitsaruk 338c9c8ccb
Bump version to 1.2.0 2024-08-22 00:50:16 +02:00
Serhii Snitsaruk a92fb9da8e
Merge pull request #201 from limbonaut/fix-undo-redo
Fix editor undo polluting scene history if `BehaviorTree` is not saved to a file
2024-08-21 20:57:51 +02:00
Serhii Snitsaruk 9da16a1e0f
Clean up unused string names 2024-08-21 20:04:35 +02:00
Serhii Snitsaruk 472f360cf9
Switch to contextual behavior tree upon undo action 2024-08-21 17:30:30 +02:00
Serhii Snitsaruk c94ec7613d
Add hack to associate undo-redo actions with global history 2024-08-21 16:40:02 +02:00
Serhii Snitsaruk 9ae61e0556
Merge pull request #200 from limbonaut/dotnet-templates
GHA: Build additional .NET templates - Android & iOS
2024-08-21 01:39:03 +02:00
Serhii Snitsaruk 9c8d782fb2
GHA: Build Android .NET templates 2024-08-20 22:13:07 +02:00
Serhii Snitsaruk d709389c87
GHA: Build iOS .NET templates 2024-08-20 17:34:10 +02:00
Serhii Snitsaruk f550ddd23f
Better error message when failed to read editor setting 2024-08-18 12:41:16 +02:00
Serhii Snitsaruk f232069dc4
Merge pull request #199 from limbonaut/gha-fix-dotnet-template-version
GHA: .NET build workflow fixes
2024-08-17 14:21:53 +02:00
Serhii Snitsaruk 6fabad213e
GHA: Fix nuget versions in linux and macos builds 2024-08-16 23:27:58 +02:00
Serhii Snitsaruk cc3d650d23
Fix .NET incorrect template version in version.txt 2024-08-16 20:20:22 +02:00
Serhii Snitsaruk 3a4caeb298
Merge pull request #198 from limbonaut/fix-btstate-overwriting-bb-vars
Don't overwrite exisiting blackboard variables in `BTState` upon initialization
2024-08-16 11:32:00 +02:00
Serhii Snitsaruk ee404c828a
Doc: Update using-blackboard.rst 2024-08-16 10:53:59 +02:00
Serhii Snitsaruk 43035839b1
Don't warn of mismatch between Object & NodePath 2024-08-16 00:44:37 +02:00
Serhii Snitsaruk cfacd57f15
Warn about type mismatch when populating blackboard 2024-08-15 23:41:39 +02:00
Serhii Snitsaruk 000f9c15d8
Fix BTState overwriting blackboard variables on init 2024-08-15 23:41:36 +02:00
Serhii Snitsaruk d7438b8a8d
Bump version to 1.2-rc 2024-08-15 16:30:42 +02:00
Serhii Snitsaruk b59db1eee8
Merge pull request #197 from limbonaut/gha-nuget-version
GHA: Preserve nuget version for C# builds
2024-08-15 16:12:53 +02:00
Serhii Snitsaruk 26cf0bb6b4
GHA: Preserve nuget version for C# builds 2024-08-15 16:11:00 +02:00
Serhii Snitsaruk 635ada23dd
Merge pull request #195 from limbonaut/fix-mapping-bug
BlackboardPlan: Fix mapping failing for NodePath variables with prefetch enabled
2024-08-14 21:15:33 +02:00
Serhii Snitsaruk e12beee51e
Fix mapping failing for NodePath variables with prefetch enabled 2024-08-14 20:34:56 +02:00
Serhii Snitsaruk 1f6cc8e55c
GHA: Change test build configuration 2024-08-11 12:56:45 +02:00
Serhii Snitsaruk f8ab80defa
Merge pull request #193 from limbonaut/fix-monitor-performance
Fix `monitor_performance` screwing C# exports
2024-08-11 12:43:28 +02:00
Serhii Snitsaruk 314fcfd741
Fix monitor_performance screwing C# exports 2024-08-11 12:37:37 +02:00
Serhii Snitsaruk 6ada9cef2f
Merge pull request #191 from ydeltastar/fix-tab-update
Fix renaming `BehaviorTree` files doesn't update tab names
2024-08-11 11:26:48 +02:00
yds 410efbe0d3 Fix tab names doesn't update when filesystem changes 2024-08-10 11:29:22 -03:00
Serhii Snitsaruk 85d5af180b
Clarify add_event_handler in docs 2024-08-10 15:01:43 +02:00
Serhii Snitsaruk b4eec2c364
Fix event handler signature example in docs 2024-08-10 14:58:20 +02:00
Serhii Snitsaruk 02af29f2fa
Merge pull request #190 from limbonaut/dev-setup
Improved dev setup for GDExtension
2024-08-10 11:06:43 +02:00
Serhii Snitsaruk 3a40de482f
Fix icon *.import files on scons build
Enables editor scaling and color conversion in LimboAI icon imports.
This won't work until icons are actually imported in the godot editor, but that's okay - it's a convenience feature.
2024-08-10 10:32:35 +02:00
Serhii Snitsaruk 1e1fb5adaf
Clone godot-cpp if not found during scons build 2024-08-09 14:21:40 +02:00
Serhii Snitsaruk 80e3ff705d
Remove setup_gdextension.sh & update README 2024-08-09 13:13:26 +02:00
Serhii Snitsaruk 10b90b70fe
GHA: Don't use setup_gdextension.sh (no longer needed) 2024-08-08 22:55:51 +02:00
Serhii Snitsaruk 7708a11840
Deploy icons on scons build (optionally) 2024-08-08 22:00:16 +02:00
Serhii Snitsaruk 98accb1aa8
Automatically deploy limboai.gdextension on build 2024-08-08 14:41:25 +02:00
Serhii Snitsaruk bf33917cfd
Add help and verification for --project option in SConstruct 2024-08-08 13:27:36 +02:00
Serhii Snitsaruk 304bd86220
Write icon entries to manifest only if changed 2024-08-07 17:47:50 +02:00
Serhii Snitsaruk 629062ea26
Update icon entries during scons build 2024-08-07 17:29:08 +02:00
Serhii Snitsaruk 2528741333
Rename update_icons.py to update_icon_entries.py 2024-08-07 17:11:51 +02:00
Serhii Snitsaruk d5becadd59
Add script to fix icon imports in the demo project 2024-08-07 17:04:49 +02:00
Serhii Snitsaruk 7b0d0aa779
GHA: Update GDExtension workflow for new structure 2024-08-07 15:26:40 +02:00
Serhii Snitsaruk 650e381659
update setup_gdextension.sh to work with new GDExtension project structure 2024-08-07 15:15:59 +02:00
Serhii Snitsaruk 6134d5130c
update SConstruct to be used from repo root and add --project option 2024-08-07 15:01:50 +02:00
Serhii Snitsaruk 32d74427e5
chore: move SConstruct to repo root 2024-08-07 14:52:05 +02:00
Serhii Snitsaruk f14a19b947
Merge pull request #189 from ydeltastar/filter-fix
Make player filter in the debugger case-insensitive
2024-08-07 10:11:19 +02:00
yds 1b04a8589f Make player filter in the debugger case-insensitive 2024-08-06 16:34:06 -03:00
Serhii Snitsaruk abb2af7d27
Merge pull request #188 from limbonaut/fix-csharp-export-errors
Fix C# exports print errors due to missing ClassDB binding
2024-08-06 19:57:07 +02:00
Serhii Snitsaruk 84becbe914
Fix C# exports print errors due to missing ClassDB binding 2024-08-06 18:17:55 +02:00
Serhii Snitsaruk 549a595b42
Doc: Fix codeblock broken sphinx 2024-08-05 17:27:43 +02:00
Serhii Snitsaruk a56272a248
Doc: Clarify `LimboState.add_event_handler()` 2024-08-05 17:09:55 +02:00
Serhii Snitsaruk 63de416066
Merge pull request #186 from limbonaut/double-click-to-edit-script
Edit task script on double-click (open help for core task)
2024-08-05 16:54:40 +02:00
Serhii Snitsaruk c19fd54927
Edit task script on double-click (open help for core task) 2024-08-05 16:34:54 +02:00
Serhii Snitsaruk f8c6e83688
Merge pull request #185 from limbonaut/open-builtin-doc
Editor setting to prefer online docs, and open builtin docs by default
2024-08-05 16:29:12 +02:00
Serhii Snitsaruk 5a4893fc53
Editor setting to prefer online docs, and open builtin docs by default 2024-08-05 15:46:02 +02:00
Serhii Snitsaruk 14d8df0858
Merge pull request #184 from limbonaut/custom-scene-root
Allow supplying custom scene root for behavior tree instantiation
2024-08-05 15:18:21 +02:00
Serhii Snitsaruk 868baa470a
Fix documentation errors 2024-08-05 13:34:13 +02:00
Serhii Snitsaruk 319c5787be
Add BTState::set_scene_root_hint() 2024-08-05 13:21:57 +02:00
Serhii Snitsaruk 1e9b321283
Allow setting custom scene root for behavior trees
- Adds new argument to `BehaviorTree.instantiate()`
- Adds `BTPlayer.set_scene_root_hint()` method
2024-08-05 13:03:50 +02:00
Serhii Snitsaruk 8b2770116d
Merge pull request #183 from limbonaut/btplayer-allow-changing-instance
BTPlayer: Allow switching BT instance at runtime
2024-08-04 13:16:48 +02:00
Serhii Snitsaruk 40863313dd
Check if blackboard is null in `BehaviorTree.instantiate()` 2024-08-04 12:41:25 +02:00
Serhii Snitsaruk ee12a56e96
BTPlayer: Allow changing BT instance at runtime 2024-08-04 12:36:44 +02:00
Serhii Snitsaruk 0f82fa3d64
Merge pull request #182 from limbonaut/btstate-monitor-performance
Allow monitoring BT performance in `BTState`
2024-08-04 11:39:02 +02:00
Serhii Snitsaruk df11afaf44
Allow monitoring BT performance in BTState 2024-08-04 10:37:41 +02:00
Serhii Snitsaruk d2ba904243
Merge pull request #181 from limbonaut/bt-instance
Implement `BTInstance` - runtime instance of `BehaviorTree`
2024-08-04 10:15:08 +02:00
Serhii Snitsaruk 63ef3e0555
BTPlayer: Fix `updated` signal and deprecate `behavior_tree_finished` signal 2024-08-03 16:11:47 +02:00
Serhii Snitsaruk 869b6465b9
Unregister BT instance with debugger if BTPlayer is removed from tree 2024-08-03 14:57:57 +02:00
Serhii Snitsaruk 91edd1c0b5
Documentation fixes 2024-08-03 14:39:27 +02:00
Serhii Snitsaruk 6b4c97e545
Fix BehaviorTree.instantiate() method binding 2024-08-03 14:29:24 +02:00
Serhii Snitsaruk 5f5b62a4ea
Fix BTState setup 2024-08-03 14:17:26 +02:00
Serhii Snitsaruk 68a9492f3d
Fix uninitialized integers 2024-08-03 13:48:15 +02:00
Serhii Snitsaruk 9abfe4ce95
Update class docs 2024-08-03 13:14:31 +02:00
Serhii Snitsaruk 6c794d6a7e
Refactor BTInstance.update() 2024-08-03 11:56:32 +02:00
Serhii Snitsaruk 47ad95b265
Fix demo API calls 2024-08-03 11:40:56 +02:00
Serhii Snitsaruk c4c9b5fe09
Utilize BTInstance in BTState 2024-08-03 11:39:23 +02:00
Serhii Snitsaruk fc26f51ff2
Implement BTInstance - runtime instance of BehaviorTree 2024-08-03 11:07:06 +02:00
Serhii Snitsaruk a2a62f636b
Merge pull request #180 from limbonaut/fix-changed-already-connected
Fix error if `changed` signal is already connected in several tasks
2024-08-02 14:43:21 +02:00
Serhii Snitsaruk ce1867be7a
Fix error if `changed` signal is already connected to a BBParam in a bunch of tasks 2024-08-02 10:07:42 +02:00
Serhii Snitsaruk 09185211ff
Merge pull request #177 from limbonaut/hide-update-mode
Hide `update_mode` property for non-root HSMs
2024-07-31 15:26:45 +02:00
Serhii Snitsaruk 9e79183579
Update demo import 2024-07-31 14:50:56 +02:00
Serhii Snitsaruk bed04dbf87
Hide update_mode for non-root HSMs 2024-07-31 14:50:04 +02:00
Serhii Snitsaruk 64df43c7c9
Merge pull request #176 from limbonaut/hsm-input-fix
LimboHSM: Fix process_input is not enabled in active substate
2024-07-31 13:40:50 +02:00
Serhii Snitsaruk d7daa027ee
Merge pull request #174 from limbonaut/gha-arm-builds
GHA: Add Linux & Windows ARM64 builds
2024-07-31 13:28:55 +02:00
Serhii Snitsaruk abe9a26460
GHA: Add Linux ARM32 template builds 2024-07-31 12:45:12 +02:00
Serhii Snitsaruk 2c58cfc3cb
GHA: Don't strip binaries, done at build time 2024-07-31 12:45:02 +02:00
Serhii Snitsaruk a1d6276097
Fix process_input is not enabled in active substate 2024-07-31 12:15:15 +02:00
Serhii Snitsaruk afc2b63f06
GHA: Disable Editor .NET ARM64 2024-07-31 10:43:56 +02:00
Serhii Snitsaruk af27aca021
GHA: Fix strip failing in Linux ARM64 builds 2024-07-30 16:19:02 +02:00
Serhii Snitsaruk dad5082e7e
GHA: Add Linux ARM toolchain 2024-07-30 15:27:58 +02:00
Serhii Snitsaruk 6aa4e63929
Merge pull request #173 from limbonaut/gha-fix-ios-builds
GHA: Fix iOS builds
2024-07-30 15:24:04 +02:00
Serhii Snitsaruk 8568572092
GHA: Add Windows ARM64 builds 2024-07-30 14:20:46 +02:00
Serhii Snitsaruk 3cce7aa0a6
GHA: Add arm64 Linux builds 2024-07-30 14:16:01 +02:00
Serhii Snitsaruk f1dba8f061
GHA: Disable treating warnings as errors for iOS builds 2024-07-30 13:49:59 +02:00
Serhii Snitsaruk 17eb029497
Merge pull request #172 from limbonaut/fix-btplayer-restart-crash
Fix BTPlayer.restart() crash
2024-07-30 13:46:51 +02:00
Serhii Snitsaruk 456687c857
Fix BTPlayer.restart() crash 2024-07-30 12:42:22 +02:00
Serhii Snitsaruk 186ee3c6a7
Update README 2024-07-30 12:02:02 +02:00
Serhii Snitsaruk 0e059c8a52
Merge pull request #164 from limbonaut/hsm-improvements
HSM improvements
2024-07-21 15:19:03 +02:00
Serhii Snitsaruk 17ccd50806
Add tests for change_active_state() 2024-07-21 14:07:56 +02:00
Serhii Snitsaruk b478c8eb2c
Add tests for has_transition() and remove_transition() 2024-07-21 14:02:27 +02:00
Serhii Snitsaruk cf99a27692
Refactor LimboHSM 2024-07-21 13:45:36 +02:00
Serhii Snitsaruk f7eb374c1e
Add `LimboHSM.has_transition(from, event)` 2024-07-21 13:35:16 +02:00
Serhii Snitsaruk a7881a0eea
Rework HSM transitions bookkeeping
Fixes a potential rare hash collision situation, and allows additional
attributes to be stored with the transition data in future.
2024-07-21 13:28:59 +02:00
Serhii Snitsaruk 0934e4e672
Expose `LimboHSM.change_active_state()` 2024-07-20 18:15:21 +02:00
Serhii Snitsaruk ddbfa132a5
Update docs 2024-07-20 17:25:24 +02:00
Serhii Snitsaruk 7c57c7dd62
Add LimboHSM.remove_transition 2024-07-20 17:23:13 +02:00
Serhii Snitsaruk 3565d6dc43
Merge pull request #162 from ydeltastar/fix-btplayer-error
Fix error when opening scene with a `BTPlayer`
2024-07-18 05:22:33 +02:00
Serhii Snitsaruk 18ee21554e
Merge pull request #161 from ydeltastar/fix-new-script-path
Fix new task script path don't update after changing the setting
2024-07-17 20:17:00 +02:00
yds 7073db7bfa Fix error when loading scene with a `BTPlayer` 2024-07-17 13:25:58 -03:00
yds 3e5e34f5f8 Fix new task script path don't update after changing the setting 2024-07-10 13:23:48 -03:00
Serhii Snitsaruk 0f9c566a63
Merge pull request #159 from limbonaut/improve-tooltips
Improve documentation tooltips
2024-07-07 13:44:26 +02:00
Serhii Snitsaruk 86d31f5f00
Update demo documentation comments 2024-07-07 13:22:02 +02:00
Serhii Snitsaruk 5f40d38f8d
Add a hack to force documentation parsing on user scripts
As things currently stand in Godot Engine, documentation comments are
not loaded from user scripts into help system when the project is
started. This leads to empty tooltips for user tasks in LimboAI, unless
such a script is resaved.

This hack forces script documentation to be added to help system,
when the editor needs it to show a tooltip.
2024-07-07 12:13:07 +02:00
Serhii Snitsaruk 800bc8f16d
Tooltip improvements
- Fix tooltip not shown for scripted tasks in TaskPalette
- Allow following links in the tooltip text
- If help data cannot be found, an empty tooltip is shown instead
2024-07-06 16:46:55 +02:00
Serhii Snitsaruk 40acd04eb9
Fix tooltip popup too small 2024-07-06 12:33:08 +02:00
Serhii Snitsaruk f1af947060
Defer banner actions to not crash upon restart 2024-07-06 12:13:58 +02:00
Serhii Snitsaruk 5f5e4a28cc
Merge pull request #158 from limbonaut/fix-bbplan-arrays
Fix BlackboardPlan arrays shouldn't be shared between instanced agents
2024-07-06 11:12:11 +02:00
Serhii Snitsaruk 254a9ca943
Merge pull request #157 from limbonaut/task-palette-placement
Improved layout for wide displays (optional)
2024-07-06 10:08:01 +02:00
Serhii Snitsaruk 3ceedbebad
Fix BlackboardPlan arrays shouldn't be shared between instanced agents
Variable values are deep copied now using Variant.duplicate(true). Note that currently it doesn't duplicate objects.
2024-07-06 10:04:36 +02:00
Serhii Snitsaruk bc99965205
Fix compilation with GDExtension 2024-07-06 09:46:22 +02:00
Serhii Snitsaruk cfa1f70d79
Update banners upon editor settings changed 2024-07-06 09:38:33 +02:00
Serhii Snitsaruk 7c0d49bafa
Reparent banners if using new layout 2024-07-06 09:29:09 +02:00
Serhii Snitsaruk da9d80d110
Add Misc->Layout options 2024-07-06 09:18:50 +02:00
Serhii Snitsaruk 4787413cb6
Add header to the sidebar 2024-07-05 20:49:16 +02:00
Serhii Snitsaruk 2813728785
Fix connected signal error when loading BT for the second time 2024-07-05 20:32:53 +02:00
Serhii Snitsaruk 2973590533
Flip split offset setting if editor layout changed 2024-07-05 17:53:35 +02:00
Serhii Snitsaruk b74f664da6
Fix compilation issue with GDExtension 2024-07-05 17:24:32 +02:00
Serhii Snitsaruk 7baa395d3f
Rename to editor_layout 2024-07-05 17:02:29 +02:00
Serhii Snitsaruk b305041f28
Bump demo version 2024-07-04 21:25:00 +02:00
Serhii Snitsaruk 7d6cc1a828
Editor: Adjust layout to work better with task palette on the left 2024-07-04 21:16:35 +02:00
Serhii Snitsaruk 4d0d2c0507
Merge pull request #155 from dpalais/auto_translate_deprecated
Replace deprecated set_auto_translate call with set_auto_translate_mode
2024-07-02 20:25:11 +02:00
Dave Palais 4cba3b39db Replace deprecated set_auto_translate call with set_auto_translate_mode 2024-07-02 12:50:56 -05:00
Serhii Snitsaruk 872f7a4532
Editor: Add setting for task palette placement 2024-07-02 11:55:22 +02:00
Serhii Snitsaruk 6432dae35d
Merge pull request #154 from limbonaut/gha-improvements
GHA improvements
2024-07-01 19:11:02 +02:00
Serhii Snitsaruk ed19d787f6
GHA: Install Wayland deps for Linux builds 2024-07-01 15:02:07 +02:00
Serhii Snitsaruk e3305782f2
GHA: Build nothreads variant of web templates 2024-07-01 13:32:02 +02:00
Serhii Snitsaruk d98be526b6
Merge pull request #151 from limbonaut/gdext-gen-doc-header
Generate built-in documentation header in GDExtension variant
2024-06-30 15:56:49 +02:00
Serhii Snitsaruk ae3b4ebb94
Generate built-in documentation header in GDExtension 2024-06-30 15:40:18 +02:00
Serhii Snitsaruk 2f62b53b6a
Merge pull request #150 from limbonaut/fix-gdext-crash
Fix: GDExtension load fails due to `Expression` used without `Ref<>`
2024-06-30 14:47:39 +02:00
Serhii Snitsaruk 8dfbd70718
Fix: GDExtension load fails due to Expression used w/o Ref 2024-06-30 14:29:40 +02:00
Serhii Snitsaruk 4d4f0d7886
Merge pull request #149 from limbonaut/gdext-virt-calls
Register and call virtual methods on scripts in GDExtension
2024-06-30 13:07:41 +02:00
Serhii Snitsaruk cd0bc8e796
Register and call virtual methods on scripts in GDExtension 2024-06-30 12:34:06 +02:00
Serhii Snitsaruk 5e89a82743
Merge pull request #64 from Rubonnek/updates-for-4.3
Add support for Godot 4.3
2024-06-29 23:17:05 +02:00
Wilson E. Alvarez d2ca303c5e
Fix List<T> access
Due to upstream change:

	955d5affa8
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez fe597a5a46
Fix GCC warning for unhandled 'PACKED_VECTOR4_ARRAY' in switch
Due to upstream change:

	f9b488508c
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez d20d28be78
Update EditorPlugin header location
Due to upstream change:

	1bcbbe96c4
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez 2f1fd6fb62
Update EditorHelpBit calls
Due to upstream change:

	a714cb9f65
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez 022d95434d
Add missing MarginContainer header
Due to upstream change:

	7884d63281
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez ce28ed92d2
Fix bottom panel visbility calls
Due to upstream change:

	eb6ca91ba6
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez 8f294ac5ea
Migrate to Tree::set_custom_draw_callback
Due to upstream change:

	a32a2eaedc
2024-06-29 14:52:05 -04:00
Wilson E. Alvarez 9410031d45
Fix upstream EditorScale header locations
Due to upstream change:

	4b55c81eba
2024-06-29 14:52:05 -04:00
Serhii Snitsaruk 61b2db5a07
Bump version to 1.2-dev 2024-06-29 16:53:30 +02:00
Serhii Snitsaruk 15464e288c
GH: Add issue templates 2024-06-29 13:35:01 +02:00
Serhii Snitsaruk 4467ebbbd9
Update README.md 2024-06-24 21:34:35 +02:00
Serhii Snitsaruk a2dedabd77
Fix potential rare var name conflict in BTCooldown 2024-06-23 12:14:15 +02:00
Serhii Snitsaruk 2356e6c967
Merge pull request #147 from limbonaut/gha-gdext-android
GHA: Build Android platform libs in GDExtension workflow
2024-06-21 11:38:31 +02:00
Serhii Snitsaruk b712fe25dc
GHA: Don't strip arm Android libs 2024-06-21 10:34:36 +02:00
Serhii Snitsaruk 5bdec804b3
Add 32-bit Android libs to GDExtension manifest 2024-06-21 10:31:30 +02:00
Serhii Snitsaruk 2784937ca8
GHA: Build Android libs for arm32 & x86_32 2024-06-21 10:18:15 +02:00
Serhii Snitsaruk d383e9d1a4
GHA: Don't build web and android libs in test builds 2024-06-20 19:55:23 +02:00
Serhii Snitsaruk 4f1b22c668
GHA: Add GDExtension Android libs to build workflow 2024-06-20 19:54:29 +02:00
Serhii Snitsaruk 8fa609ef9e
Bump version to 1.1.0 2024-06-18 14:11:04 +02:00
Serhii Snitsaruk c6851259e8
Doc: Mention mapping in BTSubtree class doc 2024-06-18 13:25:33 +02:00
Serhii Snitsaruk 5a60ad9308
Doc: Add section on "Debugging behavior trees" in index.rst 2024-06-18 13:12:05 +02:00
Serhii Snitsaruk 7a90fdb113
Merge pull request #145 from limbonaut/gha-gdext-convert-icon-colors
Support editor light themes for icons in GDExtension
2024-06-15 09:05:46 +02:00
Serhii Snitsaruk 3bc8343e8b
GHA: Set `convert_colors_with_editor_theme=true` in .import 2024-06-15 08:42:41 +02:00
Serhii Snitsaruk 1c7eb994d4
Merge pull request #142 from limbonaut/fix-task-tree-column
Fix task tree warnings column always taking up space
2024-06-12 18:36:08 +02:00
Serhii Snitsaruk c76278b735
Fix task tree warnings column always taking up space 2024-06-10 08:26:18 +02:00
Serhii Snitsaruk fc53078130
Demo: Remove strange hsm.set_guard() call 2024-06-07 17:43:46 +02:00
Serhii Snitsaruk 88583a8a2e
Merge pull request #136 from limbonaut/fix-unfolding
Fix folding/unfolding selected composite task is not working
2024-06-06 13:19:11 +02:00
Serhii Snitsaruk d6076d131f
Fix folding/unfolding selected composite task is not working 2024-06-06 12:58:18 +02:00
Serhii Snitsaruk 2d1c5fa4ba
Merge pull request #133 from limbonaut/fix-performance-monitoring-crash
Fix crash when freeing agent with performance monitoring enabled
2024-06-05 23:04:14 +02:00
Serhii Snitsaruk 7eaebc4e7c
Fix crash when freeing agent with performance monitoring enabled 2024-06-04 09:30:42 +02:00
Serhii Snitsaruk db73133f1b
Bump version to 1.1-rc 2024-06-03 22:41:46 +02:00
Serhii Snitsaruk 7c0c81d141
Hide .0 patch version for builds with pre-release version status only 2024-06-03 22:35:51 +02:00
Serhii Snitsaruk adff6bd08c
Merge pull request #131 from limbonaut/fix-reparenting-issue
Fix reparenting an agent deactivates its HSM
2024-06-03 15:50:35 +02:00
Serhii Snitsaruk 06de52492a
Fix reparenting an agent deactivates its HSM 2024-06-03 14:55:00 +02:00
Serhii Snitsaruk 2c8e0d2da0
Merge pull request #130 from limbonaut/fix-custom-task-issues
Fix custom task issues - a rare crash & a sticky name/script issue, and improve error handling
2024-06-03 11:08:21 +02:00
Serhii Snitsaruk ce5f012101
Fix sticky name issues in custom tasks due to script errors 2024-06-03 10:45:01 +02:00
Serhii Snitsaruk 3bca05bc50
Fix crash on adding a task with bad script base type and improve error handling 2024-06-02 21:58:50 +02:00
Serhii Snitsaruk 56bb91df0a
Merge pull request #127 from limbonaut/blackboard-tests
Add unit tests for `Blackboard` and fix `Blackboard.unbind_var()`
2024-06-01 16:08:35 +02:00
Serhii Snitsaruk c793c8ba53
Fix `Blackboard.unbind_var` failing for existing bound variable 2024-06-01 10:53:56 +02:00
Serhii Snitsaruk 808ca1de7f
Add unit tests for Blackboard 2024-06-01 10:52:31 +02:00
Serhii Snitsaruk 809efc1be2
Merge pull request #125 from limbonaut/api-new-blackboard-methods
API: Add Blackboard methods to enable iteration, state inspection & serialization
2024-06-01 10:26:21 +02:00
Serhii Snitsaruk 29532113c0
Change to typed array in `BlackboardPlan::list_vars` 2024-05-31 11:57:27 +02:00
Serhii Snitsaruk 1e6c3fa92b
Files reformatted by pre-commit 2024-05-31 11:46:16 +02:00
Serhii Snitsaruk 35f2c3c142
API: Add `Blackboard` methods to enable iteration, state inspection and serialization 2024-05-31 11:46:11 +02:00
Serhii Snitsaruk 49f5e3be79
Merge pull request #124 from limbonaut/show-version
Show version info in the editor
2024-05-30 16:28:35 +02:00
Serhii Snitsaruk a04d4aaca4
Show version info in the editor
- Version is set in `limboai_version.py` file and hash is taken from GIT on build.
- Click to copy version info into clipboard.
2024-05-30 16:03:05 +02:00
Serhii Snitsaruk 08ad6c1d99
Merge pull request #122 from limbonaut/open-owner-scene
Editor: Add tab context menu option "Jump to Owner"
2024-05-29 21:00:48 +02:00
Serhii Snitsaruk c9825413c0
Add shortcut for "Close Tab" and clean up input code 2024-05-29 19:13:57 +02:00
Serhii Snitsaruk 990438db55
Handle built-in resources in "Jump to owner" tab action 2024-05-29 18:27:55 +02:00
Serhii Snitsaruk 2b299c0007
Accept Ctrl-J when LimboAI editor is visible and fix shortcuts not working sometimes 2024-05-29 11:58:59 +02:00
Serhii Snitsaruk 88e468c526
Editor: Add Ctrl+J shortcut for "Jump to Owner" tab action 2024-05-29 11:18:11 +02:00
Serhii Snitsaruk a0cd983927
Editor: Fix "jump to owner" from subtree and refactor 2024-05-29 10:53:54 +02:00
Serhii Snitsaruk 792502db84
Editor: Add tab context menu option "Open owner scene" 2024-05-28 21:16:26 +02:00
Serhii Snitsaruk 5f5ecc2db1
Merge pull request #123 from limbonaut/fix-compilation-errors-with-new-godotcpp
Fix compile-time errors with updated godot-cpp
2024-05-28 20:11:40 +02:00
Serhii Snitsaruk 361eb3eb15
Fix compile-time errors with updated godot-cpp 2024-05-28 19:50:57 +02:00
Serhii Snitsaruk dbb89e6883
Merge pull request #120 from limbonaut/improve-navigation
Implement tab navigation in the editor
2024-05-28 12:28:47 +02:00
Serhii Snitsaruk fa3034d190
Remove old editor navigation code 2024-05-28 12:04:02 +02:00
Serhii Snitsaruk 9e0489a034
Editor: Tab button to inspect blackboard plan 2024-05-28 11:16:37 +02:00
Serhii Snitsaruk a7d4b1e7f7
Editor: Use the full name for tabs if the short name is not unique 2024-05-28 09:46:21 +02:00
Serhii Snitsaruk 127fa678f4
Editor: Add tab context menu 2024-05-27 16:53:44 +02:00
Serhii Snitsaruk e0d47ddf08
Fix closing last tab leads to crash on exit 2024-05-27 15:36:17 +02:00
Serhii Snitsaruk 57382e10a7
Editor: Show full filename in tabs for BTs saved as built-in resources 2024-05-27 15:06:35 +02:00
Serhii Snitsaruk 0a28feb7a9
Fix GDExtension compilation issues 2024-05-27 14:27:14 +02:00
Serhii Snitsaruk 6f8f95b5de
Editor: Replace BT resource button with tabs 2024-05-27 13:48:08 +02:00
Serhii Snitsaruk e9eec23c3e
Update README.md
Put first steps earlier in the README
2024-05-26 12:39:04 +02:00
Serhii Snitsaruk d0fcea5574
Merge pull request #118 from limbonaut/doc-first-steps
Doc: Add first steps
2024-05-26 12:36:42 +02:00
Serhii Snitsaruk e059429760
Doc: Add first steps 2024-05-26 12:34:18 +02:00
Serhii Snitsaruk 918095622c
Merge pull request #117 from limbonaut/gha-toolchain-mirror
GHA: Use godotengine buildroot mirror
2024-05-26 12:16:14 +02:00
Serhii Snitsaruk 23c19c11e6
GHA: Use godotengine buildroot mirror 2024-05-26 09:32:49 +02:00
Serhii Snitsaruk bc2c4a26ac
GHA: Restore toolchain links
Toolchain contents should be cached now.
2024-05-25 16:07:00 +02:00
Serhii Snitsaruk 83214fc93b
GHA: Temporarily change toolchain link while tuxfamily.org is down (32-bit) 2024-05-25 15:05:34 +02:00
Serhii Snitsaruk e062669cf7
GHA: Temporarily change toolchain link while tuxfamily.org is down 2024-05-25 14:05:15 +02:00
Serhii Snitsaruk 2e94bf8bf2
Merge pull request #116 from limbonaut/gha-import-files
GHA: Generate .import files for GDExtension icons
2024-05-25 14:01:16 +02:00
Serhii Snitsaruk e8816091e6
GHA: Verify toolchain checksum 2024-05-25 13:33:48 +02:00
Serhii Snitsaruk fc1b99a5b1
GHA: Action that downloads & caches Linux toolchain
TuxFamily is often down lately, maybe caching could help.
2024-05-25 13:33:42 +02:00
Serhii Snitsaruk 04300e5222
GHA: Generate .import files for GDExtension icons 2024-05-22 22:33:21 +02:00
Serhii Snitsaruk 2f326e5b6f
Merge pull request #110 from limbonaut/type-validation
Editor: Check if variable is of correct type for BBParam subtypes
2024-05-18 15:33:39 +02:00
Serhii Snitsaruk 064d00fdfa
Editor: Check if variable is of correct type for BBParam subtypes 2024-05-18 14:12:00 +02:00
Serhii Snitsaruk ff61d55c44
Merge pull request #106 from limbonaut/mapping
Mapping variables
2024-05-18 13:47:42 +02:00
Serhii Snitsaruk 7ab7a9d098
BlackboardPlan: Improve inspector update while manually typing in mappings
Fixes property glitches observed while a map variable is typed in.
2024-05-17 21:54:50 +02:00
Serhii Snitsaruk b54f3696ff
Fix crash upon adding variable in the plan editor with empty default name
Also default to float when expected type is not specified.
2024-05-17 11:08:58 +02:00
Serhii Snitsaruk dc77ecd2b2
Fix `parent_scope` argument in `create_blackboard` should have a default value 2024-05-17 10:36:25 +02:00
Serhii Snitsaruk 026272f7f7
Fix BBParam subtypes incorrectly display type error in inspector 2024-05-17 10:27:22 +02:00
Serhii Snitsaruk d08018b7b1
BlackboardPlan: Update mapping after variable renamed
Currently, only for owned variables, not parent's.
2024-05-17 10:00:12 +02:00
Serhii Snitsaruk 00396dce61
Merge pull request #107 from limbonaut/steamdeck-support
GHA: Use older toolchain for SteamDeck compatibility
2024-05-16 17:48:33 +02:00
Serhii Snitsaruk 69201fa877
GHA: Use older toolchain for SteamDeck compatibility 2024-05-16 12:08:13 +02:00
Serhii Snitsaruk d920060dee
Update class documentation 2024-05-15 20:58:38 +02:00
Serhii Snitsaruk 2718271bb1
Clean up & renames 2024-05-15 20:43:24 +02:00
Serhii Snitsaruk 3cf90f9387
BlackboardPlan: Don't show mapping in root plans 2024-05-15 13:13:27 +02:00
Serhii Snitsaruk c6b1a40627
BlackboardPlan: Update inspector upon mapping editing finished 2024-05-15 12:52:50 +02:00
Serhii Snitsaruk d36f8f1122
Fix variables missing from BTState blackboard
Non-overridden variables could be missing at runtime in the BTState blackboard due to a bug this commit fixes.
2024-05-15 11:43:31 +02:00
Serhii Snitsaruk a572613001
BlackboardPlan: Utilize mapping in LimboHSM
Also changes how parent plan providing is implemented (used for editor hints).
2024-05-15 11:38:53 +02:00
Serhii Snitsaruk c30c5a4d7a
BlackboardPlan: Auto-fill type info when adding a missing variable for a mapping 2024-05-14 22:55:25 +02:00
Serhii Snitsaruk ef1c1e5192
Fix circular ref & non-tools compilation errors 2024-05-14 22:03:29 +02:00
Serhii Snitsaruk 3b12288ae0
BlackboardPlan: Serialize only non-empty mapping values 2024-05-14 20:25:18 +02:00
Serhii Snitsaruk a1cdff2e2e
Fix issues with mapping in BTSubtree 2024-05-14 19:47:05 +02:00
Serhii Snitsaruk e43bc25d82
BlackboardPlan: Provide editor hints for mappings 2024-05-14 13:29:04 +02:00
Ola S. 549d73b8fc
Add icons for empty & error variable statuses 2024-05-14 13:25:24 +02:00
Serhii Snitsaruk 0d1e846d93
BlackboardPlan: Use mapping with BTSubtree 2024-05-14 11:39:32 +02:00
Serhii Snitsaruk 2d493a76bd
BlackboardPlan: Improve mapping and serialize 2024-05-14 09:29:56 +02:00
Serhii Snitsaruk bdfe5f52c2
BlackboardPlan: Implement rudimentary mapping 2024-05-13 23:21:55 +02:00
Serhii Snitsaruk e55611a1a9
Bump doc version 2024-05-12 17:34:12 +02:00
Serhii Snitsaruk ba467ad62c
Merge pull request #102 from limbonaut/btplayer-agent-property
Allow specifying agent in `BTPlayer` node via inspector
2024-05-12 17:29:05 +02:00
Serhii Snitsaruk 5e961ec6fa
Merge pull request #103 from limbonaut/pre-commit
Add pre-commit configuration
2024-05-03 01:31:25 +02:00
Serhii Snitsaruk bc5d5d8610
Add pre-commit configuration
To install git hook scripts:
  pip install pre-commit
  pre-commit install
2024-05-03 00:21:51 +02:00
Serhii Snitsaruk e5d04b9eda
Doc: Update doc pages and examples 2024-05-02 19:38:05 +02:00
Serhii Snitsaruk e36ea6d3e6
Better error handling in BTState, BTPlayer & BehaviorTree 2024-05-02 14:10:29 +02:00
Serhii Snitsaruk 803da63fa8
Doc: Update class docs 2024-05-02 13:39:19 +02:00
Serhii Snitsaruk 84c89356a6
Print error if agent node is set after initialization 2024-05-02 12:49:32 +02:00
Serhii Snitsaruk a2dae24b99
Rename BTPlayer's agent => agent_node 2024-05-02 12:11:59 +02:00
Serhii Snitsaruk af23272e3d
Fix unnamed arguments in method bindings 2024-05-02 01:27:14 +02:00
Serhii Snitsaruk 506d8aa967
Use `scene_root` with `BBParam` 2024-05-01 23:39:09 +02:00
Serhii Snitsaruk 5dff2e537b
Add `agent` parameter to `BTPlayer` to propagate upon `BehaviorTree` initialization, and add `scene_root` property to `BTTask`
`scene_root` is useful to resolve exported NodePath properties in `BTTask` instances (and for BBNode parameters).
2024-05-01 23:20:17 +02:00
Serhii Snitsaruk 75e8e68da4
Merge pull request #100 from TranquilMarmot/patch-1
Add note about how to run demo/tutorial
2024-05-01 21:23:18 +02:00
Nate Moore 4fe4049c3a
game -> showcase 2024-05-01 10:01:44 -07:00
Serhii Snitsaruk 69e921be31
Merge pull request #101 from limbonaut/unit-tests
Add tests for nested HSM flow, tests for dispatch() and get_root(), and fix BBParam saved_value initializing to null
2024-05-01 18:43:13 +02:00
Serhii Snitsaruk c6bb5bad74
Fix: BBParam saved_value defaults to null 2024-05-01 18:09:06 +02:00
Serhii Snitsaruk 2c2f2dd4be
Test: BBParam default values 2024-05-01 18:08:59 +02:00
Serhii Snitsaruk dedffc4f22
Test: Nested HSM flow, dispatch() and get_root() 2024-05-01 18:08:40 +02:00
Nate Moore 4491a23d52
Add note about how to run demo/tutorial
Closes https://github.com/limbonaut/limboai/issues/99
2024-04-30 23:26:00 -07:00
Serhii Snitsaruk 0e843d3193
Merge pull request #95 from limbonaut/decorator-default-tick
BTDecorator: Add default `_tick` implementation
2024-04-30 13:14:02 +02:00
Serhii Snitsaruk 769de9a7e2
Merge pull request #89 from limbonaut/blackboard-api-improvements
Blackboard: Add `create` parameter to `bind_var_to_property` and `link_var`
2024-04-30 11:31:22 +02:00
Serhii Snitsaruk 2bfedec518
Merge pull request #96 from onze/patch-1
Documentation update - BTSubTree
2024-04-22 20:16:36 +02:00
val 29d4b92bf4 found how to get custom links into the doc 2024-04-22 13:52:09 -04:00
val 40850067c8 moved the change to the doc sources 2024-04-22 12:58:44 -04:00
val f45e954e62
Update class_btsubtree.rst 2024-04-22 09:24:24 -04:00
val 40ea2ce01a
Update class_btsubtree.rst
Added a note about updating `subtree` at runtime.
2024-04-22 09:21:41 -04:00
Serhii Snitsaruk e1c8ce4a58
BTDecorator: Add default `_tick` implementation
The default implementation simply ticks the child task and returns its status.
2024-04-22 11:07:50 +02:00
Serhii Snitsaruk af0250dc60
Merge pull request #93 from limbonaut/fix-get-root
Fix `LimboState::get_root` and `dispatch` freeze the process in case of nested HSMs
2024-04-21 16:42:02 +02:00
Serhii Snitsaruk 4207fbf8f3
Fix `LimboState::get_root` freezes the process 2024-04-21 16:26:41 +02:00
Serhii Snitsaruk 03de485ebb
Merge pull request #92 from limbonaut/debugger-multi-session
Support multiple debugger sessions
2024-04-21 13:27:17 +02:00
Serhii Snitsaruk 7f89659110
Support multiple debugger sessions 2024-04-21 13:04:16 +02:00
Serhii Snitsaruk 1a37540797
Merge pull request #91 from limbonaut/fix-bt-ticked-after-transition
HSM: Delay state transition till update is finished
2024-04-20 21:50:46 +02:00
Serhii Snitsaruk c4df916bdf
HSM: Delay state transition till update is finished 2024-04-20 21:30:26 +02:00
Serhii Snitsaruk 5048d6a485
Fix BT being ticked after transition happened and state is no longer active 2024-04-20 20:19:07 +02:00
Serhii Snitsaruk 24382d3fd1
GHA: Fix demo has empty version file 2024-04-12 20:15:45 +02:00
Serhii Snitsaruk 5045e5b864
Merge pull request #88 from limbonaut/gha-macos-dotnet
GHA: Build .NET binaries for macOS
2024-04-12 18:59:55 +02:00
Serhii Snitsaruk c739a876b0
Blackboard: Add `create` parameter to `bind_var_to_property` and `link_var` 2024-04-09 11:34:22 +02:00
Serhii Snitsaruk 5e63477f9b
GHA: Build .NET binaries for macOS 2024-04-09 11:04:29 +02:00
Serhii Snitsaruk 09562ffbd3
Merge pull request #87 from limbonaut/gha-provide-version
GHA: Provide version.txt with GDExtension builds & demo project
2024-04-07 15:55:33 +02:00
Serhii Snitsaruk ceeb4dbeb3
GHA: Provide version.txt with GDExtension builds & demo 2024-04-07 14:11:39 +02:00
Serhii Snitsaruk 0ff93faacc
Merge pull request #85 from limbonaut/plan-improvements
`BlackboardPlan` fixes
2024-04-01 18:03:22 +02:00
Serhii Snitsaruk 3918272227
BehaviorTree: New signal for when BB plan changes
Utilize `plan_changed` signal in `BTPlayer` and `BTState`.
2024-04-01 16:34:36 +02:00
Serhii Snitsaruk 302de87e32
Prevent using external resources for derived blackboard plans in `BTPlayer` and `BTState` 2024-04-01 15:25:54 +02:00
Serhii Snitsaruk d48daf2135
BlackboardPlan: Avoid circular references in derived mode
If the same plan resource is assigned in BehaviorTree and in BTPlayer, simply use the resource as is. Using the same resource for `BehaviorTree` and `BTPlayer` will disable derived mode, and allow managing from `BTPlayer` . There is a risk of using `NodePath` variables with different scenes: the path may actually be different if node structure is not the same. It will lead to fetching breaking for some of those scenes.
2024-04-01 01:45:40 +02:00
Serhii Snitsaruk 5ff42e29e4
Always duplicate `BlackboardPlan` props 2024-04-01 01:11:51 +02:00
Serhii Snitsaruk 7160804c82
GHA: Bump geekyeggo/delete-artifact to v5 2024-03-26 18:49:26 +01:00
Serhii Snitsaruk 58d7ea223e
Merge pull request #84 from limbonaut/fix-subtree-bb-plan
BTSubtree: Fix subtree blackboard plan is not property utilized
2024-03-26 18:35:02 +01:00
Serhii Snitsaruk e50b00c70e
BTSubtree: Fix subtree blackboard plan is not property utilized 2024-03-26 18:19:31 +01:00
Serhii Snitsaruk 31db4b4543
Merge pull request #82 from limbonaut/fix-blackboard-plan-issues
Fix blackboard plan issues
2024-03-26 17:08:06 +01:00
Serhii Snitsaruk 671ca50b82
Update demo AI assets 2024-03-25 01:08:58 +01:00
Serhii Snitsaruk a5aea72a17
Plan: Fix syncing derived plan sometimes fails on var rename 2024-03-25 01:04:07 +01:00
Serhii Snitsaruk 1de6256401
Plan: Don't store unmodified variables in a derived plan
Fixes "sticky" old values in a derived plan.
2024-03-25 00:56:08 +01:00
Serhii Snitsaruk 930493101d
GHA: Package icons with the demo project 2024-03-21 23:27:39 +01:00
Serhii Snitsaruk ebc2ce310f
Bump doc version to v1.0 2024-03-21 21:42:54 +01:00
Serhii Snitsaruk 12fd9d00d6
Update file headers and fix whitespace 2024-03-21 21:38:57 +01:00
Serhii Snitsaruk f36f5af92a
Doc: Update README.md 2024-03-21 21:04:22 +01:00
Serhii Snitsaruk 94a277ef9d
Doc: Explain using `_var` suffix for var properties 2024-03-21 15:16:27 +01:00
Serhii Snitsaruk 6c8045b280
Update README screenshot 2024-03-21 14:26:13 +01:00
Serhii Snitsaruk 6edb7017b9
Merge pull request #77 from limbonaut/fix-bbparam-null-default
Fix `BBParam` stored value defaulting to `null` in GDExtension
2024-03-21 00:14:10 +01:00
Serhii Snitsaruk 9e62fe8fa3
Fix `BBParam` stored value defaulting to `null` in GDExtension 2024-03-20 23:57:42 +01:00
Serhii Snitsaruk 79d72c39e0
Use proper icon in inspector for BB vars 2024-03-20 17:42:04 +01:00
Serhii Snitsaruk 5a8fe97aac
Fix error when clicking resource header in debugger with a scene-embedded BT 2024-03-20 14:19:49 +01:00
Serhii Snitsaruk d9a9a1d4e5
Merge pull request #75 from limbonaut/expose-checks-and-operations
Expose checks and operations in `LimboUtility`
2024-03-20 12:31:09 +01:00
Serhii Snitsaruk 06ea008105
Expose checks and operations in `LimboUtility` 2024-03-20 12:13:32 +01:00
Serhii Snitsaruk 705f4d7415
Doc: Update custom-tasks.rst
Mention extending different base types.
2024-03-14 16:10:40 +01:00
Serhii Snitsaruk cbd467f97f
Blackboard: Assigning variables via code might have no effect if done before initialization 2024-03-13 22:00:50 +01:00
Serhii Snitsaruk 088ef008a6
Merge pull request #71 from limbonaut/blackboard-fixes
Blackboard-related improvements and fixes
2024-03-12 22:31:07 +01:00
Serhii Snitsaruk 06ebff7518 Fix includes and build errors 2024-03-12 21:09:28 +01:00
Serhii Snitsaruk 39c4511249 BBParam editor: Combine type+mode functionality in one button
Previously, we had two buttons: "mode switch" and "type choice".
Now replaced with the One Button to rule them all!
2024-03-12 18:10:53 +01:00
Serhii Snitsaruk ca6b497019 Sync order of variables in derived `BlackboardPlan` 2024-03-12 17:11:01 +01:00
Serhii Snitsaruk 434545ebad Blackboard: Linking vars with `Blackboard::link_var` 2024-03-12 16:17:34 +01:00
Serhii Snitsaruk a6e6b53e18 Improve prefetching 2024-03-12 00:30:38 +01:00
Serhii Snitsaruk 7de582c4e6 Fix complain parameter is not respected in `Blackboard::get_var` if parent scope is assigned 2024-03-11 23:04:34 +01:00
Serhii Snitsaruk e2edb083ff When prefetch fails, don't print error if variable is on blackboard 2024-03-11 22:12:44 +01:00
Serhii Snitsaruk b09006a11b Fix issues with blackboard plan system 2024-03-11 18:58:40 +01:00
Serhii Snitsaruk 92010f19f1
Merge pull request #70 from limbonaut/gha-fixes
GHA workflow updates
2024-03-11 18:00:46 +01:00
Serhii Snitsaruk b0e31f569a GHA: Don't include GodotSharp folder twice 2024-03-11 13:46:48 +01:00
Serhii Snitsaruk eba867706b GHA: Transition to new upload/download v4 actions 2024-03-11 13:27:23 +01:00
Serhii Snitsaruk 3ae38ee5da GHA: Bump cache & setup-python actions
Also fixes some Node.js-related warnings in GHA builds.
2024-03-10 14:33:02 +01:00
Serhii Snitsaruk 0be16edee0 GHA: Remove no longer needed workaround in web builds 2024-03-10 13:13:22 +01:00
Serhii Snitsaruk 37d3dcd988 GHA: Use consistent naming - limboai version first 2024-03-10 13:07:27 +01:00
Serhii Snitsaruk b0e3753d76 Update HSM unit tests 2024-03-08 20:04:27 +01:00
Serhii Snitsaruk 9957ef2ea7 Expose additional `BlackboardPlan` methods for custom tooling 2024-03-08 15:33:28 +01:00
Serhii Snitsaruk f4ceb27b35 Demo: Hide code popup upon Showcase scene load 2024-03-08 14:27:23 +01:00
Serhii Snitsaruk fda6fd5b8f
Merge pull request #69 from dpalais/root_parent_scope
Set parent scope in state initialization
2024-03-07 20:34:07 +01:00
Serhii Snitsaruk b90b85f0c3
Merge pull request #68 from Rubonnek/fix-btview-update-crash
Fix `BehaviorTreeView::update_tree` null data crash
2024-03-07 20:32:58 +01:00
Serhii Snitsaruk e182a56f7e
Merge pull request #67 from Rubonnek/expose-btview-clear
Expose `BehaviorTreeView::clear` to GDScript
2024-03-07 20:32:15 +01:00
Dave Palais 653bf13a7d Set parent scope in state initialization 2024-03-07 14:00:27 -05:00
Wilson E. Alvarez dd837ff472
Fix BehaviorTreeView::update_tree null data crash 2024-03-07 11:50:34 -05:00
Wilson E. Alvarez 3f34e4dde2
Expose BehaviorTreeView::clear to GDScript 2024-03-07 11:39:53 -05:00
Serhii Snitsaruk 41dafe642a Doc: Add a demonstration GIF to the README 2024-03-07 15:17:02 +01:00
Serhii Snitsaruk 25c72302ca
Merge pull request #66 from limbonaut/prefetching
Prefetching rework
2024-03-06 22:33:09 +01:00
Serhii Snitsaruk 81f49be6b4 Doc: Update class docs 2024-03-06 21:50:35 +01:00
Serhii Snitsaruk 2658060b1c Move prefetching code into `BlackboardPlan` and add checkbox to the plan editor 2024-03-06 21:28:06 +01:00
Serhii Snitsaruk f452552ecd
Merge pull request #65 from limbonaut/previous-state
Provide the previous state in the state_changed signal
2024-03-05 13:16:26 +01:00
Serhii Snitsaruk 193743e782 Provide the previous state in the state_changed signal
- Also provide `get_previous_active_state()` method.
- Rename state_changed -> active_state_changed.
2024-03-05 12:58:55 +01:00
Serhii Snitsaruk 27f3982250
Merge pull request #63 from limbonaut/refactor-ditch-p
Remove "p_" from the argument names in the `ClassDB` bindings
2024-03-04 21:54:01 +01:00
Serhii Snitsaruk 4c26583007 Remove "p_" from the argument names in the `ClassDB` bindings 2024-03-04 21:36:16 +01:00
Serhii Snitsaruk ae718ab00c
Merge pull request #61 from limbonaut/refactor-use-stringname
Refactor: Use `StringName` for variables and event names
2024-03-04 19:01:42 +01:00
Serhii Snitsaruk bea25049a0 Update plan editor utilizing `StringName` 2024-03-04 18:06:59 +01:00
Serhii Snitsaruk 0bd52d9b18 Demo: Update BTs & tasks to use `StringName` for variables
Also move tutorial BTs into trees/.
2024-03-04 18:06:41 +01:00
Serhii Snitsaruk d66f1e83fd Refactor BlackboardPlan to use StringName
Also update demo BTs.
2024-03-04 16:56:57 +01:00
Serhii Snitsaruk 923587e6e2 Doc: Update examples to use `StringName` 2024-03-04 16:27:35 +01:00
Serhii Snitsaruk ecf1e4b65f Doc: Update class docs 2024-03-04 16:19:39 +01:00
Serhii Snitsaruk 7cf4a4b3b8 Fix setter/getter types in BBVariable 2024-03-04 16:19:39 +01:00
Serhii Snitsaruk 88df78c4a2 Refactor HSM to use StringName for events 2024-03-04 16:19:35 +01:00
Serhii Snitsaruk 84aeb4bfff Adjust BB variable property editor to expect `StringName` 2024-03-04 15:09:15 +01:00
Serhii Snitsaruk 350c27abbc Change BB variable members to StringName 2024-03-04 12:54:45 +01:00
Serhii Snitsaruk b7d1bc11ab Blackboard: Use `StringName` for variable names 2024-03-03 23:38:52 +01:00
Serhii Snitsaruk e1bddb5d02 Doc: Fix README shields 2024-03-03 21:00:32 +01:00
Serhii Snitsaruk 507da30f04 Improve README 2024-03-03 20:53:27 +01:00
Serhii Snitsaruk 6b376e5e9a
Merge pull request #56 from dpalais/changes
Change some includes to use relative paths
2024-03-03 00:32:11 +01:00
Dave Palais 73aa636271 Change some includes to use relative paths
The paths before assumed we were inside the Godot modules folder.
This change enables building as an external module.
2024-03-02 18:10:00 -05:00
Serhii Snitsaruk f5d21e2669 Fix BTState not honoring API virtual methods 2024-03-02 20:19:38 +01:00
Serhii Snitsaruk c96e2019af Doc: Explain blackboard scopes 2024-03-02 16:17:40 +01:00
Serhii Snitsaruk bb6fab7555 API: Expose BlackboardPlan factory methods 2024-03-02 16:06:32 +01:00
Serhii Snitsaruk c4931ae420 Fix Blackboard.{set,get}_parent_scope should be {set,get}_parent in the API 2024-03-02 15:43:55 +01:00
Serhii Snitsaruk ba462c9526 Doc: Add copy button to the right of codeblocks 2024-03-02 13:15:17 +01:00
Serhii Snitsaruk e260498776 Doc: Explain parameters 2024-03-02 12:49:00 +01:00
Serhii Snitsaruk 6f9ff6a487 Doc: Update LimboState class doc 2024-03-02 00:10:44 +01:00
Serhii Snitsaruk aab38c9fb9 Doc: Rearrange pages 2024-03-02 00:06:34 +01:00
Serhii Snitsaruk 6d877c800a Doc: Add "State Machines" page.
Also update rst class docs.
2024-03-01 23:44:29 +01:00
Serhii Snitsaruk 543f2bb32c
Merge pull request #55 from limbonaut/hsm-dispatch-improvement
Allow `LimboState::dispatch` to be called from inside the hierarchy.
2024-03-01 11:56:38 +01:00
Serhii Snitsaruk eaeb57e2d7 Allow `LimboState::dispatch` to be called from inside the hierarchy.
Improves usability and removes requirement to call this method on the root state (see #49).
2024-03-01 11:02:32 +01:00
Serhii Snitsaruk 1aa64f8c5d
Merge pull request #54 from limbonaut/demo-show-code
Demo: Display source code when custom task is selected in BehaviorTreeView
2024-03-01 10:40:32 +01:00
Serhii Snitsaruk 24730a9213 Demo: Display custom task source code upon selection in BehaviorTreeView 2024-02-29 23:42:32 +01:00
Serhii Snitsaruk 7626c84633 New `task_selected` signal for BehaviorTreeView 2024-02-29 23:42:24 +01:00
Serhii Snitsaruk 2d98a38ada Fix "Manage" button is sometimes shown for derived plans 2024-02-29 15:45:59 +01:00
Serhii Snitsaruk c7a4988e6c
Merge pull request #52 from limbonaut/fix-hsm-update-crash
Fix crashing on HSM update with state transition
2024-02-26 22:29:09 +01:00
Serhii Snitsaruk 1c01767a56 Fix crashing on HSM update with state transition 2024-02-26 21:34:30 +01:00
Serhii Snitsaruk 9fbbea49a9 Fix exported demo builds breaking
Demo still requires tool builds - keeping release libs lean.
2024-02-19 11:02:28 +01:00
Serhii Snitsaruk 01d643831c Fix: Web GDExtension target lacks manifest entries and debug build 2024-02-18 22:55:42 +01:00
Serhii Snitsaruk 9d99e8bf9f Doc: Update README and setup_gdextension.sh 2024-02-18 22:51:59 +01:00
Serhii Snitsaruk d393784bbe Doc: Update accessing-nodes.rst 2024-02-18 20:50:09 +01:00
Serhii Snitsaruk c8ad4dc956 Doc: Sync rst class doc 2024-02-18 20:25:53 +01:00
Ola S. b8d054a080 Add icon for BTEvaluateExpression 2024-02-18 20:12:09 +01:00
Serhii Snitsaruk 0caa2369c6
Merge pull request #43 from Rubonnek/add-bt-evaluate-expression
Add `BTEvaluateExpression`
2024-02-18 19:43:34 +01:00
Wilson E. Alvarez fb958c7c34
Add BTEvaluateExpression 2024-02-18 12:20:48 -05:00
Serhii Snitsaruk 8176d5c83c
Merge pull request #46 from limbonaut/fix-task-icons-in-demo
Fix icons not shown for scripted tasks in demo with the module version
2024-02-18 15:52:43 +01:00
Serhii Snitsaruk 5b478b6229 Fix scripted task icons in demo with module version 2024-02-18 14:16:23 +01:00
Serhii Snitsaruk 27327cf18e
Merge pull request #45 from limbonaut/docs
Update documentation
2024-02-17 23:55:34 +01:00
Serhii Snitsaruk 487c008f5c Doc: Add accessing-nodes page 2024-02-17 23:54:38 +01:00
Serhii Snitsaruk e7f1d3a424 Doc: Update introduction to behavior trees 2024-02-17 23:25:45 +01:00
Serhii Snitsaruk 0f0a09cc5e
Merge pull request #44 from Rubonnek/fix-btv-formatting
Fix BehaviorTreeView doc formatting
2024-02-17 22:26:01 +01:00
Wilson E. Alvarez dad8d86d3e
Fix BehaviorTreeView doc formatting 2024-02-17 16:05:13 -05:00
Serhii Snitsaruk e1d03d651a Demo: Add icons for navigation buttons 2024-02-17 21:49:04 +01:00
Serhii Snitsaruk 291a40d33a Demo: Fix skirmisher variable missing errors 2024-02-17 20:42:31 +01:00
Serhii Snitsaruk cac44eadc7 Demo: Init scaling and base resolution 2024-02-17 20:42:31 +01:00
Serhii Snitsaruk 78c61d459d
Merge pull request #42 from limbonaut/debugger-improvements
Debugger improvements
2024-02-17 15:35:09 +01:00
Serhii Snitsaruk b3380bd0ac Fix missing break in a switch 2024-02-17 15:15:20 +01:00
Serhii Snitsaruk 7ebdfc9026 Update BehaviorTreeView class doc 2024-02-17 15:03:18 +01:00
Serhii Snitsaruk ecf44e83e0 Debugger: Add update interval controls and keep it in the config
Also fix bug with partial update.
2024-02-17 14:56:19 +01:00
Serhii Snitsaruk b9cd31eb2b Debugger: Add BehaviorTreeView::update_interval_msec property 2024-02-17 13:40:53 +01:00
Serhii Snitsaruk 0ea8b9932c Debugger: Implement selective tree update in BehaviorTreeView
Flame graph showed performance bottleneck with recreating and redrawing the whole tree each frame.
This commit should improve debugger performance by a good margin.
2024-02-17 11:43:31 +01:00
Serhii Snitsaruk 38409d45f9
Merge pull request #41 from Rubonnek/fix-typed-array-crash
Fix crash upon increasing TypedArray<BBVariant> size
2024-02-16 17:58:40 +01:00
Wilson E. Alvarez 1711cb6b87
Fix crash upon increasing TypedArray<BBVariant> size
Needed after upstream patch:

db7175458a
2024-02-16 10:46:42 -05:00
Serhii Snitsaruk b220a9f418 GHA: Remove project.godot from GDExtension build 2024-02-15 22:40:53 +01:00
Serhii Snitsaruk 91f3148493 Demo: Init input via code to insure that demo works even when project.godot is not imported 2024-02-15 22:34:32 +01:00
Serhii Snitsaruk 5909735add GHA: Just copy the whole demo in GDExtension build 2024-02-15 17:06:38 +01:00
Serhii Snitsaruk bc3fe05a4d GHA: Bundle license with GDExtension build 2024-02-15 16:33:08 +01:00
Serhii Snitsaruk d9c6a64a62 Move LICENSE_ASSETS.md 2024-02-15 16:31:08 +01:00
Serhii Snitsaruk ed69bcf0bb
Update README.md 2024-02-15 16:23:15 +01:00
Serhii Snitsaruk ac2052bd4b
Merge pull request #39 from limbonaut/gha-package-demo
GHA: Package demo project
2024-02-15 15:42:51 +01:00
Serhii Snitsaruk 3c9fc333b0 GHA: Tweaks 2024-02-15 14:34:05 +01:00
Serhii Snitsaruk 17291081e5 GHA: Package demo project 2024-02-15 14:24:45 +01:00
Serhii Snitsaruk b0245457db
Merge pull request #36 from limbonaut/gha-web-gdextension
GHA: Fix web gdextension build
2024-02-15 12:54:09 +01:00
Serhii Snitsaruk b5247dda0f GHA: Fix strip running and failing in gdextension web 2024-02-15 12:15:41 +01:00
Serhii Snitsaruk 69751260a6 GHA: Update path-ignore 2024-02-14 21:27:08 +01:00
Serhii Snitsaruk 8e2fdc4bc0 GHA: Fix web gdextension build 2024-02-14 21:27:04 +01:00
Serhii Snitsaruk 8a226a1160 Demo: Tweak descriptions 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk e09928f87f Demo: Fix ninja star 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk cd4e28f391 Demo: Add LICENSE_ASSETS.md 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 9443c50d94 Demo: Add tutorial and improve UI 2024-02-14 21:09:16 +01:00
Ola S. 9eb7a9c346 Junior sprite 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 1de059d806 Demo: Numerous improvements, refactoring and comments 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk dae96feeb9 Demo: Link game to showcase and vice versa 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk f54c86f9fc Demo: Dash => Dodge 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 22eea7be0e Demo: Implement rounds, gameplay, and balance agents 2024-02-14 21:09:16 +01:00
Ola S. adc9490672 Add HP bar graphics 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 7949330c90 Demo: Refactoring, docstrings and tweaks 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk c925bab659 Demo: Rename agents 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 73152b5760 Demo fixes 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 065b6dc29b Demo: Add a showcase scene and tweak imp 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 102a770c42 Demo: Refactor arena and add dummy 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 2451cf801f Demo: Implement Summoner and Imp 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 51012571ae Fix issues with demon & imp loading 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 39d1440b96 Demo: Add demon BT 2024-02-14 21:09:16 +01:00
Ola S. 2fd15f04d6 New shadow 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk dc8aaa6098 Demo: Implement skirmisher AI 2024-02-14 21:09:16 +01:00
Ola S. 778ee80dda Add charge and dance animations 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk fa804f3f6d Demo: Implement basic knockback 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 79813d57a8 Demo: Implement combo enemy BT 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk f6ce516771 Demo: Improved AI for melee and ranged 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 92ecc17a44 Demo: Simple avoidance using collision shapes 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk d0ff58052d Demo: Add AI for ranged enemy 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk c8ecaf6c8c Demo: Add throwing stars routine to nuanced melee
Also add collisions to gong.
Also don't register hits for enemies from enemies
2024-02-14 21:09:16 +01:00
Ola S. 8bce9cceb7 Add shadow 2024-02-14 21:09:16 +01:00
Ola S. 154bd2a839 Add dummy 2024-02-14 21:09:16 +01:00
Ola S. bea67b9a87 Added ranged animations 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 688a5416f2 Demo: Implement flanking for nuanced melee agent
Also add license info to the scripts.
2024-02-14 21:09:16 +01:00
Serhii Snitsaruk e9e582f251 gitignore: Ignore script templates in demo 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk f85555675b Demo: Combo attack, better particles and animation tweaks 2024-02-14 21:09:16 +01:00
Serhii Snitsaruk 597a795d6b Demo: Simplify melee AI 2024-02-14 21:09:15 +01:00
Ola S. c61f265454 Animation changes 2024-02-14 21:09:15 +01:00
Serhii Snitsaruk 67d86214f0 Demo: Attack state and simple melee AI 2024-02-14 21:09:15 +01:00
Serhii Snitsaruk 4719c77f94 Demo: Add player idle and move states 2024-02-14 21:09:15 +01:00
Ola S. 828f4dbad5 Smoke replacement 2024-02-14 21:09:15 +01:00
Ola S. da8c5b9a83 Add smoke sprite 2024-02-14 21:09:15 +01:00
Ola S. c2603554e6 Add fireball sprite 2024-02-14 21:09:15 +01:00
Serhii Snitsaruk 1d35d84ec5 Demo: Refactor agents, add health, hitbox and hurtbox 2024-02-14 21:09:15 +01:00
Ola S. a839be1ada Fixed the grass 2024-02-14 21:09:15 +01:00
Serhii Snitsaruk 47c0c4e85c Demo: Reorganize demo scene for Y sorting 2024-02-14 21:09:15 +01:00
Ola S. 55fb102838 Demo: Assets, scenes & animations for the new demo 2024-02-14 21:09:15 +01:00
Serhii Snitsaruk dd3eebabf1 Doc: Update class rst 2024-02-14 20:34:18 +01:00
Serhii Snitsaruk 58ff47d688 GHA: Add web build to GDExtension workflow 2024-02-14 20:33:52 +01:00
Serhii Snitsaruk a60280ccfb Doc: Update README.md 2024-02-14 20:32:32 +01:00
Serhii Snitsaruk be0b5233c0 Doc: Add C# instructions 2024-02-14 19:58:50 +01:00
Serhii Snitsaruk fcedf681cd GH: Create FUNDING.yml 2024-02-14 15:53:58 +01:00
Serhii Snitsaruk 69bcc763f7
Merge pull request #35 from limbonaut/complain-if-variable-missing
Blackboard: Complain when variable is missing
2024-02-13 18:26:15 +01:00
Serhii Snitsaruk 0081731654 Fix tests printing errors 2024-02-13 17:27:32 +01:00
Serhii Snitsaruk 6d36d20d06 Blackboard: Complain when variable is missing 2024-02-13 17:15:19 +01:00
Serhii Snitsaruk 5621b433c9
Merge pull request #33 from limbonaut/runlimit-policy
Runlimit policy
2024-02-10 21:08:12 +01:00
Serhii Snitsaruk 3a6dc1e90c BTRunLimit: Update class doc 2024-02-10 20:29:48 +01:00
Serhii Snitsaruk 55dfd55645 BTRunLimit: Update unit tests 2024-02-10 20:14:49 +01:00
Serhii Snitsaruk e6e2f5595d BTRunLimit: Add `count_policy` property
Breaking compatibility: RunLimit count policy defaults to counting only successful runs. Previously, both successful and failed runs were counted.
2024-02-10 20:13:39 +01:00
Serhii Snitsaruk 654eda1c65 Better error handling when resolving _generate_name 2024-02-10 15:05:50 +01:00
Serhii Snitsaruk 899335d1fe Util: Function to decorate output variable 2024-02-10 12:34:29 +01:00
Serhii Snitsaruk 95c2496adf Improve variable synchronization between base and derived blackboard plans
When variable is altered in the base plan, values should properly sync to the derived plans if those vars are not altered in the derived plan. Editor QoL improvement.
2024-02-09 13:58:54 +01:00
Serhii Snitsaruk 98a685b592
Merge pull request #32 from limbonaut/copypaste
Editor: Implement Cut-Copy-Paste
2024-02-08 17:45:03 +01:00
Serhii Snitsaruk d38e6f97f1 Editor: Implement Cut-Copy-Paste
Resolves #14
2024-02-08 17:16:26 +01:00
Serhii Snitsaruk fca8aea99c
Merge pull request #31 from limbonaut/fix-transitions-to-self
Disallow LimboHSM transitions to self when ANYSTATE is used
2024-02-07 13:57:43 +01:00
Serhii Snitsaruk 22c472fdd1 Disallow LimboHSM transitions to self when ANYSTATE is used
Resolves #29
2024-02-07 13:39:45 +01:00
Serhii Snitsaruk 8260954654
Merge pull request #30 from limbonaut/keyboard-shortcuts
Fix shortcuts not working in the module version
2024-02-07 13:21:23 +01:00
Serhii Snitsaruk 6405f9031b Fix shortcuts not working in the module version
Resolves #27
2024-02-07 12:36:59 +01:00
Serhii Snitsaruk 449538d6d3
Merge pull request #26 from limbonaut/debugger-crash-fix
Fix: Debugger crashes when detached in GDExtension
2024-02-06 16:52:19 +01:00
Serhii Snitsaruk 6713ea1590 Fix: Debugger crashes when detached in GDExtension
Resolves #25.
2024-02-06 16:30:02 +01:00
Serhii Snitsaruk 16840057a1 Editor: More space and align to right for BehaviorTreeView timings 2024-02-06 15:44:25 +01:00
Serhii Snitsaruk a353e561de Editor: More space for timings in BehaviorTreeView 2024-02-06 14:54:18 +01:00
Serhii Snitsaruk d0c7d98fc4 Editor: Clip content in BehaviorTreeView 2024-02-04 16:23:15 +01:00
Serhii Snitsaruk 74a3635e1c
Merge pull request #24 from limbonaut/expose-behavior-tree-view
Expose `BehaviorTreeView` and `BehaviorTreeData` to use with custom in-game tools
2024-02-03 21:09:51 +01:00
Serhii Snitsaruk 3ce199f628 Fix GDExtension template compilation error 2024-02-03 17:59:21 +01:00
Ola S. f60fa3a7f2 Add icon for BehaviorTreeView 2024-02-03 17:55:05 +01:00
Serhii Snitsaruk 8dc645c9a7 Fix issues and update docs for BehaviorTreeData/View 2024-02-03 17:53:12 +01:00
Serhii Snitsaruk c5b92aa676 Expose BehaviorTreeView for tools and in-game use 2024-02-03 16:59:51 +01:00
Serhii Snitsaruk 5bd8a90dcd
Merge pull request #23 from limbonaut/remember-collapsed
Editor: Remember collapsed items in the task tree
2024-02-02 17:40:57 +01:00
Serhii Snitsaruk 3e32051791 Editor: Remember collapsed items in task tree 2024-02-02 16:46:26 +01:00
Serhii Snitsaruk b0e4c15982
Merge pull request #22 from Rubonnek/fix-doc
Fix wrong parameter reference in Blackboard documentation
2024-02-02 11:40:12 +01:00
Wilson E. Alvarez b765b2adc8
Fix wrong parameter reference in Blackboard documentation 2024-02-01 20:47:54 -05:00
Serhii Snitsaruk ab564eb631 BTProbability: Fix incorrect percentage shown 2024-01-31 15:40:59 +01:00
Serhii Snitsaruk c49f5d2b0a
Merge pull request #21 from VisitingOcean/small_docs_fix
Fix space/tab issues in custom-tasks.rst
2024-01-31 10:48:58 +01:00
VisitingOcean 9576cdc8e7
Update custom-tasks.rst
Fix some spacing typos to prevent mixed space/tab errors when copy/pasting into the Godot editor.
2024-01-30 16:48:42 -06:00
Serhii Snitsaruk caff21137d Doc: Add page on sharing data with Blackboard 2024-01-29 14:53:53 +01:00
Serhii Snitsaruk 61ef929411 Editor: Don't allow variables with the same names as Resource props 2024-01-29 10:32:32 +01:00
Serhii Snitsaruk b4ab521e0f Editor: Improve tooltips in the property editors 2024-01-29 10:26:13 +01:00
Serhii Snitsaruk ee0795269d Editor: Fix issues with property editors & remove old docs 2024-01-29 10:16:24 +01:00
Serhii Snitsaruk 11f43c2494 Update demo 2024-01-28 22:36:30 +01:00
Serhii Snitsaruk 656bc169b0 Editor: Scroll to focus when adding a var in Blackboard Plan editor 2024-01-28 22:25:31 +01:00
Serhii Snitsaruk c44648c69c Fix nullptr crash 2024-01-28 22:00:47 +01:00
Ola S. de8d3abbc8 Add icon for private vars in the EditorPropertyVariableName 2024-01-28 21:59:39 +01:00
Serhii Snitsaruk 011040e46f Editor: Distinguish private variables in the inspector 2024-01-28 21:58:18 +01:00
Serhii Snitsaruk 87a1687c74 BlackboardPlanEditor: Focus on added var and autofill name 2024-01-28 21:03:22 +01:00
Serhii Snitsaruk 174810fb34 Editor: Validate var name in BlackboardPlanEditor 2024-01-28 20:15:42 +01:00
Serhii Snitsaruk 7ac1bc2dec Use variable property editor within the param property editor 2024-01-28 19:24:59 +01:00
Ola S. b8bf8e07e9 Add icons for variable property editor 2024-01-28 17:49:55 +01:00
Serhii Snitsaruk 73f51f23ef Implement BB variable property editor 2024-01-28 17:49:38 +01:00
Serhii Snitsaruk 2612ec0855 Fix LimboHSM::add_transition signature 2024-01-28 11:56:53 +01:00
Serhii Snitsaruk c81c1ec872 Blackboard: Add variable-to-property binding interface 2024-01-27 21:44:58 +01:00
Serhii Snitsaruk a6717ec76d Editor: Show only relevant hints for the chosen variant type in the Blackboard Plan editor 2024-01-26 16:47:45 +01:00
Serhii Snitsaruk 761b211740 Editor: Mark behavior tree as dirty when blackboard plan changes 2024-01-26 16:47:26 +01:00
Serhii Snitsaruk f8ce5c1311 GHA: Fix iOS packaging 2024-01-26 13:42:51 +01:00
Serhii Snitsaruk 662738e6bf
Merge pull request #20 from limbonaut/blackboard-improvements
Rework `Blackboard` API and introduce `BlackboardPlan` resource and editor.

- `BBVariable` object holds the value of a blackboard variable and its metadata (not exposed to the API).
- `BlackboardPlan` resource stores and manages a collection of variables, and is used to construct new `Blackboard` instances.
  - Each `BehaviorTree` resource has its own `BlackboardPlan` resource that acts as a blueprint.
  - `BTPlayer` also has its own `BlackboardPlan` which extends the behavior tree `BlackboardPlan` resource, i.e. variables from BehaviorTree are overridden in the BTPlayer node.
- Editor for the `BlackboardPlan` resources
  - Accessed with "Manage" button in the inspector.
  - Rename, reposition, and change type and hint of the blackboard variables.
  - Edit default variable values directly in the inspector.
- Define variables in the `BehaviorTree` blackboard plan and override those variables in the `BTPlayer`'s plan.
- Fully compatible with both module and GDExtension builds!
2024-01-26 11:14:25 +01:00
Serhii Snitsaruk f912f0acc4 Usability improvements 2024-01-25 22:58:21 +01:00
Ola S. a22860b244 Add BlackboardPlan icon 2024-01-25 21:08:03 +01:00
Serhii Snitsaruk 5fee89b00b Make blackboard improvements compatible with GDExtension 2024-01-25 19:46:27 +01:00
Serhii Snitsaruk a251d92aa3 Update class documentation 2024-01-25 14:56:59 +01:00
Serhii Snitsaruk 8155c2764a Refactoring and clean up 2024-01-25 14:35:48 +01:00
Serhii Snitsaruk fb1ab16682 In a derived BB plan, hide variables with names that begin with "_" 2024-01-25 11:51:35 +01:00
Serhii Snitsaruk 06052332b2 BlackboardPlanEditor: Fixes and clean up 2024-01-25 11:08:35 +01:00
Serhii Snitsaruk 15e0323919 Implement BlackboardPlan editor 2024-01-24 23:11:09 +01:00
Serhii Snitsaruk 20a995d1d2 Rename BlackboardSource => BlackboardPlan
Because it's a better name ;)
2024-01-23 20:02:23 +01:00
Serhii Snitsaruk b04f7530e4 Add a mechanism for overriding and resetting variables in a derived blackboard source 2024-01-23 17:54:20 +01:00
Serhii Snitsaruk f84127657b Fix crash while initializing blackboard in the BTPlayer node 2024-01-23 16:22:10 +01:00
Serhii Snitsaruk dc40109ade Fix default object value issues 2024-01-23 15:56:30 +01:00
Serhii Snitsaruk 8c67886b52 Parsing BlackboardSource properties 2024-01-23 15:31:56 +01:00
Serhii Snitsaruk a247d0d67b Replace node blackboard data with BlackboardSource 2024-01-23 12:05:54 +01:00
Serhii Snitsaruk 6ef0dd942e Add initial implementation of BBVariable and BlackboardSource classes 2024-01-23 10:33:57 +01:00
Serhii Snitsaruk 33b455f8d9 Add BBParam missing types 2024-01-19 17:15:22 +01:00
Serhii Snitsaruk 881a32f92d Doc: Remove native method override stuff from gdextension.rst
It's no longer true.
2024-01-19 14:34:50 +01:00
Serhii Snitsaruk 782e72d92d GHA: Change godot repo ref to "4.2" 2024-01-19 14:01:02 +01:00
Serhii Snitsaruk a3f8c09766 Use the new virtual workaround and rework LimboState and HSM 2024-01-18 11:33:24 +01:00
Serhii Snitsaruk 390d4a9385 New and improved workaround for the missing ClassDB::add_virtual_method 2024-01-17 22:46:48 +01:00
Serhii Snitsaruk caa1508fea
Merge pull request #18 from limbonaut/prerelease-prep
Pre-release prep work
2024-01-17 19:17:42 +01:00
Serhii Snitsaruk db51defddd GHA: For GDExtension builds, package demo, license and readme 2024-01-17 17:54:20 +01:00
Serhii Snitsaruk c5be3a725f Editor: Links to "Creating custom tasks" doc page in the editor 2024-01-17 15:51:24 +01:00
Serhii Snitsaruk 27d3ec7555 Editor: Show alert about editing project settings in GDExtension 2024-01-17 15:17:22 +01:00
Serhii Snitsaruk dc8dcf9d71 Add action banner if native method override warning is set to Error 2024-01-17 14:49:43 +01:00
Serhii Snitsaruk 242c1f03d7 Fix: Introduction points to a wrong page 2024-01-17 14:16:35 +01:00
Serhii Snitsaruk 7ccda2736d In setup_gdextension.sh, add options --copy-all and --trash-old 2024-01-17 12:01:13 +01:00
Serhii Snitsaruk a5728a11a0 In update_icons.py, sort by filename before updating entries 2024-01-17 11:14:51 +01:00
Serhii Snitsaruk 12dbd9e1a6 Restructure demo project for better compatibility with AssetLib package
Also, add warning ignores for the custom task.
2024-01-16 21:51:47 +01:00
Serhii Snitsaruk 9bfa0268c1 create logo_and_screenshot.png 2024-01-16 15:25:52 +01:00
Serhii Snitsaruk 1ac96bc330 Add logo signet and screenshots 2024-01-16 15:22:09 +01:00
597 changed files with 32382 additions and 4695 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
ko_fi: limbonaut

64
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Bug report
description: Report a bug in LimboAI
labels:
- bug
body:
- type: markdown
attributes:
value: |
- Write a descriptive title above.
- Search [open](https://github.com/limbonaut/limboai/issues) and [closed](https://github.com/limbonaut/limboai/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
- type: input
attributes:
label: Godot version
description: |
- Specify the Godot version and hardware information if relevant.
- You can copy the version info by clicking on it in the Godot status bar.
- Alternatively, you can copy the version and hardware info in Godot using the main menu command "Help -> Copy System Info".
placeholder: v4.2.2.limboai+v1.1.0.gha [15073afe3]
validations:
required: true
- type: input
attributes:
label: LimboAI version
description: |
- Specify the LimboAI version.
- You can copy the version info by clicking on it in the toolbar of the LimboAI editor (top-right corner).
placeholder: v1.1.0 [8fa609e]
validations:
required: true
- type: dropdown
id: variant
attributes:
label: LimboAI variant
description: Which variant of our plugin are you running?
options:
- GDExtension / AssetLib
- Module (custom editor or template build)
default: 0
validations:
required: true
- type: textarea
attributes:
label: Issue description
description: |
- Describe your issue in detail. What doesn't work and how do you expect it to work instead?
- Provide screenshots and/or a console output if it helps to convey the problem.
validations:
required: true
- type: textarea
attributes:
label: How to reproduce
description: |
- Provide a list of steps or sample code that reproduces the issue.
- You can provide a small Godot project which reproduces the issue, with no unnecessary files included.
- Drag and drop a ZIP archive to upload it (10Mb limit).
- Don't include the `.godot` folder in the archive.
- Redroduction project helps to find the bug more quickly!
validations:
required: true

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Documentation
url: https://limboai.readthedocs.io/en/stable/
about: Please see our documentation for more information.
- name: Discussions
url: https://github.com/limbonaut/limboai/discussions
about: Need help? Ask questions in Discussions or on our Discord server.
- name: Discord Server
url: https://discord.gg/N5MGC95GpP
about: Share your experience or get help on our Discord server.

View File

@ -0,0 +1,38 @@
name: Feature or improvement proposal
description: Propose a new feature to be added or improved in LimboAI
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
- Write a descriptive title above.
- Search [open](https://github.com/limbonaut/limboai/issues) and [closed](https://github.com/limbonaut/limboai/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
- type: textarea
attributes:
label: Problem statement
description: |
- Describe the problem or limitation you're currently facing with the LimboAI plugin.
- If it helps, describe the project you're working on and how it relates to the problem or limitation.
validations:
required: true
- type: textarea
attributes:
label: Proposed solution
description: |
- Describe your proposed solution and how it helps to overcome the problem or limitation.
- If it helps, show how it will work with code, pseudo-code, mock-ups, and/or diagrams.
- You can include any images or videos with drag'n'drop, and sample code blocks with <code>```</code> tags.
validations:
required: true
- type: textarea
attributes:
label: Alternatives
description: |
- Describe alternative solutions and features you've considered.
- If this enhancement will not be used often, can it be worked around with a few clicks or lines of code?
validations:
required: true

View File

@ -0,0 +1,33 @@
name: Build .NET assemblies
inputs:
platform:
required: true
type: choice
options:
- linuxbsd
- windows
- macos
bin:
required: true
type: string
runs:
using: "composite"
steps:
- name: Override GODOT_VERSION_STATUS for NuGet packages
shell: bash
run: |
GODOT_VERSION_STATUS=$(echo "${GODOT_VERSION_STATUS}" | sed "s|+|-|").gha
echo "GODOT_VERSION_STATUS=${GODOT_VERSION_STATUS}" >> "$GITHUB_ENV"
echo "GODOT_VERSION_STATUS: ${GODOT_VERSION_STATUS}"
- name: Generate C# glue
shell: bash
run: |
./bin/${{inputs.bin}} --headless --generate-mono-glue ./modules/mono/glue || true
- name: Build .NET assemblies
shell: bash
run: |
python ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=${{ inputs.platform }}

View File

@ -15,10 +15,10 @@ runs:
echo "GDEXTENSION_VERSION=${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"
cd ../limboai
cd ..
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
- name: Set NAME_PREFIX
shell: bash
run: echo "NAME_PREFIX=gdextension-${GDEXTENSION_VERSION}.limboai+${LIMBOAI_VERSION}" >> "$GITHUB_ENV"
run: |
echo "NAME_PREFIX=limboai+${LIMBOAI_VERSION}.gdextension-${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"

View File

@ -12,7 +12,7 @@ runs:
- name: Set NAME_PREFIX
shell: bash
run: echo "NAME_PREFIX=godot-${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" >> "$GITHUB_ENV"
run: echo "NAME_PREFIX=limboai+${LIMBOAI_VERSION}.godot-${GODOT_VERSION}" >> "$GITHUB_ENV"
- name: Set GODOT_VERSION_STATUS & BUILD_NAME
shell: bash

View File

@ -0,0 +1,58 @@
name: Setup Linux toolchain
inputs:
arch:
required: true
runs:
using: "composite"
steps:
- name: Set up environment
shell: bash
run: |
# ! Settings:
TOOLCHAIN_64_URL=https://github.com/godotengine/buildroot/releases/download/godot-2020.11.x-2/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
TOOLCHAIN_64_SHA=16c8302fcb676c1f0fb9df73d6cff250ba1f4286
TOOLCHAIN_32_URL=https://github.com/godotengine/buildroot/releases/download/godot-2020.11.x-2/i686-godot-linux-gnu_sdk-buildroot.tar.bz2
TOOLCHAIN_32_SHA=6171652abc54ef219e5187bc53660ee4e2f796f4
TOOLCHAIN_ARM64_URL=https://github.com/godotengine/buildroot/releases/download/godot-2023.08.x-3/aarch64-godot-linux-gnu_sdk-buildroot.tar.bz2
TOOLCHAIN_ARM64_SHA=73bed3d26b92c8b9a93c0ceb6bcce8fe567d1764
TOOLCHAIN_ARM32_URL=https://github.com/godotengine/buildroot/releases/download/godot-2023.08.x-3/arm-godot-linux-gnueabihf_sdk-buildroot.tar.bz2
TOOLCHAIN_ARM32_SHA=aa5853fd73faec3837c6127649471275d7e61cb2
# ! Export variables:
if [[ "${{ inputs.arch }}" == "x86_64" ]]; then
echo "TOOLCHAIN_URL=${TOOLCHAIN_64_URL}" >> "$GITHUB_ENV"
echo "TOOLCHAIN_SHA=${TOOLCHAIN_64_SHA}" >> "$GITHUB_ENV"
elif [[ "${{ inputs.arch }}" == "x86_32" ]]; then
echo "TOOLCHAIN_URL=${TOOLCHAIN_32_URL}" >> "$GITHUB_ENV"
echo "TOOLCHAIN_SHA=${TOOLCHAIN_32_SHA}" >> "$GITHUB_ENV"
elif [[ "${{ inputs.arch }}" == "arm64" ]]; then
echo "TOOLCHAIN_URL=${TOOLCHAIN_ARM64_URL}" >> "$GITHUB_ENV"
echo "TOOLCHAIN_SHA=${TOOLCHAIN_ARM64_SHA}" >> "$GITHUB_ENV"
elif [[ "${{ inputs.arch }}" == "arm32" ]]; then
echo "TOOLCHAIN_URL=${TOOLCHAIN_ARM32_URL}" >> "$GITHUB_ENV"
echo "TOOLCHAIN_SHA=${TOOLCHAIN_ARM32_SHA}" >> "$GITHUB_ENV"
fi
- name: Cache buildroot
id: cache-buildroot
uses: actions/cache@v4
with:
path: buildroot
key: ${{env.TOOLCHAIN_SHA}}
- name: Set up buildroot
if: steps.cache-buildroot.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir buildroot
wget ${TOOLCHAIN_URL} -O buildroot/buildroot.tar.bz2
cd buildroot
echo "${TOOLCHAIN_SHA} buildroot.tar.bz2"
echo "${TOOLCHAIN_SHA} buildroot.tar.bz2" | shasum --check
tar -xjf buildroot.tar.bz2 --strip-components=1
ls -l
rm buildroot.tar.bz2
./relocate-sdk.sh
cd ..

View File

@ -2,22 +2,22 @@ name: 🔗 All builds
on:
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: 4.2.1-stable
limboai-treeish:
default: master
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
godot-cpp-treeish:
godot-cpp-ref:
description: A tag, branch or commit hash in the godot-cpp repository.
type: string
default: 4.2
default: master
jobs:
cache-sha:
name: Cache treeish SHA
name: Cache SHA
runs-on: ubuntu-latest
outputs:
godot-sha: ${{ steps.cache-sha.outputs.godot-sha }}
@ -27,13 +27,13 @@ jobs:
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
- name: Cache SHA
id: cache-sha
@ -47,24 +47,24 @@ jobs:
needs: cache-sha
uses: ./.github/workflows/android.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
ios-build:
name: 🍏 iOS
needs: cache-sha
uses: ./.github/workflows/ios.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
linux-build:
name: 🐧 Linux
needs: cache-sha
uses: ./.github/workflows/linux.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
test-build: false
macos-build:
@ -72,16 +72,16 @@ jobs:
needs: cache-sha
uses: ./.github/workflows/macos.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
windows-build:
name: 🪟 Windows
needs: cache-sha
uses: ./.github/workflows/windows.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
test-build: false
web-build:
@ -89,14 +89,39 @@ jobs:
needs: cache-sha
uses: ./.github/workflows/web.yml
with:
godot-treeish: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
gdextension:
name: 🔌 GDExtension
needs: cache-sha
uses: ./.github/workflows/gdextension.yml
with:
godot-cpp-treeish: ${{ inputs.godot-cpp-treeish }}
limboai-treeish: ${{ needs.cache-sha.outputs.limboai-sha }}
godot-cpp-ref: ${{ inputs.godot-cpp-ref }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
test-build: false
demo:
name: 🎮️ Demo project
needs: cache-sha
uses: ./.github/workflows/demo.yml
with:
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
merge_templates:
name: 📦 Merge templates
if: ${{ always() }}
needs:
[
cache-sha,
android-build,
ios-build,
linux-build,
macos-build,
windows-build,
web-build,
]
uses: ./.github/workflows/merge_templates.yml
with:
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}

View File

@ -2,22 +2,22 @@ name: 🤖 Android builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
@ -37,59 +37,123 @@ jobs:
fail-fast: false
matrix:
include:
# * Standard arm64
- name: Template (arm64, debug)
arch: arm64
target: template_debug
dotnet: false
- name: Template (arm64, release)
arch: arm64
target: template_release
dotnet: false
# * Standard arm32
- name: Template (arm32, debug)
arch: arm32
target: template_debug
dotnet: false
- name: Template (arm32, release)
arch: arm32
target: template_release
dotnet: false
# * Standard x86_64
- name: Template (x86_64, debug)
arch: x86_64
target: template_debug
dotnet: false
- name: Template (x86_64, release)
arch: x86_64
target: template_release
dotnet: false
# * Standard x86_32
- name: Template (x86_32, debug)
arch: x86_32
target: template_debug
dotnet: false
- name: Template (x86_32, release)
arch: x86_32
target: template_release
dotnet: false
# * .NET arm64
- name: Template .NET (arm64, debug)
arch: arm64
target: template_debug
dotnet: true
- name: Template .NET (arm64, release)
arch: arm64
target: template_release
dotnet: true
# * .NET arm32
- name: Template .NET (arm32, debug)
arch: arm32
target: template_debug
dotnet: true
- name: Template .NET (arm32, release)
arch: arm32
target: template_release
dotnet: true
# * .NET x86_64
- name: Template .NET (x86_64, debug)
arch: x86_64
target: template_debug
dotnet: true
- name: Template .NET (x86_64, release)
arch: x86_64
target: template_release
dotnet: true
# * .NET x86_32
- name: Template .NET (x86_32, debug)
arch: x86_32
target: template_debug
dotnet: true
- name: Template .NET (x86_32, release)
arch: x86_32
target: template_release
dotnet: true
env:
BIN: godot.linuxbsd.${{matrix.target}}.${{matrix.arch}} #${{ matrix.build-mono == true && '.mono' || '' }}
BIN: godot.linuxbsd.${{matrix.target}}.${{matrix.arch}}${{ matrix.dotnet == true && '.mono' || '' }}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Set up Java 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
@ -101,65 +165,75 @@ jobs:
python --version
scons --version
- name: Set up scons cache
uses: actions/cache@v3
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-treeish}}
# ! Note: we stopped using the scons cache in release builds.
# - name: Set up scons cache
# uses: actions/cache@v4
# with:
# path: ${{github.workspace}}/.scons_cache/
# key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# restore-keys: |
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
# ${{env.BIN}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
scons platform=android target=${{matrix.target}} arch=${{matrix.arch}} ${{env.SCONSFLAGS}}
scons platform=android target=${{matrix.target}} arch=${{matrix.arch}} module_mono_enabled=${{matrix.dotnet}} ${{env.SCONSFLAGS}}
ls platform/android/java/lib/libs/*
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: android-templates
name: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-${{strategy.job-index}}
path: platform/android/java/lib/libs/*
make-android-package:
runs-on: "ubuntu-20.04"
name: Make Android package
needs: android-builds
name: ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- name: Package Android templates
dotnet: false
- name: Package Android .NET templates
dotnet: true
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Download Android template builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: android-templates
pattern: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
merge-multiple: true
path: platform/android/java/lib/libs/
- name: Set up Java 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up Python 3.x
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: 3.x
architecture: x64
@ -180,23 +254,24 @@ jobs:
mkdir -p out/templates/
mv bin/android_* out/templates/
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
ls -l out/*
- name: Delete Android template builds
uses: geekyeggo/delete-artifact@v2
uses: geekyeggo/delete-artifact@v5
with:
name: android-templates
failOnError: false
name: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
useGlob: true
failOnError: false
- name: Upload Android libs
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.android-lib
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.android-lib
path: bin/godot-lib.*
- name: Upload Android templates
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.export-templates
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.export-templates.android
path: out/*

46
.github/workflows/demo.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: 🎮️ Demo project
on:
workflow_call:
inputs:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
workflow_dispatch:
inputs:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
jobs:
package-demo:
runs-on: ubuntu-latest
name: Package demo
steps:
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
fetch-tags: true
ref: ${{ inputs.limboai-ref }}
- name: Init version
run: echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
- name: Prepare artifact
shell: bash
run: |
cp {README,LICENSE}.md demo/
mkdir -p demo/addons/limboai/
cp -R icons/ demo/addons/limboai/icons
echo "${LIMBOAI_VERSION}" > demo/version.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
env:
NAME: limboai+${{env.LIMBOAI_VERSION}}.demo-project
with:
name: ${{ env.NAME }}
path: demo/*

View File

@ -2,43 +2,57 @@ name: 🔌 GDExtension
on:
workflow_call:
inputs:
godot-cpp-treeish:
godot-cpp-ref:
description: A tag, branch or commit hash in the godot-cpp repository.
type: string
default: 4.2
limboai-treeish:
default: godot-4.3-stable
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
debug-symbols:
description: Build with debug symbols
type: boolean
default: false
workflow_dispatch:
inputs:
godot-cpp-treeish:
godot-cpp-ref:
description: A tag, branch or commit hash in the godot-cpp repository.
type: string
default: 4.2
limboai-treeish:
default: godot-4.3-stable
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
debug-symbols:
description: Build with debug symbols
type: boolean
default: false
# Global Settings
env:
SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: dev_build=no debug_symbols=no
SCONSFLAGS: use_mingw=yes dev_build=no
EM_VERSION: 3.1.45
EM_CACHE_FOLDER: "emsdk-cache"
GODOT_VERSION: 4.4-beta3
GODOT_REPO: godotengine/godot-builds
jobs:
gdextension:
runs-on: ${{ matrix.opts.runner }}
name: ${{ matrix.opts.name }}
outputs:
name-prefix: ${{ steps.output-name-prefix.outputs.name-prefix }}
strategy:
fail-fast: false
matrix:
@ -85,125 +99,288 @@ jobs:
arch: universal
should-build: true
- name: 🌐 Web (wasm32, release)
runner: ubuntu-20.04
platform: web
target: template_release
arch: wasm32
should-build: ${{ !inputs.test-build }}
- name: 🌐 Web (wasm32, debug)
runner: ubuntu-20.04
platform: web
target: editor
arch: wasm32
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (arm64, release)
runner: ubuntu-20.04
platform: android
target: template_release
arch: arm64
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (arm64, debug)
runner: ubuntu-20.04
platform: android
target: editor
arch: arm64
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (arm32, release)
runner: ubuntu-20.04
platform: android
target: template_release
arch: arm32
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (arm32, debug)
runner: ubuntu-20.04
platform: android
target: editor
arch: arm32
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (x86_64, release)
runner: ubuntu-20.04
platform: android
target: template_release
arch: x86_64
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (x86_64, debug)
runner: ubuntu-20.04
platform: android
target: editor
arch: x86_64
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (x86_32, release)
runner: ubuntu-20.04
platform: android
target: template_release
arch: x86_32
should-build: ${{ !inputs.test-build }}
- name: 🤖 Android (x86_32, debug)
runner: ubuntu-20.04
platform: android
target: editor
arch: x86_32
should-build: ${{ !inputs.test-build }}
- name: 🍏 iOS (arm64, release)
runner: macos-latest
platform: ios
target: template_release
arch: arm64
should-build: ${{ !inputs.test-build }}
- name: 🍏 iOS (arm64, debug)
runner: macos-latest
platform: ios
target: editor
arch: arm64
should-build: ${{ !inputs.test-build }}
- name: 🍏 iOS (simulator, release)
runner: macos-latest
platform: ios
target: template_release
arch: universal
scons-flags: ios_simulator=yes
should-build: ${{ !inputs.test-build }}
- name: 🍏 iOS (simulator, debug)
runner: macos-latest
platform: ios
target: editor
arch: universal
scons-flags: ios_simulator=yes
should-build: ${{ !inputs.test-build }}
exclude:
- { opts: {should-build: false }}
- { opts: { should-build: false } }
env:
BIN: liblimboai.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
steps:
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
fetch-tags: true
ref: ${{ inputs.limboai-ref }}
- name: Clone godot-cpp
uses: actions/checkout@v4
with:
repository: godotengine/godot-cpp
fetch-tags: true
path: godot-cpp
ref: ${{ inputs.godot-cpp-treeish }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: limboai
fetch-tags: true
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.godot-cpp-ref }}
# Inits GDEXTENSION_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./limboai/.github/actions/init-version-gdext
- uses: ./.github/actions/init-version-gdext
- name: Set up Linux buildroot x86_64
if: matrix.opts.platform == 'linux' && matrix.opts.arch == 'x86_64'
run: |
wget https://download.tuxfamily.org/godotengine/toolchains/linux/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
tar -xjf x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
mv x86_64-godot-linux-gnu_sdk-buildroot buildroot
cd buildroot
./relocate-sdk.sh
cd ..
- name: Output NAME_PREFIX
id: output-name-prefix
run: echo "name-prefix=${NAME_PREFIX}" >> $GITHUB_OUTPUT
- name: Set up Linux buildroot x86_32
if: matrix.opts.platform == 'linux' && matrix.opts.arch == 'x86_32'
run: |
wget https://download.tuxfamily.org/godotengine/toolchains/linux/i686-godot-linux-gnu_sdk-buildroot.tar.bz2
tar -xjf i686-godot-linux-gnu_sdk-buildroot.tar.bz2
mv i686-godot-linux-gnu_sdk-buildroot buildroot
cd buildroot
./relocate-sdk.sh
cd ..
- name: Setup Linux toolchain
if: matrix.opts.platform == 'linux'
uses: ./.github/actions/setup-linux-toolchain
with:
arch: ${{matrix.opts.arch}}
- name: Set up Python 3.x
if: matrix.opts.platform == 'windows' || matrix.opts.platform == 'macos'
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'
architecture: 'x64'
python-version: "3.x"
architecture: "x64"
- name: Set up Emscripten cache
if: matrix.opts.platform == 'web'
uses: actions/cache@v4
with:
path: ${{env.EM_CACHE_FOLDER}}
key: ${{env.EM_VERSION}}-${{runner.os}}-libs
- name: Set up Emscripten
if: matrix.opts.platform == 'web'
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- name: Verify Emscripten setup
if: matrix.opts.platform == 'web'
run: |
emcc -v
- name: Set up scons
if: matrix.opts.platform == 'windows' || matrix.opts.platform == 'macos'
if: matrix.opts.platform != 'linux'
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons==4.4.0
python --version
scons --version
- name: Set up Java 17
if: matrix.opts.platform == 'android'
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- uses: nttld/setup-ndk@v1
if: matrix.opts.platform == 'android'
id: setup-ndk
with:
ndk-version: r23c
link-to-sdk: true
- name: Set up MSVC problem matcher on Windows
if: matrix.opts.platform == 'windows'
uses: ammaraskar/msvc-problem-matcher@master
- name: Set up scons cache
uses: actions/cache@v3
if: inputs.test-build # ! Only cache test/PR builds
uses: actions/cache@v4
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-cpp-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
key: ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-cpp-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-cpp-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-cpp-treeish}}
- name: Setup project structure for GDExtension
shell: bash
run: |
python ./limboai/gdextension/update_icons.py
mkdir -p demo/addons/limboai/bin
mv limboai/icons demo/addons/limboai/
cp limboai/gdextension/SConstruct SConstruct
cp limboai/gdextension/limboai.gdextension demo/addons/limboai/bin
echo "---"
ls -l
ls -l -R ./demo/
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}
- name: Compilation
shell: bash
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
DEBUG_FLAGS: ${{ inputs.debug-symbols && 'debug_symbols=yes symbols_visibility=visible' || 'debug_symbols=no' }}
run: |
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.SCONSFLAGS}}
scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.DEBUG_FLAGS}} ${{matrix.opts.scons-flags}} ${{env.SCONSFLAGS}}
- name: Prepare artifact
shell: bash
run: |
ls -R demo/addons/limboai/
mkdir out
mv demo/addons/ out/
cp {README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/
cp -R demo/demo/ out/demo/
cp demo/LICENSE_ASSETS.md out/demo/
rm -f out/addons/limboai/bin/*.{exp,lib,pdb}
echo "${LIMBOAI_VERSION}" > out/addons/limboai/version.txt
echo "---"
ls -R out/
- name: Strip lib
if: matrix.opts.platform != 'windows'
run: |
ls -l -R out/addons/limboai/bin/
echo "---"
if [ "$RUNNER_OS" == "macOS" ]; then
strip -u out/addons/limboai/bin/liblimboai*/liblimboai*
else
strip out/addons/limboai/bin/liblimboai*
fi
echo "---"
ls -l -R out/addons/limboai/bin/
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
NAME: ${{env.NAME_PREFIX}}
NAME: tmp-gdextension.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
with:
name: ${{ env.NAME }}
path: out/*
package-extension:
name: 📦 Package extension
runs-on: ubuntu-latest
needs: gdextension
steps:
- name: Merge artifacts
uses: actions/upload-artifact/merge@v4
with:
name: ${{needs.gdextension.outputs.name-prefix}}
pattern: tmp-gdextension.*
delete-merged: true
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: ${{needs.gdextension.outputs.name-prefix}}
path: out/
- name: Setup Godot
shell: bash
run: |
echo "Downloading Godot ${GODOT_VERSION}"
mkdir bin
cd bin
wget "https://github.com/${GODOT_REPO}/releases/download/${GODOT_VERSION}/Godot_v${GODOT_VERSION}_linux.x86_64.zip" -O godot.zip
unzip godot.zip
rm godot.zip
mv Godot_* godot
chmod u+x godot
ls -l
cd ..
./bin/godot --version
- name: Generate icon .import files
shell: bash
run: |
touch out/project.godot
timeout 20s ./bin/godot --headless --editor --path ./out/ || /bin/true
rm out/project.godot
rm -rf out/.godot/
- name: Change editor icon import settings
shell: bash
run: |
echo "--- Listing icons dir:"
ls out/addons/limboai/icons/
echo "--- (end of listing)"
sed -i 's|editor/scale_with_editor_scale=false|editor/scale_with_editor_scale=true|' out/addons/limboai/icons/*.import
sed -i 's|editor/convert_colors_with_editor_theme=false|editor/convert_colors_with_editor_theme=true|' out/addons/limboai/icons/*.import
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{needs.gdextension.outputs.name-prefix}}
path: out/*
overwrite: true

View File

@ -2,36 +2,34 @@ name: 🍏 iOS builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
# Global Settings
env:
SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
ios-builds:
runs-on: "macos-latest"
name: ${{ matrix.name }}
@ -44,21 +42,25 @@ jobs:
target: template_release
arch: arm64
ios_simulator: false
dotnet: false
- name: Template (arm64, debug)
target: template_debug
arch: arm64
ios_simulator: false
dotnet: false
- name: Simulator Lib (x86_64, release)
- name: Simulator (x86_64, release)
target: template_release
arch: x86_64
ios_simulator: true
dotnet: false
- name: Simulator Lib (x86_64, debug)
- name: Simulator (x86_64, debug)
target: template_debug
arch: x86_64
ios_simulator: true
dotnet: false
# ! Disabled for now as it doesn't work with cctools-port and current LLVM.
# * See https://github.com/godotengine/build-containers/pull/85.
@ -72,31 +74,54 @@ jobs:
# arch: arm64
# ios_simulator: true
- name: Template .NET (arm64, release)
target: template_release
arch: arm64
ios_simulator: false
dotnet: true
- name: Template .NET (arm64, debug)
target: template_debug
arch: arm64
ios_simulator: false
dotnet: true
- name: Simulator .NET (x86_64, release)
target: template_release
arch: x86_64
ios_simulator: true
dotnet: true
- name: Simulator .NET (x86_64, debug)
target: template_debug
arch: x86_64
ios_simulator: true
dotnet: true
env:
BIN: godot.ios.${{matrix.target}}.${{matrix.arch}}
BIN: godot.ios.${{matrix.target}}.${{matrix.arch}}${{ matrix.dotnet == true && '.mono' || '' }}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Set up Python 3.x
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'
architecture: 'x64'
python-version: "3.x"
architecture: "x64"
- name: Set up scons
run: |
@ -111,60 +136,84 @@ jobs:
- name: Set up Vulkan SDK
run: |
sh misc/scripts/install_vulkan_sdk_macos.sh
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
#sh misc/scripts/install_vulkan_sdk_macos.sh
- name: Set up scons cache
uses: actions/cache@v3
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-treeish}}
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
unzip /tmp/vulkan-sdk.zip -d /tmp
/tmp/InstallVulkan.app/Contents/MacOS/InstallVulkan --accept-licenses --default-answer --confirm-command install
rm -Rf /tmp/InstallVulkan.app
rm -f /tmp/vulkan-sdk.zip
# ! Note: we stopped using the scons cache in release builds.
# - name: Set up scons cache
# uses: actions/cache@v4
# with:
# path: ${{github.workspace}}/.scons_cache/
# key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# restore-keys: |
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
# ${{env.BIN}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
scons platform=ios target=${{matrix.target}} arch=${{matrix.arch}} ios_simulator=${{matrix.ios_simulator}} ${{env.SCONSFLAGS}}
scons platform=ios target=${{matrix.target}} arch=${{matrix.arch}} ios_simulator=${{matrix.ios_simulator}} module_mono_enabled=${{matrix.dotnet}} ${{env.SCONSFLAGS}}
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ios-templates
name: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-${{strategy.job-index}}
path: bin/*
package-ios-templates:
runs-on: "macos-latest"
name: Package iOS templates
name: ${{ matrix.name }}
needs: ios-builds
steps:
strategy:
fail-fast: false
matrix:
include:
- name: Package iOS templates
dotnet: false
- name: Package iOS .NET templates
dotnet: true
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Set up Vulkan SDK
run: |
sh misc/scripts/install_vulkan_sdk_macos.sh
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
#sh misc/scripts/install_vulkan_sdk_macos.sh
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
unzip /tmp/vulkan-sdk.zip -d /tmp
/tmp/InstallVulkan.app/Contents/MacOS/InstallVulkan --accept-licenses --default-answer --confirm-command install
rm -Rf /tmp/InstallVulkan.app
rm -f /tmp/vulkan-sdk.zip
- name: Download templates artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ios-templates
pattern: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
merge-multiple: true
path: bin/
- name: Make template bundle
@ -173,8 +222,6 @@ jobs:
cp -r misc/dist/ios_xcode bin/
cd bin/
strip *.a
mv libgodot.ios.template_debug.arm64.a ios_xcode/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a
# ! lipo -create libgodot.ios.template_debug.arm64.simulator.a libgodot.ios.template_debug.x86_64.simulator.a -output ios_xcode/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a
mv libgodot.ios.template_debug.x86_64.simulator.a ios_xcode/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a
@ -183,25 +230,26 @@ jobs:
# ! lipo -create libgodot.ios.template_release.arm64.simulator.a libgodot.ios.template_release.x86_64.simulator.a -output ios_xcode/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a
mv libgodot.ios.template_release.x86_64.simulator.a ios_xcode/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a
cp -r ~/VulkanSDK/*/MoltenVK/MoltenVK.xcframework ios_xcode
cp -r ~/VulkanSDK/*/macOS/lib/MoltenVK.xcframework ios_xcode
rm -rf ios_xcode/MoltenVK.xcframework/{macos,tvos}*
mkdir -p ${{github.workspace}}/out/templates/
cd ios_xcode
zip -q -9 -r ${{github.workspace}}/out/templates/ios.zip *
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > ${{github.workspace}}/out/templates/version.txt
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.dotnet == true && '.mono' || ''}}" > ${{github.workspace}}/out/templates/version.txt
ls -l ${{github.workspace}}/out/*
- name: Upload template bundle
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.export-templates
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.export-templates.ios
path: out/*
- name: Delete templates artifact
uses: geekyeggo/delete-artifact@v2
uses: geekyeggo/delete-artifact@v5
with:
name: ios-templates
failOnError: false
name: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
useGlob: true
failOnError: false

View File

@ -2,31 +2,31 @@ name: 🐧 Linux builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
@ -45,158 +45,216 @@ jobs:
fail-fast: false
matrix:
opts:
# * Standard x86_64
- name: Editor (x86_64, release)
target: editor
arch: x86_64
build-mono: false
dotnet: false
should-build: true
- name: Template (x86_64, release)
target: template_release
arch: x86_64
build-mono: false
dotnet: false
should-build: true
- name: Template (x86_64, debug)
target: template_debug
arch: x86_64
build-mono: false
dotnet: false
should-build: ${{ !inputs.test-build }}
# * Standard x86_32
# - name: Editor (x86_32, release)
# target: editor
# arch: x86_32
# build-mono: false
# dotnet: false
# should-build: ${{ !inputs.test-build }}
- name: Template (x86_32, release)
target: template_release
arch: x86_32
build-mono: false
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (x86_32, debug)
target: template_debug
arch: x86_32
build-mono: false
dotnet: false
should-build: ${{ !inputs.test-build }}
# * Standard arm64
- name: Editor (arm64, release)
target: editor
arch: arm64
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (arm64, release)
target: template_release
arch: arm64
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (arm64, debug)
target: template_debug
arch: arm64
dotnet: false
should-build: ${{ !inputs.test-build }}
# * Standard arm32
- name: Template (arm32, release)
target: template_release
arch: arm32
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (arm32, debug)
target: template_debug
arch: arm32
dotnet: false
should-build: ${{ !inputs.test-build }}
# * .NET x86_64
- name: Editor .NET (x86_64, release)
target: editor
arch: x86_64
build-mono: true
should-build: ${{ !inputs.test-build }}
dotnet: true
should-build: true
- name: Template .NET (x86_64, release)
target: template_release
arch: x86_64
build-mono: true
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_64, debug)
target: template_debug
arch: x86_64
build-mono: true
dotnet: true
should-build: ${{ !inputs.test-build }}
# * .NET x86_32
# - name: Editor .NET (x86_32, release)
# target: editor
# arch: x86_32
# build-mono: true
# dotnet: true
# should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_32, release)
target: template_release
arch: x86_32
build-mono: true
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_32, debug)
target: template_debug
arch: x86_32
build-mono: true
dotnet: true
should-build: ${{ !inputs.test-build }}
# * .NET arm64
# ! FIXME: Needs a separate job for .NET glue generation since we can't execute arm64 binaries on x86_64.
# ! Alternatively, solution generation can be done as post-process job, taking the glue from x86_64, after all builds complete.
# - name: Editor .NET (arm64, release)
# target: editor
# arch: arm64
# dotnet: true
# should-build: ${{ !inputs.test-build }}
- name: Template .NET (arm64, release)
target: template_release
arch: arm64
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (arm64, debug)
target: template_debug
arch: arm64
dotnet: true
should-build: ${{ !inputs.test-build }}
# * .NET arm32
- name: Template .NET (arm32, release)
target: template_release
arch: arm32
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (arm32, debug)
target: template_debug
arch: arm32
dotnet: true
should-build: ${{ !inputs.test-build }}
exclude:
- { opts: {should-build: false }}
- { opts: { should-build: false } }
env:
BIN: godot.linuxbsd.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.build-mono == true && '.mono' || '' }}
BIN: godot.linuxbsd.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.dotnet == true && '.mono' || '' }}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
# About sed see: https://github.com/godotengine/buildroot/issues/6
- name: Set up buildroot x86_64
if: matrix.opts.arch == 'x86_64'
run: |
wget https://download.tuxfamily.org/godotengine/toolchains/linux/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
tar -xjf x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
mv x86_64-godot-linux-gnu_sdk-buildroot buildroot
cd buildroot
sed -i x86_64-godot-linux-gnu/sysroot/usr/lib/pkgconfig/dbus-1.pc -e "s@/lib@/lib64@g"
./relocate-sdk.sh
cd ..
- name: Set up Linux toolchain
uses: ./modules/limboai/.github/actions/setup-linux-toolchain
with:
arch: ${{matrix.opts.arch}}
- name: Set up buildroot x86_32
if: matrix.opts.arch == 'x86_32'
- name: Set up Wayland deps
run: |
wget https://download.tuxfamily.org/godotengine/toolchains/linux/i686-godot-linux-gnu_sdk-buildroot.tar.bz2
tar -xjf i686-godot-linux-gnu_sdk-buildroot.tar.bz2
mv i686-godot-linux-gnu_sdk-buildroot buildroot
cd buildroot
./relocate-sdk.sh
cd ..
sudo apt-get install libwayland-dev
- name: Set up scons cache
uses: actions/cache@v3
if: inputs.test-build # ! Only cache test/PR builds
uses: actions/cache@v4
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-treeish}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
scons platform=linuxbsd target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.build-mono}} ${{env.SCONSFLAGS}}
scons platform=linuxbsd target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.dotnet}} ${{env.SCONSFLAGS}}
- name: Generate C# glue
if: matrix.opts.build-mono && matrix.opts.target == 'editor'
env:
GODOT_VERSION_STATUS: limboai
run: |
./bin/$BIN --headless --generate-mono-glue ./modules/mono/glue || true
- name: Build .NET solutions
if: matrix.opts.build-mono && matrix.opts.target == 'editor'
env:
GODOT_VERSION_STATUS: limboai
run: |
./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd
- name: Build .NET assemblies
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
with:
platform: linuxbsd
bin: ${{env.BIN}}
- name: Prepare artifact
env:
OUTDIR: ${{ startsWith(matrix.opts.target, 'template') && 'out/templates' || 'out/' }}
run: |
strip ./bin/godot.*
chmod +x ./bin/godot.*
mkdir -p ${{env.OUTDIR}}
mv bin/* ${{env.OUTDIR}}
@ -211,6 +269,7 @@ jobs:
pushd out/
zip -r godot-limboai.editor.linux.zip *
rm godot.*
rm -rf GodotSharp/
echo -e "## Why another ZIP inside?\n\nWorkaround for: https://github.com/actions/upload-artifact/issues/38\n" > README.md
popd
@ -220,14 +279,11 @@ jobs:
BUILD_TYPE: ${{ endsWith(matrix.opts.target, 'release') && 'release' || 'debug' }}
run: |
mv out/templates/${BIN} out/templates/linux_${BUILD_TYPE}.${{matrix.opts.arch}}
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
ls -R out/
- name: Upload artifact
uses: actions/upload-artifact@v3
env:
NAME_EDITOR: ${{env.NAME_PREFIX}}.${{matrix.opts.target}}.linux.${{matrix.opts.arch}}${{ matrix.opts.build-mono == true && '.mono' || '' }}
NAME_TEMPLATES: ${{env.NAME_PREFIX}}.export-templates${{ matrix.opts.build-mono == true && '.mono' || '' }}
uses: actions/upload-artifact@v4
with:
name: ${{ startsWith(matrix.opts.target, 'template') && env.NAME_TEMPLATES || env.NAME_EDITOR }}
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.${{matrix.opts.target}}.linux.${{matrix.opts.arch}}
path: out/*

View File

@ -2,39 +2,38 @@ name: 🍎 macOS builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
# Global Settings
env:
SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
@ -50,125 +49,114 @@ jobs:
- name: Editor (x86_64, release)
target: editor
arch: x86_64
build-mono: false
artifact-name: macos-editor
dotnet: false
should-build: true
- name: Template (x86_64, release)
target: template_release
arch: x86_64
build-mono: false
artifact-name: macos-templates
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (x86_64, debug)
target: template_debug
arch: x86_64
build-mono: false
artifact-name: macos-templates
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Editor (arm64, release)
target: editor
arch: arm64
build-mono: false
artifact-name: macos-editor
dotnet: false
should-build: true
- name: Template (arm64, release)
target: template_release
arch: arm64
build-mono: false
artifact-name: macos-templates
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (arm64, debug)
target: template_debug
arch: arm64
build-mono: false
artifact-name: macos-templates
dotnet: false
should-build: ${{ !inputs.test-build }}
# ! Disabled for now: .NET version fails to build
- name: .NET Editor (x86_64, release)
target: editor
arch: x86_64
dotnet: true
should-build: ${{ !inputs.test-build }}
# - name: .NET Editor (x86_64, release)
# target: editor
# arch: x86_64
# build-mono: true
# artifact-name: macos-mono-editor
# cache-name: macos-editor
# should-build: ${{ !inputs.test-build }}
- name: .NET Template (x86_64, release)
target: template_release
arch: x86_64
dotnet: true
should-build: ${{ !inputs.test-build }}
# - name: .NET Template (x86_64, release)
# target: template_release
# arch: x86_64
# build-mono: true
# artifact-name: macos-mono-templates
# should-build: ${{ !inputs.test-build }}
- name: .NET Template (x86_64, debug)
target: template_debug
arch: x86_64
dotnet: true
should-build: ${{ !inputs.test-build }}
# - name: .NET Template (x86_64, debug)
# target: template_debug
# arch: x86_64
# build-mono: true
# artifact-name: macos-mono-templates
# should-build: ${{ !inputs.test-build }}
- name: .NET Editor (arm64, release)
target: editor
arch: arm64
dotnet: true
should-build: ${{ !inputs.test-build }}
# - name: .NET Editor (arm64, release)
# target: editor
# arch: arm64
# build-mono: true
# artifact-name: macos-mono-editor
# cache-name: macos-editor
# should-build: ${{ !inputs.test-build }}
- name: .NET Template (arm64, release)
target: template_release
arch: arm64
dotnet: true
should-build: ${{ !inputs.test-build }}
# - name: .NET Template (arm64, release)
# target: template_release
# arch: arm64
# build-mono: true
# artifact-name: macos-mono-templates
# should-build: ${{ !inputs.test-build }}
# - name: .NET Template (arm64, debug)
# target: template_debug
# arch: arm64
# build-mono: true
# artifact-name: macos-mono-templates
# should-build: ${{ !inputs.test-build }}
- name: .NET Template (arm64, debug)
target: template_debug
arch: arm64
dotnet: true
should-build: ${{ !inputs.test-build }}
exclude:
- { opts: {should-build: false }}
- { opts: { should-build: false } }
env:
BIN: godot.macos.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.build-mono == true && '.mono' || '' }}
BIN: godot.macos.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.dotnet == true && '.mono' || '' }}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Set up Python 3.x
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'
architecture: 'x64'
python-version: "3.x"
architecture: "x64"
- name: Set up scons
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons==4.4.0
- name: Set up .NET SDK 6.0
if: matrix.opts.dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: "6.0.x"
- name: Diagnostics
run: |
python --version
@ -177,45 +165,49 @@ jobs:
- name: Set up Vulkan SDK
run: |
sh misc/scripts/install_vulkan_sdk_macos.sh
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
#sh misc/scripts/install_vulkan_sdk_macos.sh
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/config.json" -o /tmp/vulkan-sdk.json
sdk_version=`jq -r '.version' /tmp/vulkan-sdk.json`
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
unzip /tmp/vulkan-sdk.zip -d /tmp
/tmp/InstallVulkan-${sdk_version}.app/Contents/MacOS/InstallVulkan-${sdk_version} --accept-licenses --default-answer --confirm-command install
rm -Rf /tmp/InstallVulkan-${sdk_version}.app
rm -f /tmp/vulkan-sdk.zip
- name: Set up scons cache
uses: actions/cache@v3
if: inputs.test-build # ! Only cache test/PR builds
uses: actions/cache@v4
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-treeish}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
scons -j2 platform=macos target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.build-mono}} ${{env.SCONSFLAGS}}
scons -j2 platform=macos target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.dotnet}} ${{env.SCONSFLAGS}}
# ! Disabled for now: .NET version fail to build
# - name: Generate C# glue
# if: matrix.opts.build-mono && matrix.opts.target == 'editor'
# run: |
# ./bin/$BIN --headless --generate-mono-glue ./modules/mono/glue || true
# - name: Build .NET solutions
# if: matrix.opts.build-mono && matrix.opts.target == 'editor'
# run: |
# ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=macos
- name: Build .NET assemblies
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
with:
platform: macos
bin: ${{env.BIN}}
- name: Prepare artifact
run: |
strip bin/godot.*
chmod +x bin/godot.*
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.opts.artifact-name }}
name: tmp-${{matrix.opts.dotnet == true && 'dotnet-' || ''}}macos-${{matrix.opts.target}}-${{matrix.opts.arch}}
path: bin/*
make-macos-bundle:
@ -223,60 +215,76 @@ jobs:
name: Make macOS Bundles
needs: macos-builds
steps:
strategy:
fail-fast: false
matrix:
opts:
- download-prefix: tmp-macos
dotnet: false
should-build: true
- download-prefix: tmp-dotnet-macos
dotnet: true
should-build: ${{ !inputs.test-build }}
exclude:
- { opts: { should-build: false } }
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Download editor artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: macos-editor
pattern: ${{matrix.opts.download-prefix}}-editor-*
merge-multiple: true
path: bin/
# Zipping the editor bundle to retain executable bit;
# workaround for: https://github.com/actions/upload-artifact/issues/38
- name: Make editor bundle
env:
APP_NAME: Godot${{matrix.opts.dotnet == true && '_mono' || ''}}.app
run: |
ls bin/
lipo -create bin/godot.macos.editor.x86_64 bin/godot.macos.editor.arm64 -output bin/godot.macos.editor.universal
strip bin/godot.macos.editor.universal
rm bin/godot.macos.editor.{x86_64,arm64}
lipo -create bin/godot.macos.editor.x86_64* bin/godot.macos.editor.arm64* -output bin/godot.macos.editor.universal
mkdir -p out/editor/
cp -r misc/dist/macos_tools.app out/editor/Godot.app
mkdir -p out/editor/Godot.app/Contents/MacOS
cp bin/godot.macos.editor.universal out/editor/Godot.app/Contents/MacOS/Godot
chmod +x out/editor/Godot.app/Contents/MacOS/Godot
cp -r misc/dist/macos_tools.app out/editor/${APP_NAME}
mkdir -p out/editor/${APP_NAME}/Contents/{MacOS,Resources}
cp bin/godot.macos.editor.universal out/editor/${APP_NAME}/Contents/MacOS/Godot
chmod +x out/editor/${APP_NAME}/Contents/MacOS/Godot
cp -r bin/GodotSharp out/editor/${APP_NAME}/Contents/Resources/GodotSharp || true
pushd out/editor
zip -r Godot.app.zip Godot.app
rm -rf Godot.app
zip -q -9 -r ${APP_NAME}.zip ${APP_NAME}
rm -rf ${APP_NAME}
echo -e "## Why another ZIP inside?\n\nWorkaround for: https://github.com/actions/upload-artifact/issues/38\n" > README.md
popd
rm -rf bin/*
ls out/editor/
- name: Upload editor bundle
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.editor.macos.universal
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.editor.macos.universal
path: out/editor/*
- name: Download templates artifact
if: ${{ !inputs.test-build }}
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: macos-templates
pattern: ${{matrix.opts.download-prefix}}-template_*
merge-multiple: true
path: bin/
- name: Make templates bundle
@ -284,31 +292,29 @@ jobs:
run: |
rm -rf out/
ls bin/
lipo -create bin/godot.macos.template_release.x86_64 bin/godot.macos.template_release.arm64 -output bin/godot.macos.template_release.universal
lipo -create bin/godot.macos.template_debug.x86_64 bin/godot.macos.template_debug.arm64 -output bin/godot.macos.template_debug.universal
rm bin/godot.macos.template_{debug,release}.{x86_64,arm64}
strip bin/godot.*
lipo -create bin/godot.macos.template_release.x86_64* bin/godot.macos.template_release.arm64* -output bin/godot.macos.template_release.universal
lipo -create bin/godot.macos.template_debug.x86_64* bin/godot.macos.template_debug.arm64* -output bin/godot.macos.template_debug.universal
cp -r misc/dist/macos_template.app macos_template.app
mkdir -p macos_template.app/Contents/MacOS
cp bin/godot.macos.template_debug.universal macos_template.app/Contents/MacOS/godot_macos_debug.universal
cp bin/godot.macos.template_release.universal macos_template.app/Contents/MacOS/godot_macos_release.universal
chmod +x macos_template.app/Contents/MacOS/godot_macos_{release,debug}.universal
zip -r macos.zip macos_template.app
rm bin/*
zip -q -9 -r macos.zip macos_template.app
mkdir -p out/templates/
mv macos.zip out/templates/macos.zip
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
rm -rf bin/*
ls out/templates/
- uses: geekyeggo/delete-artifact@v2
- uses: geekyeggo/delete-artifact@v5
with:
name: macos-*
useGlob: true
failOnError: false
name: ${{matrix.opts.download-prefix}}-*
useGlob: true
failOnError: false
- name: Upload templates bundle
if: ${{ !inputs.test-build }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.export-templates
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.export-templates.macos
path: out/*

52
.github/workflows/merge_templates.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: 📦️ Merge templates
on:
workflow_call:
inputs:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
workflow_dispatch:
inputs:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
jobs:
merge-templates:
runs-on: ubuntu-latest
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Merge classical templates
uses: actions/upload-artifact/merge@v4
with:
name: ${{env.NAME_PREFIX}}.export-templates
pattern: ${{env.NAME_PREFIX}}.{export-templates,template_}*
delete-merged: true
- name: Merge .NET templates
uses: actions/upload-artifact/merge@v4
with:
name: ${{env.NAME_PREFIX}}.dotnet.export-templates
pattern: ${{env.NAME_PREFIX}}.dotnet.{export-templates,template_}*
delete-merged: true

View File

@ -3,22 +3,22 @@ on:
workflow_dispatch:
push:
branches: [ master ]
branches: [master]
paths-ignore:
- "README.md"
- "LICENSE"
- "LICENSE.md"
- "**/*.png"
- "demo/*"
- "doc/*"
- "demo/**"
- "doc/**"
pull_request:
branches: [ master ]
branches: [master]
paths-ignore:
- "README.md"
- "LICENSE"
- "LICENSE.md"
- "**/*.png"
- "demo/*"
- "doc/*"
- "demo/**"
- "doc/**"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -26,8 +26,8 @@ concurrency:
# Global Settings.
env:
GODOT_REF: "4.2.1-stable"
GODOT_CPP_REF: "4.2"
GODOT_REF: "master"
GODOT_CPP_REF: "master"
jobs:
unit-tests:
@ -36,7 +36,7 @@ jobs:
# Settings
env:
SCONSFLAGS: platform=linuxbsd target=editor arch=x86_64 production=false dev_build=true tests=true verbose=yes warnings=extra werror=yes
SCONSFLAGS: platform=linuxbsd target=editor arch=x86_64 production=false dev_build=true tests=true verbose=yes warnings=extra werror=yes strict_checks=yes
SCONS_CACHE_LIMIT: 7168
BIN: godot.linuxbsd.editor.dev.x86_64
@ -52,19 +52,13 @@ jobs:
with:
path: modules/limboai
# About sed see: https://github.com/godotengine/buildroot/issues/6
- name: Set up buildroot x86_64
run: |
wget https://download.tuxfamily.org/godotengine/toolchains/linux/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
tar -xjf x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
mv x86_64-godot-linux-gnu_sdk-buildroot buildroot
cd buildroot
sed -i x86_64-godot-linux-gnu/sysroot/usr/lib/pkgconfig/dbus-1.pc -e "s@/lib@/lib64@g"
./relocate-sdk.sh
cd ..
- name: Set up Linux toolchain
uses: ./modules/limboai/.github/actions/setup-linux-toolchain
with:
arch: x86_64
- name: Set up scons cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}-${{github.sha}}
@ -75,10 +69,10 @@ jobs:
continue-on-error: true
- name: Set up Python 3.x
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'
architecture: 'x64'
python-version: "3.x"
architecture: "x64"
- name: Set up scons
run: |
@ -107,6 +101,18 @@ jobs:
run: |
bin/${{ env.BIN }} --test --headless
static-checks:
name: ⚙️ Static checks
runs-on: ubuntu-20.04
steps:
- name: Clone LimboAI module
uses: actions/checkout@v4
- name: Code style checks
uses: pre-commit/action@v3.0.1
with:
extra_args: --all-files
cache-env:
runs-on: ubuntu-latest
outputs:
@ -124,8 +130,8 @@ jobs:
needs: cache-env
uses: ./.github/workflows/linux.yml
with:
godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }}
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
limboai-ref: ${{ github.sha }}
test-build: true
windows-test-build:
@ -133,8 +139,8 @@ jobs:
needs: cache-env
uses: ./.github/workflows/windows.yml
with:
godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }}
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
limboai-ref: ${{ github.sha }}
test-build: true
macos-test-build:
@ -142,8 +148,8 @@ jobs:
needs: cache-env
uses: ./.github/workflows/macos.yml
with:
godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }}
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
limboai-ref: ${{ github.sha }}
test-build: true
gdextension:
@ -151,6 +157,6 @@ jobs:
needs: cache-env
uses: ./.github/workflows/gdextension.yml
with:
godot-cpp-treeish: ${{ needs.cache-env.outputs.godot-cpp-ref }}
limboai-treeish: ${{ github.sha }}
godot-cpp-ref: ${{ needs.cache-env.outputs.godot-cpp-ref }}
limboai-ref: ${{ github.sha }}
test-build: true

View File

@ -2,22 +2,22 @@ name: 🌐 Web builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
@ -31,68 +31,80 @@ env:
EM_CACHE_FOLDER: "emsdk-cache"
jobs:
# Workaround for issue: https://github.com/mymindstorm/setup-emsdk/issues/20
init-emscripten:
name: Init Emscripten
runs-on: "ubuntu-20.04"
steps:
- name: Set up Emscripten
uses: mymindstorm/setup-emsdk@v12
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
web-builds:
runs-on: "ubuntu-20.04"
name: ${{ matrix.name }}
needs: init-emscripten
strategy:
fail-fast: false
matrix:
include:
- name: Template (release)
target: template_release
dlink_enabled: false
threads: true
dlink: false
- name: Template (release, dlink_enabled=true)
- name: Template (release, dlink)
target: template_release
dlink_enabled: true
threads: true
dlink: true
- name: Template (debug)
target: template_debug
dlink_enabled: false
threads: true
dlink: false
- name: Template (debug, dlink_enabled=true)
- name: Template (debug, dlink)
target: template_debug
dlink_enabled: true
threads: true
dlink: true
- name: Template (release, nothreads)
target: template_release
threads: false
dlink: false
- name: Template (release, nothreads, dlink)
target: template_release
threads: false
dlink: true
- name: Template (debug, nothreads)
target: template_debug
threads: false
dlink: false
- name: Template (debug, nothreads, dlink)
target: template_debug
threads: false
dlink: true
env:
CACHE_NAME: godot.web.${{matrix.target}}${{ matrix.dlink_enabled == true && '.dlink' || '' }}
CACHE_NAME: godot.web.${{matrix.target}}${{ matrix.dlink == true && '.dlink' || '' }}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
# - name: Set up Emscripten cache
# uses: actions/cache@v3
# with:
# path: ${{env.EM_CACHE_FOLDER}}
# key: ${{env.EM_VERSION}}-${{runner.os}}-libs
- name: Set up Emscripten cache
uses: actions/cache@v4
with:
path: ${{env.EM_CACHE_FOLDER}}
key: ${{env.EM_VERSION}}-${{runner.os}}-libs
- name: Set up Emscripten
uses: mymindstorm/setup-emsdk@v12
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
@ -108,34 +120,39 @@ jobs:
python --version
scons --version
- name: Set up scons cache
uses: actions/cache@v3
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.CACHE_NAME}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.CACHE_NAME}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.CACHE_NAME}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.CACHE_NAME}}-${{inputs.godot-treeish}}
# ! Note: we stopped using the scons cache in release builds.
# - name: Set up scons cache
# uses: actions/cache@v4
# with:
# path: ${{github.workspace}}/.scons_cache/
# key: ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# restore-keys: |
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
scons platform=web target=${{matrix.target}} dlink_enabled=${{matrix.dlink_enabled}} ${{env.SCONSFLAGS}}
scons platform=web target=${{matrix.target}} threads=${{matrix.threads}} dlink_enabled=${{matrix.dlink}} ${{env.SCONSFLAGS}}
- name: Prepare artifacts
run: |
mkdir -p out/templates/
mv bin/godot.web.template_release.wasm32.zip out/templates/web_release.zip || true
mv bin/godot.web.template_release.wasm32.dlink.zip out/templates/web_dlink_release.zip || true
mv bin/godot.web.template_debug.wasm32.zip out/templates/web_debug.zip || true
mv bin/godot.web.template_debug.wasm32.nothreads.zip out/templates/web_nothreads_debug.zip || true
mv bin/godot.web.template_debug.wasm32.dlink.zip out/templates/web_dlink_debug.zip || true
mv bin/godot.web.template_debug.wasm32.nothreads.dlink.zip out/templates/web_dlink_nothreads_debug.zip || true
mv bin/godot.web.template_release.wasm32.zip out/templates/web_release.zip || true
mv bin/godot.web.template_release.wasm32.nothreads.zip out/templates/web_nothreads_release.zip || true
mv bin/godot.web.template_release.wasm32.dlink.zip out/templates/web_dlink_release.zip || true
mv bin/godot.web.template_release.wasm32.nothreads.dlink.zip out/templates/web_dlink_nothreads_release.zip || true
rm -rf bin/
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{env.NAME_PREFIX}}.export-templates
name: ${{env.NAME_PREFIX}}.${{matrix.target}}.web${{matrix.threads == false && '.nothreads' || ''}}${{matrix.dlink == true && '.dlink' || ''}}
path: out/*

View File

@ -2,189 +2,274 @@ name: 🪟 Windows builds
on:
workflow_call:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
workflow_dispatch:
inputs:
godot-treeish:
godot-ref:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: master
limboai-treeish:
limboai-ref:
description: A tag, branch or commit hash in the LimboAI repository.
type: string
default: master
test-build:
description: Should we perform only a limited number of test builds?
description: Limit to pre-defined test builds
type: boolean
default: false
# Global Settings
env:
SCONS_CACHE_MSVC_CONFIG: true
BUILD_IMAGE_VERSION: 4.3-f40
MESA_VERSION: 23.1.9-1
SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
SCONSFLAGS: production=yes use_mingw=yes verbose=yes warnings=no progress=no d3d12=yes
jobs:
windows-builds:
runs-on: "windows-latest"
runs-on: "ubuntu-24.04"
name: ${{ matrix.opts.name }}
outputs:
built-dotnet-editor: ${{ steps.mark-dotnet-editor.outputs.built-dotnet-editor }}
strategy:
fail-fast: false
matrix:
opts:
# * Standard x86_64
- name: Editor (x86_64, release)
target: editor
arch: x86_64
build-mono: false
llvm: false
dotnet: false
should-build: true
- name: Template (x86_64, release)
target: template_release
arch: x86_64
build-mono: false
llvm: false
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (x86_64, debug)
target: template_debug
arch: x86_64
build-mono: false
llvm: false
dotnet: false
should-build: ${{ !inputs.test-build }}
# * Standard x86_32
# - name: Editor (x86_32, release)
# target: editor
# arch: x86_32
# build-mono: false
# llvm: false
# dotnet: false
# should-build: ${{ !inputs.test-build }}
- name: Template (x86_32, release)
target: template_release
arch: x86_32
build-mono: false
llvm: false
dotnet: false
should-build: ${{ !inputs.test-build }}
- name: Template (x86_32, debug)
target: template_debug
arch: x86_32
build-mono: false
llvm: false
dotnet: false
should-build: ${{ !inputs.test-build }}
# * Standard arm64
# - name: Editor (arm64, release)
# target: editor
# arch: arm64
# llvm: true
# dotnet: false
# should-build: ${{ !inputs.test-build }}
- name: Template (arm64, release)
target: template_release
arch: arm64
llvm: true
dotnet: false
scons-flags: mingw_prefix=/root/llvm-mingw
should-build: ${{ !inputs.test-build }}
- name: Template (arm64, debug)
target: template_debug
arch: arm64
llvm: true
dotnet: false
scons-flags: mingw_prefix=/root/llvm-mingw
should-build: ${{ !inputs.test-build }}
# * .NET x86_64
- name: Editor .NET (x86_64, release)
target: editor
arch: x86_64
build-mono: true
should-build: true
llvm: false
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_64, release)
target: template_release
arch: x86_64
build-mono: true
llvm: false
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_64, debug)
target: template_debug
arch: x86_64
build-mono: true
llvm: false
dotnet: true
should-build: ${{ !inputs.test-build }}
# * .NET x86_32
# - name: Editor .NET (x86_32, release)
# target: editor
# arch: x86_32
# build-mono: true
# llvm: false
# dotnet: true
# should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_32, release)
target: template_release
arch: x86_32
build-mono: true
llvm: false
dotnet: true
should-build: ${{ !inputs.test-build }}
- name: Template .NET (x86_32, debug)
target: template_debug
arch: x86_32
build-mono: true
llvm: false
dotnet: true
should-build: ${{ !inputs.test-build }}
# * .NET arm64
# - name: Editor .NET (arm64, release)
# target: editor
# arch: arm64
# llvm: true
# dotnet: true
# should-build: ${{ !inputs.test-build }}
- name: Template .NET (arm64, release)
target: template_release
arch: arm64
llvm: true
dotnet: true
scons-flags: mingw_prefix=/root/llvm-mingw
should-build: ${{ !inputs.test-build }}
- name: Template .NET (arm64, debug)
target: template_debug
arch: arm64
llvm: true
dotnet: true
scons-flags: mingw_prefix=/root/llvm-mingw
should-build: ${{ !inputs.test-build }}
exclude:
- { opts: {should-build: false }}
- { opts: { should-build: false } }
env:
BIN: godot.windows.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.build-mono == true && '.mono' || '' }}
BIN: godot.windows.${{matrix.opts.target}}.${{matrix.opts.arch}}${{matrix.opts.llvm && '.llvm' || ''}}${{matrix.opts.dotnet == true && '.mono' || ''}}
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-treeish }}
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-treeish }}
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
# Inits GODOT_VERSION, LIMBOAI_VERSION, NAME_PREFIX, GODOT_VERSION_STATUS, BUILD_NAME environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Set up Python 3.x
uses: actions/setup-python@v4
with:
python-version: '3.x'
architecture: 'x64'
- name: Set up scons
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons==4.4.0
python --version
scons --version
- name: Set up MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
- name: Set up scons cache
uses: actions/cache@v3
if: inputs.test-build # ! Only cache test/PR builds
uses: actions/cache@v4
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{inputs.limboai-treeish}}
${{env.BIN}}-${{inputs.godot-treeish}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.godot-ref}}
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
- name: Static ANGLE libs
run: |
scons -j2 platform=windows target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.build-mono}} ${{env.SCONSFLAGS}}
mkdir -p deps/angle
cd deps/angle
url=https://github.com/godotengine/godot-angle-static/releases/download/chromium%2F6601.2/godot-angle-static
curl -L -o windows_${{matrix.opts.arch}}.zip $url-${{matrix.opts.arch}}-${{matrix.opts.llvm && 'llvm' || 'gcc'}}-release.zip
unzip windows_${{matrix.opts.arch}}.zip
rm windows_${{matrix.opts.arch}}.zip
- name: Generate C# glue
if: matrix.opts.build-mono && matrix.opts.target == 'editor'
env:
GODOT_VERSION_STATUS: limboai
- name: Mesa libs
run: |
./bin/${{ env.BIN }} --headless --generate-mono-glue ./modules/mono/glue || true
mkdir -p deps/mesa
cd deps/mesa
curl -L -o mesa_${{matrix.opts.arch}}.zip https://github.com/godotengine/godot-nir-static/releases/download/${{env.MESA_VERSION}}/godot-nir-static-${{matrix.opts.arch}}-${{matrix.opts.llvm && 'llvm' || 'gcc'}}-release.zip
unzip -o mesa_${{matrix.opts.arch}}.zip
rm -f mesa_${{matrix.opts.arch}}.zip
- name: Build .NET solutions
if: matrix.opts.build-mono && matrix.opts.target == 'editor'
env:
GODOT_VERSION_STATUS: limboai
- name: Pull build container
run: |
python ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=windows
podman pull ghcr.io/limbonaut/godot-windows:${{env.BUILD_IMAGE_VERSION}}
- name: Build using container
shell: bash
run: |
scons_command="scons \
platform=windows \
target=${{matrix.opts.target}} \
arch=${{matrix.opts.arch}} \
use_llvm=${{matrix.opts.llvm}} \
module_mono_enabled=${{matrix.opts.dotnet}} \
${{env.SCONSFLAGS}} \
${{matrix.opts.scons-flags}} \
angle_libs=/build/deps/angle \
mesa_libs=/build/deps/mesa \
"
podman_run="podman run -it --rm \
--env GODOT_VERSION_STATUS=${GODOT_VERSION_STATUS} \
--env BUILD_NAME=${BUILD_NAME} \
--env NUM_CORES=$(nproc --all) \
--env DOTNET_NOLOGO=true \
--env DOTNET_CLI_TELEMETRY_OPTOUT=true \
--env SCONS_CACHE=/build/.scons_cache/ \
--env SCONS_CACHE_LIMIT=${SCONS_CACHE_LIMIT} \
-v ${GITHUB_WORKSPACE}/:/build/ \
-w /build godot-windows:${{env.BUILD_IMAGE_VERSION}} bash -c \
"
echo "Running ${podman_run} \"${scons_command}\""
${podman_run} "${scons_command}"
- name: Prepare artifact
shell: bash
@ -204,14 +289,70 @@ jobs:
run: |
mv out/templates/${BIN}.exe out/templates/windows_${BUILD_TYPE}_${{matrix.opts.arch}}.exe
mv out/templates/${BIN}.console.exe out/templates/windows_${BUILD_TYPE}_${{matrix.opts.arch}}_console.exe
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
ls -R out/
- name: Upload artifact
uses: actions/upload-artifact@v3
env:
NAME_EDITOR: ${{env.NAME_PREFIX}}.${{matrix.opts.target}}.windows.${{matrix.opts.arch}}${{ matrix.opts.build-mono == true && '.mono' || '' }}
NAME_TEMPLATES: ${{env.NAME_PREFIX}}.export-templates${{ matrix.opts.build-mono == true && '.mono' || '' }}
uses: actions/upload-artifact@v4
with:
name: ${{ startsWith(matrix.opts.target, 'template') && env.NAME_TEMPLATES || env.NAME_EDITOR }}
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.${{matrix.opts.target}}.windows.${{matrix.opts.arch}}
path: out/*
- name: Mark .NET editor as built
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
id: mark-dotnet-editor
run: echo "built-dotnet-editor=true" >> $GITHUB_OUTPUT
dotnet-assemblies:
name: .NET assembly for ${{matrix.opts.arch}}
needs: windows-builds
if: always() && needs.windows-builds.outputs.built-dotnet-editor == 'true'
runs-on: "windows-latest"
strategy:
fail-fast: false
matrix:
opts:
- arch: x86_64
llvm: false
env:
BIN: godot.windows.editor.${{matrix.opts.arch}}${{matrix.opts.llvm && '.llvm' || ''}}.mono
steps:
- name: Clone Godot
uses: actions/checkout@v4
with:
repository: godotengine/godot
ref: ${{ inputs.godot-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: modules/limboai
ref: ${{ inputs.limboai-ref }}
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./modules/limboai/.github/actions/init-version
- name: Reconstruct artifact name
shell: bash
run: |
echo "ARTIFACT=${{env.NAME_PREFIX}}.dotnet.editor.windows.${{matrix.opts.arch}}" >> $GITHUB_ENV
- name: Download editor artifact
uses: actions/download-artifact@v4
with:
name: ${{env.ARTIFACT}}
path: bin/
- name: Build .NET assemblies
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
with:
platform: windows
bin: ${{env.BIN}}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{env.ARTIFACT}}
overwrite: true
path: bin/*

5
.gitignore vendored
View File

@ -1,6 +1,8 @@
# LimboAI-specific
demo/addons/
demo/script_templates/
icons/*.import
godot-cpp
# Godot auto generated files
*.gen.*
@ -185,3 +187,6 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
# clang cache
.cache

24
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,24 @@
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
hooks:
- id: clang-format
files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java|glsl)$
types_or: [text]
exclude: |
(?x)^(
tests/python_build.*|
.*thirdparty.*|
.*platform/android/java/lib/src/com.*|
.*-so_wrap.*
)
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.2.0
hooks:
- id: black
files: (\.py$|SConstruct|SCsub)
types_or: [text]
exclude: .*thirdparty.*
args:
- --line-length=120

View File

@ -1,4 +1,4 @@
Copyright 2021-2023 Serhii Snitsaruk
Copyright (c) 2023-2025 Serhii Snitsaruk and the LimboAI contributors.
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:

119
README.md
View File

@ -1,29 +1,48 @@
# LimboAI - Behavior Trees and State Machines for Godot 4
<p align="center">
<img src="doc/images/logo.svg" width="400" alt="LimboAI logo">
</p>
# LimboAI - Behavior Trees & State Machines for Godot 4
[![🔗 All builds](https://github.com/limbonaut/limboai/actions/workflows/all_builds.yml/badge.svg)](https://github.com/limbonaut/limboai/actions/workflows/all_builds.yml)
[![🔎 Unit Tests](https://github.com/limbonaut/limboai/actions/workflows/test_builds.yml/badge.svg)](https://github.com/limbonaut/limboai/actions/workflows/test_builds.yml)
[![Documentation Status](https://readthedocs.org/projects/limboai/badge/?version=latest)](https://limboai.readthedocs.io/en/latest/?badge=latest)
![GitHub License](https://img.shields.io/github/license/limbonaut/limboai)
![Discord](https://img.shields.io/discord/1185664967379267774?logo=discord&link=https%3A%2F%2Fdiscord.gg%2FN5MGC95GpP)
![Mastodon Follow](https://img.shields.io/mastodon/follow/109346796150895359?domain=https%3A%2F%2Fmastodon.gamedev.place)
[![GitHub License](https://img.shields.io/github/license/limbonaut/limboai)](https://github.com/limbonaut/limboai/blob/master/LICENSE.md)
[![Discord](https://img.shields.io/discord/1185664967379267774?logo=discord&link=https%3A%2F%2Fdiscord.gg%2FN5MGC95GpP)](https://discord.gg/N5MGC95GpP)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/109346796150895359?domain=https%3A%2F%2Fmastodon.gamedev.place)](https://mastodon.gamedev.place/@limbo)
**LimboAI** is an open-source C++ module for **Godot Engine 4** providing a combination of
>**🛈 Supported Godot Engine:** **4.3** (v1.2.0+) | **4.2** (v1.1.x releases)
**LimboAI** is an open-source C++ plugin for **Godot Engine 4** providing a combination of
**Behavior Trees** and **State Machines**, which can be used together to create complex AI behaviors.
It comes with a behavior tree editor, built-in documentation, visual debugger, and more!
While it is implemented in C++, it fully supports GDScript for [creating your own tasks](https://limboai.readthedocs.io/en/latest/getting-started/custom-tasks.html) and states.
It comes with a behavior tree editor, built-in documentation, visual debugger, extensive demo project with a tutorial, and more!
While it is implemented in C++, it fully supports GDScript for [creating your own tasks](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html) and [states](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html).
>**🛈 Supported Godot Engine: 4.2**
If you enjoy using LimboAI, please **consider supporting** my efforts with a donation on Ko-fi 😊 Your contribution will help me continue developing and improving it.
>**🛈 License**: Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
Behavior Trees are powerful hierarchical structures used to model and control the behavior of agents in a game (e.g., characters, enemies, entities). They are designed to make it easier to create complex and highly modular behaviors for your games. To learn more about behavior trees, check out [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/latest/getting-started/introduction.html).
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Y8Y2TCNH0)
![Textured screenshot](doc/images/behavior-tree-editor-debugger.png)
Behavior Trees are powerful hierarchical structures used to model and control the behavior of agents in a game (e.g., characters, enemies). They are designed to make it easier to create rich and highly modular behaviors for your games. To learn more about behavior trees, check out [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/stable/behavior-trees/introduction.html) and our demo project, which includes a tutorial.
## Demonstration
![Charger from Demo](doc/images/demo_charger.gif)
>**🛈 Demo project** lives in the `demo` folder and is available separately in [**Releases**](https://github.com/limbonaut/limboai/releases).
> Run `demo/scenes/showcase.tscn` to get started.
> It also includes a tutorial that introduces behavior trees through illustrative examples.
### Videos
> **🛈** YouTube videos produced by various creators
<a href="https://www.youtube.com/watch?v=NWaMArUg7mY"><img src="https://img.youtube.com/vi/NWaMArUg7mY/0.jpg" width=410></a>
<a href="https://www.youtube.com/watch?v=aP0Aacdxmno"><img src="https://img.youtube.com/vi/aP0Aacdxmno/0.jpg" width=410></a>
<a href="https://www.youtube.com/watch?v=vZHzMO90IwQ"><img src="https://img.youtube.com/vi/vZHzMO90IwQ/0.jpg" width=410></a>
<a href="https://www.youtube.com/watch?v=gAk3xl5fBsM"><img src="https://img.youtube.com/vi/gAk3xl5fBsM/0.jpg" width=410></a>
## Features
- **Behavior Trees (BT):**
@ -31,30 +50,41 @@ Behavior Trees are powerful hierarchical structures used to model and control th
- Execute `BehaviorTree` resources using the `BTPlayer` node.
- Create complex behaviors by combining and nesting tasks in a hierarchy.
- Control execution flow using composite, decorator, and condition tasks.
- [Create custom tasks](https://limboai.readthedocs.io/en/latest/getting-started/custom-tasks.html) by extending core classes: `BTAction`, `BTCondition`, `BTDecorator`, and `BTComposite`.
- Built-in class documentation. Check out the `BehaviorTree` class documentation to get started.
- Share data seamlessly between tasks using the `Blackboard`.
- Blackboard scopes isolate variable namespaces and enable advanced techniques like sharing data between agents in a group.
- [Create custom tasks](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html) by extending core classes: `BTAction`, `BTCondition`, `BTDecorator`, and `BTComposite`.
- Built-in class documentation.
- Blackboard system: Share data seamlessly between tasks using the `Blackboard`.
- Blackboard plans: Define variables in the BehaviorTree resource and override their values in the BTPlayer node.
- Plan editor: Manage variables, their data types and property hints.
- Blackboard scopes: Prevent name conflicts and enable advanced techniques like [sharing data between several agents](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html#sharing-data-between-several-agents).
- Blackboard parameters: [Export a BB parameter](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html#task-parameters), for which user can provide a value or bind it to a blackboard variable (can be used in custom tasks).
- Inspector support for specifying blackboard variables (custom editor for exported `StringName` properties ending with "_var").
- Use the `BTSubtree` task to execute a tree from a different resource file, promoting organization and reusability.
- Visual Debugger: Inspect the execution of any BT in a running scene to identify and troubleshoot issues.
- Visualize BT in-game using `BehaviorTreeView` node (for custom in-game tools).
- Monitor tree performance with custom performance monitors.
- **Hierarchical State Machines (HSM):**
- Extend the `LimboState` class to implement state logic.
- The `LimboHSM` node serves as a state machine that manages `LimboState` instances and transitions.
- `LimboHSM` node serves as a state machine that manages `LimboState` instances and transitions.
- `LimboHSM` is a state itself and can be nested within other `LimboHSM` instances.
- Event-based: Transitions are associated with events and are triggered by the state machine when the relevant event is dispatched, allowing for better decoupling of transitions from state logic.
- [Event-based](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html#events-and-transitions): Transitions are associated with events and are triggered by the state machine when the relevant event is dispatched, allowing for better decoupling of transitions from state logic.
- Combine state machines with behavior trees using `BTState` for advanced reactive AI.
- Delegation Option: Using the vanilla `LimboState`, delegate the implementation to your callback functions, making it perfect for rapid prototyping and game jams.
- Delegation Option: Using the vanilla `LimboState`, [delegate the implementation](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html#single-file-state-machine-setup) to your callback functions, making it perfect for rapid prototyping and game jams.
- 🛈 Note: State machine setup and initialization require code; there is no GUI editor.
- **Tested:** Behavior tree tasks and HSM are covered by unit tests.
- **GDExtension:** LimboAI can be [used as extension](https://limboai.readthedocs.io/en/latest/getting-started/gdextension.html). Custom engine builds are not necessary.
- **GDExtension:** LimboAI can be [used as extension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version). Custom engine builds are not necessary.
- **Demo + Tutorial:** Check out our extensive demo project, which includes an introduction to behavior trees using examples.
## First steps
Follow the [Getting started](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html) guide to learn how to get started with LimboAI and the demo project.
## Getting LimboAI
LimboAI can be used as either a C++ module or as a GDExtension shared library. GDExtension version is more convenient to use but somewhat limited in features. Whichever you choose to use, your project will stay compatible with both and you can switch from one to the other any time. See [Using GDExtension](https://limboai.readthedocs.io/en/latest/getting-started/gdextension.html).
LimboAI can be used as either a C++ module or as a GDExtension shared library. GDExtension version is more convenient to use but somewhat limited in features. Whichever you choose to use, your project will stay compatible with both and you can switch from one to the other any time. See [Using GDExtension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version).
### Precompiled builds
@ -68,35 +98,42 @@ LimboAI can be used as either a C++ module or as a GDExtension shared library. G
- If you plan to export a game utilizing the LimboAI module, you'll also need to build export templates.
- To execute unit tests, compile the engine with `tests=yes` and run it with `--test --tc="*[LimboAI]*"`.
#### For GDExtension
- You'll need SCons build tool and a C++ compiler. See also [Compiling](https://docs.godotengine.org/en/stable/contributing/development/compiling/index.html).
- Run `scons target=editor` to build the plugin library for your current platform.
- SCons will automatically clone the godot-cpp/ repository if it doesn't already exist in the `limboai/godot-cpp` directory.
- By default, built targets are placed in the demo project: `demo/addons/limboai/bin/`
- Check `scons -h` for other options and targets.
## Using the plugin
- [Online Documentation](https://limboai.readthedocs.io/en/latest/index.html)
- [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/latest/getting-started/introduction.html)
- [Creating custom tasks in GDScript](https://limboai.readthedocs.io/en/latest/getting-started/custom-tasks.html)
- [Using GDExtension](https://limboai.readthedocs.io/en/latest/getting-started/gdextension.html)
- [Class reference](https://limboai.readthedocs.io/en/latest/getting-started/featured-classes.html)
- Online Documentation: [stable](https://limboai.readthedocs.io/en/stable/index.html), [latest](https://limboai.readthedocs.io/en/latest/index.html)
- [Getting started](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html)
- [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/stable/behavior-trees/introduction.html)
- [Creating custom tasks in GDScript](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html)
- [Sharing data using Blackboard](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html)
- [Accessing nodes in the scene tree](https://limboai.readthedocs.io/en/stable/behavior-trees/accessing-nodes.html)
- [State machines](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html)
- [Using GDExtension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version)
- [Using LimboAI with C#](https://limboai.readthedocs.io/en/stable/getting-started/c-sharp.html)
- [Class reference](https://limboai.readthedocs.io/en/stable/classes/featured-classes.html)
## Contributing
All contributions are welcome! Feel free to open issues with bug reports and feature requests, and submit PRs.
Contributions are welcome! Please open issues for bug reports, feature requests, or code changes.
For detailed guidelines on contributing to code or documentation, check out our [Contributing](https://limboai.readthedocs.io/en/latest/getting-started/contributing.html) page.
Got an idea for a behavior tree task that you think would be useful on a variety of projects?
Feel free to open an issue and describe your concept.
If you have an idea for a behavior tree task or a feature that could be useful in a variety of projects, open an issue to discuss it.
## Social
We have a fresh new Discord server: https://discord.gg/N5MGC95GpP
Need help? We have a Discord server: https://discord.gg/N5MGC95GpP
I also write about LimboAI development on the Mastodon: https://mastodon.gamedev.place/@limbo.
I write about LimboAI development on Mastodon: https://mastodon.gamedev.place/@limbo.
## Roadmap
## License
Features and improvements that may be implemented in the future:
- ~~Providing precompiled builds for download.~~ 🗸
- ~~Tests and CI.~~ 🗸
- Expanding the library of commonly useful tasks.
- Creating a non-trivial demo project to showcase the capabilities of LimboAI.
- Exploring the execution history of behavior trees in the visual debugger.
- Per-project ignore list for tasks that users may want to hide in the task palette.
- GUI editor for state machines.
~~- Supporting GDExtension in the future, once it matures.~~ 🗸
Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT
LimboAI logo and demo project art assets are licensed under the Creative Commons Attribution 4.0 International license that can be found at https://creativecommons.org/licenses/by/4.0/

160
SConstruct Normal file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env python
"""
This is SConstruct file for building GDExtension variant using SCons build system.
For module variant, see SCsub file.
Use --project=DIR to customize output path for built targets.
- Built targets are placed into "DIR/addons/limboai/bin".
- For example: scons --project="../my_project"
- built targets will be placed into "../my_project/addons/limboai/bin".
- If not specified, built targets are put into the demo/ project.
"""
import os
import sys
import subprocess
from limboai_version import generate_module_version_header, godot_cpp_ref
sys.path.append("gdextension")
from update_icon_entries import update_icon_entries
from fix_icon_imports import fix_icon_imports
# Check if godot-cpp/ exists
if not os.path.exists("godot-cpp"):
print("Directory godot-cpp/ not found. Cloning repository...")
result = subprocess.run(
["git", "clone", "-b", godot_cpp_ref, "https://github.com/godotengine/godot-cpp.git"],
check=True,
# capture_output=True
)
if result.returncode != 0:
print("Error: Cloning godot-cpp repository failed.")
Exit(1)
print("Finished cloning godot-cpp repository.")
AddOption(
"--project",
dest="project",
type="string",
nargs=1,
action="store",
metavar="DIR",
default="demo",
help="Specify project directory",
)
help_text = """
Options:
--project=DIR Specify project directory (default: "demo");
built targets will be placed in DIR/addons/limboai/bin
"""
Help(help_text)
project_dir = GetOption("project")
if not os.path.isdir(project_dir):
print("Project directory not found: " + project_dir)
Exit(2)
# Parse LimboAI-specific variables.
vars = Variables()
vars.AddVariables(
BoolVariable("deploy_manifest", help="Deploy limboai.gdextension into PROJECT/addons/limboai/bin", default=True),
BoolVariable("deploy_icons", help="Deploy icons into PROJECT/addons/limboai/icons", default=True),
)
env = Environment(tools=["default"], PLATFORM="", variables=vars)
Help(vars.GenerateHelpText(env))
# Read LimboAI-specific variables.
deploy_manifest = env["deploy_manifest"]
deploy_icons = env["deploy_icons"]
# Remove processed variables from ARGUMENTS to avoid godot-cpp warnings.
for o in vars.options:
if o.key in ARGUMENTS:
del ARGUMENTS[o.key]
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
env = SConscript("godot-cpp/SConstruct")
# Generate version header.
print("Generating LimboAI version header...")
generate_module_version_header()
# Update icon entries in limboai.gdextension file.
# Note: This will remove everything after [icons] section, and rebuild it with generated icon entries.
print("Updating LimboAI icon entries...")
update_icon_entries(silent=True)
# Fix icon imports in the PROJECT/addons/limboai/icons/.
# Enables scaling and color conversion in the editor for imported SVG icons.
try:
fix_icon_imports(project_dir)
except FileNotFoundError as e:
print(e)
except Exception as e:
print("Unknown error: " + str(e))
# Tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPDEFINES=["LIMBOAI_GDEXTENSION"])
sources = Glob("*.cpp")
sources += Glob("blackboard/*.cpp")
sources += Glob("blackboard/bb_param/*.cpp")
sources += Glob("bt/*.cpp")
sources += Glob("bt/tasks/*.cpp")
sources += Glob("bt/tasks/blackboard/*.cpp")
sources += Glob("bt/tasks/composites/*.cpp")
sources += Glob("bt/tasks/decorators/*.cpp")
sources += Glob("bt/tasks/scene/*.cpp")
sources += Glob("bt/tasks/utility/*.cpp")
sources += Glob("gdextension/*.cpp")
sources += Glob("editor/debugger/*.cpp")
sources += Glob("editor/*.cpp")
sources += Glob("hsm/*.cpp")
sources += Glob("util/*.cpp")
# Generate documentation header.
if env["target"] in ["editor", "template_debug"]:
doc_data = env.GodotCPPDocData("gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
sources.append(doc_data)
# Build library.
if env["platform"] == "macos":
library = env.SharedLibrary(
project_dir
+ "/addons/limboai/bin/liblimboai.{}.{}.framework/liblimboai.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
project_dir + "/addons/limboai/bin/liblimboai{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)
# Deploy icons into PROJECT/addons/limboai/icons.
if deploy_icons:
cmd_deploy_icons = env.Command(
project_dir + "/addons/limboai/icons/",
"icons/",
Copy("$TARGET", "$SOURCE"),
)
Default(cmd_deploy_icons)
# Deploy limboai.gdextension into PROJECT/addons/limboai/bin.
if deploy_manifest:
cmd_deploy_manifest = env.Command(
project_dir + "/addons/limboai/bin/limboai.gdextension",
"gdextension/limboai.gdextension",
Copy("$TARGET", "$SOURCE"),
)
Default(cmd_deploy_manifest)

6
SCsub
View File

@ -5,7 +5,11 @@ Import("env_modules")
module_env = env.Clone()
module_env.Append(CPPDEFINES = ['LIMBOAI_MODULE'])
module_env.Append(CPPDEFINES=["LIMBOAI_MODULE"])
import limboai_version
limboai_version.generate_module_version_header()
module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.add_source_files(env.modules_sources, "blackboard/*.cpp")

View File

@ -1,7 +1,7 @@
/**
* bb_aabb.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBAabb : public BBParam {
GDCLASS(BBAabb, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::AABB; }
};
#endif // BB_AABB_H
#endif // BB_AABB_H

View File

@ -1,7 +1,7 @@
/**
* bb_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBArray : public BBParam {
GDCLASS(BBArray, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::ARRAY; }
};
#endif // BB_ARRAY_H
#endif // BB_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_basis.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBBasis : public BBParam {
GDCLASS(BBBasis, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::BASIS; }
};
#endif // BB_BASIS_H
#endif // BB_BASIS_H

View File

@ -1,7 +1,7 @@
/**
* bb_bool.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBBool : public BBParam {
GDCLASS(BBBool, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::BOOL; }
};
#endif // BB_BOOL_H
#endif // BB_BOOL_H

View File

@ -1,7 +1,7 @@
/**
* bb_byte_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBByteArray : public BBParam {
GDCLASS(BBByteArray, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_BYTE_ARRAY; }
};
#endif // BB_BYTE_ARRAY_H
#endif // BB_BYTE_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_color.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBColor : public BBParam {
GDCLASS(BBColor, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::COLOR; }
};
#endif // BB_COLOR_H
#endif // BB_COLOR_H

View File

@ -1,7 +1,7 @@
/**
* bb_color_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBColorArray : public BBParam {
GDCLASS(BBColorArray, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_COLOR_ARRAY; }
};
#endif // BB_COLOR_ARRAY_H
#endif // BB_COLOR_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_dictionary.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBDictionary : public BBParam {
GDCLASS(BBDictionary, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::DICTIONARY; }
};
#endif // BB_DICTIONARY_H
#endif // BB_DICTIONARY_H

View File

@ -1,7 +1,7 @@
/**
* bb_float.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBFloat : public BBParam {
GDCLASS(BBFloat, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::FLOAT; }
};
#endif // BB_FLOAT_H
#endif // BB_FLOAT_H

View File

@ -0,0 +1,26 @@
/**
* bb_float32_array.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BB_FLOAT32_ARRAY_H
#define BB_FLOAT32_ARRAY_H
#include "bb_param.h"
class BBFloat32Array : public BBParam {
GDCLASS(BBFloat32Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_FLOAT32_ARRAY; }
};
#endif // BB_FLOAT32_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_float_array.h
* bb_float64_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -9,16 +9,18 @@
* =============================================================================
*/
#ifndef BB_FLOAT_ARRAY_H
#define BB_FLOAT_ARRAY_H
#ifndef BB_FLOAT64_ARRAY_H
#define BB_FLOAT64_ARRAY_H
#include "bb_param.h"
class BBFloatArray : public BBParam {
GDCLASS(BBFloatArray, BBParam);
class BBFloat64Array : public BBParam {
GDCLASS(BBFloat64Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_FLOAT64_ARRAY; }
};
#endif // BB_FLOAT_ARRAY_H
#endif // BB_FLOAT64_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_int.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBInt : public BBParam {
GDCLASS(BBInt, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::INT; }
};
#endif // BB_INT_H
#endif // BB_INT_H

View File

@ -0,0 +1,26 @@
/**
* bb_int32_array.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BB_INT32_ARRAY_H
#define BB_INT32_ARRAY_H
#include "bb_param.h"
class BBInt32Array : public BBParam {
GDCLASS(BBInt32Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_INT32_ARRAY; }
};
#endif // BB_INT32_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_int_array.h
* bb_int64_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -9,16 +9,18 @@
* =============================================================================
*/
#ifndef BB_INT_ARRAY_H
#define BB_INT_ARRAY_H
#ifndef BB_INT64_ARRAY_H
#define BB_INT64_ARRAY_H
#include "bb_param.h"
class BBIntArray : public BBParam {
GDCLASS(BBIntArray, BBParam);
class BBInt64Array : public BBParam {
GDCLASS(BBInt64Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_INT64_ARRAY; }
};
#endif // BB_INT_ARRAY_H
#endif // BB_INT64_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_node.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -11,18 +11,9 @@
#include "bb_node.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h"
#include "scene/main/node.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#endif // LIMBOAI_GDEXTENSION
Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
ERR_FAIL_COND_V(p_agent == nullptr, Variant());
ERR_FAIL_COND_V(!p_blackboard.is_valid(), Variant());
Variant BBNode::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
ERR_FAIL_NULL_V_MSG(p_scene_root, Variant(), "BBNode: get_value() failed - scene_root is null.");
ERR_FAIL_COND_V_MSG(p_blackboard.is_null(), Variant(), "BBNode: get_value() failed - blackboard is null.");
Variant val;
if (get_value_source() == SAVED_VALUE) {
@ -32,16 +23,11 @@ Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard,
}
if (val.get_type() == Variant::NODE_PATH) {
Node *agent = Object::cast_to<Node>(p_agent);
ERR_FAIL_COND_V_MSG(agent == nullptr, Variant(), "BBNode: p_agent must be a Node.");
return agent->get_node_or_null(val);
return p_scene_root->get_node_or_null(val);
} else if (val.get_type() == Variant::OBJECT || val.get_type() == Variant::NIL) {
return val;
} else {
Object *obj = val;
if (unlikely(obj == nullptr && val.get_type() != Variant::NIL)) {
WARN_PRINT("BBNode: Unexpected variant type of a blackboard variable.");
return p_default;
} else {
return obj;
}
WARN_PRINT("BBNode: Unexpected variant type: " + Variant::get_type_name(val.get_type()) + ". Returning default value.");
return p_default;
}
}

View File

@ -1,7 +1,7 @@
/**
* bb_node.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,10 +18,11 @@ class BBNode : public BBParam {
GDCLASS(BBNode, BBParam);
protected:
virtual Variant::Type get_type() const override { return Variant::NODE_PATH; }
static void _bind_methods() {}
public:
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override;
virtual Variant::Type get_type() const override { return Variant::NODE_PATH; }
virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override;
};
#endif // BB_NODE_H
#endif // BB_NODE_H

View File

@ -1,7 +1,7 @@
/**
* bb_param.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -14,12 +14,6 @@
#include "../../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "core/core_bind.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/variant/variant.h"
#include "core/variant/variant_utility.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
@ -49,8 +43,8 @@ void BBParam::set_saved_value(Variant p_value) {
emit_changed();
}
void BBParam::set_variable(const String &p_value) {
variable = p_value;
void BBParam::set_variable(const StringName &p_variable) {
variable = p_variable;
_update_name();
emit_changed();
}
@ -81,10 +75,13 @@ String BBParam::_to_string() {
}
}
Variant BBParam::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
Variant BBParam::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
ERR_FAIL_COND_V(!p_blackboard.is_valid(), p_default);
if (value_source == SAVED_VALUE) {
if (saved_value == Variant()) {
_assign_default_value();
}
return saved_value;
} else {
ERR_FAIL_COND_V_MSG(!p_blackboard->has_var(variable), p_default, vformat("BBParam: Blackboard variable \"%s\" doesn't exist.", variable));
@ -96,22 +93,22 @@ void BBParam::_get_property_list(List<PropertyInfo> *p_list) const {
if (value_source == ValueSource::SAVED_VALUE) {
p_list->push_back(PropertyInfo(get_type(), "saved_value"));
} else {
p_list->push_back(PropertyInfo(Variant::STRING, "variable"));
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "variable"));
}
}
void BBParam::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value_source", "p_value_source"), &BBParam::set_value_source);
ClassDB::bind_method(D_METHOD("set_value_source", "value_source"), &BBParam::set_value_source);
ClassDB::bind_method(D_METHOD("get_value_source"), &BBParam::get_value_source);
ClassDB::bind_method(D_METHOD("set_saved_value", "p_value"), &BBParam::set_saved_value);
ClassDB::bind_method(D_METHOD("set_saved_value", "value"), &BBParam::set_saved_value);
ClassDB::bind_method(D_METHOD("get_saved_value"), &BBParam::get_saved_value);
ClassDB::bind_method(D_METHOD("set_variable", "p_variable_name"), &BBParam::set_variable);
ClassDB::bind_method(D_METHOD("set_variable", "variable_name"), &BBParam::set_variable);
ClassDB::bind_method(D_METHOD("get_variable"), &BBParam::get_variable);
ClassDB::bind_method(D_METHOD("get_type"), &BBParam::get_type);
ClassDB::bind_method(D_METHOD("get_value", "p_agent", "p_blackboard", "p_default"), &BBParam::get_value, Variant());
ClassDB::bind_method(D_METHOD("get_value", "scene_root", "blackboard", "default"), &BBParam::get_value, Variant());
ADD_PROPERTY(PropertyInfo(Variant::INT, "value_source", PROPERTY_HINT_ENUM, "Saved Value,Blackboard Var"), "set_value_source", "get_value_source");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::NIL, "saved_value", PROPERTY_HINT_NONE, "", 0), "set_saved_value", "get_saved_value");
BIND_ENUM_CONSTANT(SAVED_VALUE);
@ -120,7 +117,4 @@ void BBParam::_bind_methods() {
BBParam::BBParam() {
value_source = SAVED_VALUE;
variable = "";
_assign_default_value();
}

View File

@ -1,7 +1,7 @@
/**
* bb_param.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -17,16 +17,10 @@
#ifdef LIMBOAI_MODULE
#include "core/io/resource.h"
#include "core/object/object.h"
#include "core/typedefs.h"
#include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/variant/variant.hpp>
#endif // LIMBOAI_GDEXTENSION
class BBParam : public Resource {
@ -41,7 +35,7 @@ public:
private:
ValueSource value_source;
Variant saved_value;
String variable;
StringName variable;
_FORCE_INLINE_ void _update_name() {
set_name((value_source == SAVED_VALUE) ? String(saved_value) : LimboUtility::get_singleton()->decorate_var(variable));
@ -50,28 +44,19 @@ private:
protected:
static void _bind_methods();
_FORCE_INLINE_ void _assign_default_value() {
#ifdef LIMBOAI_MODULE
Callable::CallError err;
Variant::construct(get_type(), saved_value, nullptr, 0, err);
#elif LIMBOAI_GDEXTENSION
saved_value.clear();
#endif
}
_FORCE_INLINE_ void _assign_default_value() { saved_value = VARIANT_DEFAULT(get_type()); }
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
virtual Variant::Type get_type() const { return Variant::NIL; }
void set_value_source(ValueSource p_value);
ValueSource get_value_source() const { return value_source; }
void set_saved_value(Variant p_value);
Variant get_saved_value();
void set_variable(const String &p_value);
String get_variable() const { return variable; }
void set_variable(const StringName &p_variable);
StringName get_variable() const { return variable; }
#ifdef LIMBOAI_MODULE
virtual String to_string() override;
@ -79,9 +64,11 @@ public:
virtual String _to_string();
#endif
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());
virtual Variant::Type get_type() const { return Variant::NIL; }
virtual Variant::Type get_variable_expected_type() const { return get_type(); }
virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());
BBParam();
};
#endif // BB_PARAM_H
#endif // BB_PARAM_H

View File

@ -1,7 +1,7 @@
/**
* bb_plane.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBPlane : public BBParam {
GDCLASS(BBPlane, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PLANE; }
};
#endif // BB_PLANE_H
#endif // BB_PLANE_H

View File

@ -0,0 +1,26 @@
/**
* bb_projection.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BB_PROJECTION_H
#define BB_PROJECTION_H
#include "bb_param.h"
class BBProjection : public BBParam {
GDCLASS(BBProjection, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PROJECTION; }
};
#endif // BB_PROJECTION_H

View File

@ -1,7 +1,7 @@
/**
* bb_quaternion.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBQuaternion : public BBParam {
GDCLASS(BBQuaternion, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::QUATERNION; }
};
#endif // BB_QUATERNION_H
#endif // BB_QUATERNION_H

View File

@ -1,7 +1,7 @@
/**
* bb_rect2.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBRect2 : public BBParam {
GDCLASS(BBRect2, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::RECT2; }
};
#endif // BB_RECT2_H
#endif // BB_RECT2_H

View File

@ -1,7 +1,7 @@
/**
* bb_rect2i.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBRect2i : public BBParam {
GDCLASS(BBRect2i, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::RECT2I; }
};
#endif // BB_RECT2I_H
#endif // BB_RECT2I_H

View File

@ -1,7 +1,7 @@
/**
* bb_string.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBString : public BBParam {
GDCLASS(BBString, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::STRING; }
};
#endif // BB_STRING_H
#endif // BB_STRING_H

View File

@ -1,7 +1,7 @@
/**
* bb_string_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBStringArray : public BBParam {
GDCLASS(BBStringArray, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_STRING_ARRAY; }
};
#endif // BB_STRING_ARRAY_H
#endif // BB_STRING_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_string_name.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBStringName : public BBParam {
GDCLASS(BBStringName, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::STRING_NAME; }
};
#endif // BB_STRING_H
#endif // BB_STRING_H

View File

@ -1,7 +1,7 @@
/**
* bb_transform2d.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBTransform2D : public BBParam {
GDCLASS(BBTransform2D, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::TRANSFORM2D; }
};
#endif // BB_TRANSFORM2D_H
#endif // BB_TRANSFORM2D_H

View File

@ -1,7 +1,7 @@
/**
* bb_transform3d.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBTransform3D : public BBParam {
GDCLASS(BBTransform3D, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::TRANSFORM3D; }
};
#endif // BB_TRANSFORM3D_H
#endif // BB_TRANSFORM3D_H

View File

@ -1,7 +1,7 @@
/**
* bb_variant.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -27,7 +27,7 @@ Variant::Type BBVariant::get_type() const {
}
void BBVariant::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_type", "p_type"), &BBVariant::set_type);
ClassDB::bind_method(D_METHOD("set_type", "type"), &BBVariant::set_type);
String vtypes;
for (int i = 0; i < Variant::VARIANT_MAX; i++) {

View File

@ -1,7 +1,7 @@
/**
* bb_variant.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -27,8 +27,10 @@ public:
virtual Variant::Type get_type() const override;
void set_type(Variant::Type p_type);
virtual Variant::Type get_variable_expected_type() const override { return Variant::NIL; }
BBVariant(const Variant &p_value);
BBVariant();
};
#endif // BB_VARIANT
#endif // BB_VARIANT

View File

@ -1,7 +1,7 @@
/**
* bb_vector2.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector2 : public BBParam {
GDCLASS(BBVector2, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR2; }
};
#endif // BB_VECTOR2_H
#endif // BB_VECTOR2_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector2_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector2Array : public BBParam {
GDCLASS(BBVector2Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_VECTOR2_ARRAY; }
};
#endif // BB_VECTOR2_ARRAY_H
#endif // BB_VECTOR2_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector2i.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector2i : public BBParam {
GDCLASS(BBVector2i, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR2I; }
};
#endif // BB_VECTOR2I_H
#endif // BB_VECTOR2I_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector3.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector3 : public BBParam {
GDCLASS(BBVector3, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR3; }
};
#endif // BB_VECTOR3_H
#endif // BB_VECTOR3_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector3_array.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector3Array : public BBParam {
GDCLASS(BBVector3Array, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::PACKED_VECTOR3_ARRAY; }
};
#endif // BB_VECTOR3_ARRAY_H
#endif // BB_VECTOR3_ARRAY_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector3i.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector3i : public BBParam {
GDCLASS(BBVector3i, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR3I; }
};
#endif // BB_VECTOR3I_H
#endif // BB_VECTOR3I_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector4.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector4 : public BBParam {
GDCLASS(BBVector4, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR4; }
};
#endif // BB_VECTOR4_H
#endif // BB_VECTOR4_H

View File

@ -1,7 +1,7 @@
/**
* bb_vector4i.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,7 +18,9 @@ class BBVector4i : public BBParam {
GDCLASS(BBVector4i, BBParam);
protected:
static void _bind_methods() {}
virtual Variant::Type get_type() const override { return Variant::VECTOR4I; }
};
#endif // BB_VECTOR4I_H
#endif // BB_VECTOR4I_H

190
blackboard/bb_variable.cpp Normal file
View File

@ -0,0 +1,190 @@
/**
* bb_variable.cpp
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#include "bb_variable.h"
#include "../util/limbo_compat.h"
void BBVariable::unref() {
if (data && data->refcount.unref()) {
memdelete(data);
}
data = nullptr;
}
void BBVariable::set_value(const Variant &p_value) {
data->value = p_value; // Setting value even when bound as a fallback in case the binding fails.
data->value_changed = true;
if (is_bound()) {
Object *obj = OBJECT_DB_GET_INSTANCE(data->bound_object);
ERR_FAIL_COND_MSG(!obj, "Blackboard: Failed to get bound object.");
#ifdef LIMBOAI_MODULE
bool r_valid;
obj->set(data->bound_property, p_value, &r_valid);
ERR_FAIL_COND_MSG(!r_valid, vformat("Blackboard: Failed to set bound property `%s` on %s", data->bound_property, obj));
#elif LIMBOAI_GDEXTENSION
obj->set(data->bound_property, p_value);
#endif
}
}
Variant BBVariable::get_value() const {
if (is_bound()) {
Object *obj = OBJECT_DB_GET_INSTANCE(data->bound_object);
ERR_FAIL_COND_V_MSG(!obj, data->value, "Blackboard: Failed to get bound object.");
#ifdef LIMBOAI_MODULE
bool r_valid;
Variant ret = obj->get(data->bound_property, &r_valid);
ERR_FAIL_COND_V_MSG(!r_valid, data->value, vformat("Blackboard: Failed to get bound property `%s` on %s", data->bound_property, obj));
#elif LIMBOAI_GDEXTENSION
Variant ret = obj->get(data->bound_property);
#endif
return ret;
}
return data->value;
}
void BBVariable::set_type(Variant::Type p_type) {
data->type = p_type;
data->value = VARIANT_DEFAULT(p_type);
}
Variant::Type BBVariable::get_type() const {
return data->type;
}
void BBVariable::set_hint(PropertyHint p_hint) {
data->hint = p_hint;
}
PropertyHint BBVariable::get_hint() const {
return data->hint;
}
void BBVariable::set_hint_string(const String &p_hint_string) {
data->hint_string = p_hint_string;
}
String BBVariable::get_hint_string() const {
return data->hint_string;
}
BBVariable BBVariable::duplicate(bool p_deep) const {
BBVariable var;
var.data->hint = data->hint;
var.data->hint_string = data->hint_string;
var.data->type = data->type;
if (p_deep) {
var.data->value = data->value.duplicate(p_deep);
} else {
var.data->value = data->value;
}
var.data->binding_path = data->binding_path;
var.data->bound_object = data->bound_object;
var.data->bound_property = data->bound_property;
return var;
}
bool BBVariable::is_same_prop_info(const BBVariable &p_other) const {
if (data->type != p_other.data->type) {
return false;
}
if (data->hint != p_other.data->hint) {
return false;
}
if (data->hint_string != p_other.data->hint_string) {
return false;
}
return true;
}
void BBVariable::copy_prop_info(const BBVariable &p_other) {
data->type = p_other.data->type;
data->hint = p_other.data->hint;
data->hint_string = p_other.data->hint_string;
}
void BBVariable::bind(Object *p_object, const StringName &p_property) {
ERR_FAIL_NULL_MSG(p_object, "Blackboard: Binding failed - object is null.");
ERR_FAIL_COND_MSG(p_property == StringName(), "Blackboard: Binding failed - property name is empty.");
ERR_FAIL_COND_MSG(!OBJECT_HAS_PROPERTY(p_object, p_property), vformat("Blackboard: Binding failed - %s has no property `%s`.", p_object, p_property));
data->bound_object = p_object->get_instance_id();
data->bound_property = p_property;
}
void BBVariable::unbind() {
data->bound_object = 0;
data->bound_property = StringName();
}
bool BBVariable::operator==(const BBVariable &p_var) const {
if (data == p_var.data) {
return true;
}
if (!data || !p_var.data) {
return false;
}
if (data->type != p_var.data->type) {
return false;
}
if (data->hint != p_var.data->hint) {
return false;
}
if (data->hint_string != p_var.data->hint_string) {
return false;
}
if (get_value() != p_var.get_value()) {
return false;
}
return true;
}
bool BBVariable::operator!=(const BBVariable &p_var) const {
return !(*this == p_var);
}
void BBVariable::operator=(const BBVariable &p_var) {
if (this == &p_var) {
return;
}
unref();
if (p_var.data && p_var.data->refcount.ref()) {
data = p_var.data;
}
}
BBVariable::BBVariable(const BBVariable &p_var) {
if (p_var.data && p_var.data->refcount.ref()) {
data = p_var.data;
}
}
BBVariable::BBVariable(Variant::Type p_type, PropertyHint p_hint, const String &p_hint_string) {
data = memnew(Data);
data->refcount.init();
set_type(p_type);
data->hint = p_hint;
data->hint_string = p_hint_string;
}
BBVariable::~BBVariable() {
unref();
}

84
blackboard/bb_variable.h Normal file
View File

@ -0,0 +1,84 @@
/**
* bb_variable.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BB_VARIABLE_H
#define BB_VARIABLE_H
#ifdef LIMBOAI_MODULE
#include "core/object/object.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/core/object.hpp"
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
class BBVariable {
private:
struct Data {
// Is used to decide if the value needs to be synced in a derived plan.
bool value_changed = false;
SafeRefCount refcount;
Variant value;
Variant::Type type = Variant::NIL;
PropertyHint hint = PropertyHint::PROPERTY_HINT_NONE;
String hint_string;
NodePath binding_path;
uint64_t bound_object = 0;
StringName bound_property;
};
Data *data = nullptr;
void unref();
public:
void set_value(const Variant &p_value);
Variant get_value() const;
void set_type(Variant::Type p_type);
Variant::Type get_type() const;
void set_hint(PropertyHint p_hint);
PropertyHint get_hint() const;
void set_hint_string(const String &p_hint_string);
String get_hint_string() const;
BBVariable duplicate(bool p_deep = false) const;
_FORCE_INLINE_ bool is_value_changed() const { return data->value_changed; }
_FORCE_INLINE_ void reset_value_changed() { data->value_changed = false; }
bool is_same_prop_info(const BBVariable &p_other) const;
void copy_prop_info(const BBVariable &p_other);
// * Editor binding methods
NodePath get_binding_path() const { return data->binding_path; }
void set_binding_path(const NodePath &p_binding_path) { data->binding_path = p_binding_path; }
bool has_binding() { return data->binding_path.is_empty(); }
// * Runtime binding methods
_FORCE_INLINE_ bool is_bound() const { return data->bound_object != 0; }
void bind(Object *p_object, const StringName &p_property);
void unbind();
bool operator==(const BBVariable &p_var) const;
bool operator!=(const BBVariable &p_var) const;
void operator=(const BBVariable &p_var);
BBVariable(const BBVariable &p_var);
BBVariable(Variant::Type p_type = Variant::Type::NIL, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "");
~BBVariable();
};
#endif // BB_VARIABLE_H

View File

@ -1,7 +1,7 @@
/**
* blackboard.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -10,9 +10,9 @@
*/
#include "blackboard.h"
#include "../util/limbo_compat.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h"
#include "core/variant/variant.h"
#include "scene/main/node.h"
#endif // LIMBOAI_MODULE
@ -22,63 +22,146 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/dictionary.hpp>
using namespace godot;
#endif
Ref<Blackboard> Blackboard::top() const {
Ref<Blackboard> bb(this);
while (bb->get_parent_scope().is_valid()) {
bb = bb->get_parent_scope();
while (bb->get_parent().is_valid()) {
bb = bb->get_parent();
}
return bb;
}
Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const {
if (data.has(p_key)) {
return data.get(p_key, Variant());
Variant Blackboard::get_var(const StringName &p_name, const Variant &p_default, bool p_complain) const {
if (data.has(p_name)) {
return data.get(p_name).get_value();
} else if (parent.is_valid()) {
return parent->get_var(p_key, p_default);
return parent->get_var(p_name, p_default, p_complain);
} else {
if (p_complain) {
ERR_PRINT(vformat("Blackboard: Variable \"%s\" not found.", p_name));
}
return p_default;
}
}
void Blackboard::set_var(const Variant &p_key, const Variant &p_value) {
data[p_key] = p_value;
void Blackboard::set_var(const StringName &p_name, const Variant &p_value) {
if (data.has(p_name)) {
// Not checking type - allowing duck-typing.
data[p_name].set_value(p_value);
} else {
BBVariable var(p_value.get_type());
var.set_value(p_value);
data.insert(p_name, var);
}
}
bool Blackboard::has_var(const Variant &p_key) const {
return data.has(p_key) || (parent.is_valid() && parent->has_var(p_key));
bool Blackboard::has_var(const StringName &p_name) const {
return data.has(p_name) || (parent.is_valid() && parent->has_var(p_name));
}
void Blackboard::erase_var(const Variant &p_key) {
data.erase(p_key);
void Blackboard::erase_var(const StringName &p_name) {
data.erase(p_name);
}
void Blackboard::prefetch_nodepath_vars(Node *p_node) {
ERR_FAIL_COND(p_node == nullptr);
Array keys = data.keys();
Array values = data.values();
for (int i = 0; i < keys.size(); i++) {
if (values[i].get_type() == Variant::NODE_PATH) {
Node *fetched_node = p_node->get_node_or_null(values[i]);
if (fetched_node != nullptr) {
data[keys[i]] = fetched_node;
TypedArray<StringName> Blackboard::list_vars() const {
TypedArray<StringName> var_names;
var_names.resize(data.size());
int idx = 0;
for (const KeyValue<StringName, BBVariable> &kv : data) {
var_names[idx] = kv.key;
idx += 1;
}
return var_names;
}
void Blackboard::print_state() const {
Ref<Blackboard> bb{ this };
int scope_idx = 0;
while (bb.is_valid()) {
int i = 0;
String line = "Scope " + itos(scope_idx) + ": { ";
for (const KeyValue<StringName, BBVariable> &kv : bb->data) {
if (i > 0) {
line += ", ";
}
line += String(kv.key) + ": " + String(kv.value.get_value());
i++;
}
line += " }";
PRINT_LINE(line);
bb = bb->get_parent();
scope_idx++;
}
}
Dictionary Blackboard::get_vars_as_dict() const {
Dictionary dict;
for (const KeyValue<StringName, BBVariable> &kv : data) {
dict[kv.key] = kv.value.get_value();
}
return dict;
}
void Blackboard::populate_from_dict(const Dictionary &p_dictionary) {
Array keys = p_dictionary.keys();
for (int i = 0; i < keys.size(); i++) {
if (keys[i].get_type() == Variant::STRING_NAME || keys[i].get_type() == Variant::STRING) {
set_var(keys[i], p_dictionary[keys[i]]);
} else {
ERR_PRINT("Blackboard: Invalid key type in dictionary to populate blackboard. Must be StringName or String.");
}
}
}
void Blackboard::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data);
ClassDB::bind_method(D_METHOD("set_data", "p_data"), &Blackboard::set_data);
ClassDB::bind_method(D_METHOD("get_var", "p_key", "p_default"), &Blackboard::get_var, Variant());
ClassDB::bind_method(D_METHOD("set_var", "p_key", "p_value"), &Blackboard::set_var);
ClassDB::bind_method(D_METHOD("has_var", "p_key"), &Blackboard::has_var);
ClassDB::bind_method(D_METHOD("set_parent_scope", "p_blackboard"), &Blackboard::set_parent_scope);
ClassDB::bind_method(D_METHOD("get_parent_scope"), &Blackboard::get_parent_scope);
ClassDB::bind_method(D_METHOD("erase_var", "p_key"), &Blackboard::erase_var);
ClassDB::bind_method(D_METHOD("prefetch_nodepath_vars", "p_node"), &Blackboard::prefetch_nodepath_vars);
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
void Blackboard::bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create) {
if (!data.has(p_name)) {
if (p_create) {
data.insert(p_name, BBVariable());
} else {
ERR_FAIL_MSG("Blackboard: Can't bind variable that doesn't exist (var: " + p_name + ").");
}
}
data[p_name].bind(p_object, p_property);
}
void Blackboard::unbind_var(const StringName &p_name) {
ERR_FAIL_COND_MSG(!data.has(p_name), "Blackboard: Can't unbind variable that doesn't exist (var: " + p_name + ").");
data[p_name].unbind();
}
void Blackboard::assign_var(const StringName &p_name, const BBVariable &p_var) {
data.insert(p_name, p_var);
}
void Blackboard::link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create) {
if (!data.has(p_name)) {
if (p_create) {
data.insert(p_name, BBVariable());
} else {
ERR_FAIL_MSG("Blackboard: Can't link variable that doesn't exist (var: " + p_name + ").");
}
}
ERR_FAIL_COND_MSG(p_target_blackboard.is_null(), "Blackboard: Can't link variable to target blackboard that is null (var: " + p_name + ").");
ERR_FAIL_COND_MSG(!p_target_blackboard->data.has(p_target_var), "Blackboard: Can't link variable to non-existent target (var: " + p_name + ", target: " + p_target_var + ").");
data[p_name] = p_target_blackboard->data[p_target_var];
}
void Blackboard::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_var", "var_name", "default", "complain"), &Blackboard::get_var, DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_var", "var_name", "value"), &Blackboard::set_var);
ClassDB::bind_method(D_METHOD("has_var", "var_name"), &Blackboard::has_var);
ClassDB::bind_method(D_METHOD("set_parent", "blackboard"), &Blackboard::set_parent);
ClassDB::bind_method(D_METHOD("get_parent"), &Blackboard::get_parent);
ClassDB::bind_method(D_METHOD("erase_var", "var_name"), &Blackboard::erase_var);
ClassDB::bind_method(D_METHOD("clear"), &Blackboard::clear);
ClassDB::bind_method(D_METHOD("list_vars"), &Blackboard::list_vars);
ClassDB::bind_method(D_METHOD("print_state"), &Blackboard::print_state);
ClassDB::bind_method(D_METHOD("get_vars_as_dict"), &Blackboard::get_vars_as_dict);
ClassDB::bind_method(D_METHOD("populate_from_dict", "dictionary"), &Blackboard::populate_from_dict);
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
ClassDB::bind_method(D_METHOD("bind_var_to_property", "var_name", "object", "property", "create"), &Blackboard::bind_var_to_property, DEFVAL(false));
ClassDB::bind_method(D_METHOD("unbind_var", "var_name"), &Blackboard::unbind_var);
ClassDB::bind_method(D_METHOD("link_var", "var_name", "target_blackboard", "target_var", "create"), &Blackboard::link_var, DEFVAL(false));
}

View File

@ -1,7 +1,7 @@
/**
* blackboard.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -12,10 +12,11 @@
#ifndef BLACKBOARD_H
#define BLACKBOARD_H
#include "bb_variable.h"
#ifdef LIMBOAI_MODULE
#include "core/object/object.h"
#include "core/object/ref_counted.h"
#include "core/variant/dictionary.h"
#include "core/variant/variant.h"
#include "scene/main/node.h"
#endif // LIMBOAI_MODULE
@ -25,7 +26,7 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/dictionary.hpp>
#include <godot_cpp/templates/hash_map.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
@ -33,27 +34,40 @@ class Blackboard : public RefCounted {
GDCLASS(Blackboard, RefCounted);
private:
Dictionary data;
HashMap<StringName, BBVariable> data;
Ref<Blackboard> parent;
protected:
static void _bind_methods();
public:
void set_data(const Dictionary &p_value) { data = p_value; }
Dictionary get_data() const { return data; }
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
void set_parent_scope(const Ref<Blackboard> &p_blackboard) { parent = p_blackboard; }
Ref<Blackboard> get_parent_scope() const { return parent; }
public:
void set_parent(const Ref<Blackboard> &p_blackboard) { parent = p_blackboard; }
Ref<Blackboard> get_parent() const { return parent; }
Ref<Blackboard> top() const;
Variant get_var(const Variant &p_key, const Variant &p_default) const;
void set_var(const Variant &p_key, const Variant &p_value);
bool has_var(const Variant &p_key) const;
void erase_var(const Variant &p_key);
Variant get_var(const StringName &p_name, const Variant &p_default = Variant(), bool p_complain = true) const;
void set_var(const StringName &p_name, const Variant &p_value);
bool has_var(const StringName &p_name) const;
_FORCE_INLINE_ bool has_local_var(const StringName &p_name) const { return data.has(p_name); }
void erase_var(const StringName &p_name);
void clear() { data.clear(); }
TypedArray<StringName> list_vars() const;
void print_state() const;
void prefetch_nodepath_vars(Node *p_node);
Dictionary get_vars_as_dict() const;
void populate_from_dict(const Dictionary &p_dictionary);
void bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create = false);
void unbind_var(const StringName &p_name);
void assign_var(const StringName &p_name, const BBVariable &p_var);
void link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create = false);
};
#endif // BLACKBOARD_H
#endif // BLACKBOARD_H

View File

@ -0,0 +1,578 @@
/**
* blackboard_plan.cpp
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#include "blackboard_plan.h"
#include "../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "editor/editor_inspector.h"
#include "editor/editor_interface.h"
#elif LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/editor_inspector.hpp>
#include <godot_cpp/classes/editor_interface.hpp>
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#endif
bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) {
String name_str = p_name;
#ifdef TOOLS_ENABLED
// * Editor
if (var_map.has(p_name)) {
BBVariable &var = var_map[p_name];
var.set_value(p_value);
if (base.is_valid() && p_value == base->get_var(p_name).get_value()) {
// When user pressed reset property button in inspector...
var.reset_value_changed();
}
return true;
}
#endif // TOOLS_ENABLED
// * Mapping
if (name_str.begins_with("mapping/")) {
StringName mapped_var_name = name_str.get_slicec('/', 1);
StringName value = p_value;
bool prop_list_changed = false;
if (value == StringName()) {
if (parent_scope_mapping.has(mapped_var_name)) {
prop_list_changed = true;
parent_scope_mapping.erase(mapped_var_name);
}
} else {
if (!parent_scope_mapping.has(mapped_var_name)) {
prop_list_changed = true;
}
parent_scope_mapping[mapped_var_name] = value;
}
if (prop_list_changed) {
notify_property_list_changed();
}
return true;
}
// * Binding
if (name_str.begins_with("binding/")) {
StringName bound_var = name_str.get_slicec('/', 1);
NodePath value = p_value;
bool prop_list_changed = false;
if (value.is_empty()) {
if (property_bindings.has(bound_var)) {
prop_list_changed = true;
property_bindings.erase(bound_var);
}
} else {
if (!property_bindings.has(bound_var)) {
prop_list_changed = true;
}
property_bindings[bound_var] = value;
}
if (prop_list_changed) {
notify_property_list_changed();
}
}
// * Storage
if (name_str.begins_with("var/")) {
StringName var_name = name_str.get_slicec('/', 1);
String what = name_str.get_slicec('/', 2);
if (!var_map.has(var_name) && what == "name") {
add_var(var_name, BBVariable());
}
if (what == "name") {
// We don't store variable name with the variable.
} else if (what == "type") {
var_map[var_name].set_type((Variant::Type)(int)p_value);
} else if (what == "value") {
var_map[var_name].set_value(p_value);
} else if (what == "hint") {
var_map[var_name].set_hint((PropertyHint)(int)p_value);
} else if (what == "hint_string") {
var_map[var_name].set_hint_string(p_value);
} else if (what == "property_binding") {
property_bindings[var_name] = NodePath(p_value);
} else {
return false;
}
return true;
}
return false;
}
bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const {
String name_str = p_name;
#ifdef TOOLS_ENABLED
// * Editor
if (var_map.has(p_name)) {
if (has_mapping(p_name)) {
r_ret = "Mapped to " + LimboUtility::get_singleton()->decorate_var(parent_scope_mapping[p_name]);
} else if (has_property_binding(p_name)) {
const NodePath &binding = property_bindings[p_name];
Node *edited_node = Object::cast_to<Node>(EditorInterface::get_singleton()->get_inspector()->get_edited_object());
if (!edited_node) {
edited_node = SCENE_TREE()->get_edited_scene_root();
}
Node *bound_node = edited_node ? edited_node->get_node_or_null(binding) : nullptr;
String shortened_path;
if (bound_node) {
shortened_path = (String)bound_node->get_name() +
":" + (String)binding.get_concatenated_subnames();
} else {
shortened_path = (String)binding.get_name(binding.get_name_count() - 1) +
":" + (String)binding.get_concatenated_subnames();
}
r_ret = String::utf8("🔗 ") + shortened_path;
} else {
r_ret = var_map[p_name].get_value();
}
return true;
}
#endif // TOOLS_ENABLED
// * Mapping
if (name_str.begins_with("mapping/")) {
StringName mapped_var_name = name_str.get_slicec('/', 1);
ERR_FAIL_COND_V(mapped_var_name == StringName(), false);
if (has_mapping(mapped_var_name)) {
r_ret = parent_scope_mapping[mapped_var_name];
} else if (has_property_binding(mapped_var_name)) {
r_ret = RTR("Already bound to property.");
} else {
r_ret = StringName();
}
return true;
}
// * Binding
if (name_str.begins_with("binding/")) {
StringName bound_var = name_str.get_slicec('/', 1);
ERR_FAIL_COND_V(bound_var == StringName(), false);
if (has_property_binding(bound_var)) {
r_ret = property_bindings[bound_var];
} else if (has_mapping(bound_var)) {
r_ret = RTR("Already mapped to variable.");
} else {
r_ret = NodePath();
}
return true;
}
// * Storage
if (!name_str.begins_with("var/")) {
return false;
}
StringName var_name = name_str.get_slicec('/', 1);
String what = name_str.get_slicec('/', 2);
ERR_FAIL_COND_V(!var_map.has(var_name), false);
if (what == "name") {
r_ret = var_name;
} else if (what == "type") {
r_ret = var_map[var_name].get_type();
} else if (what == "value") {
r_ret = var_map[var_name].get_value();
} else if (what == "hint") {
r_ret = var_map[var_name].get_hint();
} else if (what == "hint_string") {
r_ret = var_map[var_name].get_hint_string();
}
return true;
}
void BlackboardPlan::_get_property_list(List<PropertyInfo> *p_list) const {
for (const Pair<StringName, BBVariable> &p : var_list) {
String var_name = p.first;
BBVariable var = p.second;
#ifdef TOOLS_ENABLED
// * Editor
if (!_is_var_nil(var) && !_is_var_private(var_name, var)) {
if (has_mapping(var_name) || has_property_binding(var_name)) {
p_list->push_back(PropertyInfo(Variant::STRING, var_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
} else {
p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR));
}
}
#endif // TOOLS_ENABLED
// * Storage
if (is_derived() && (!var.is_value_changed() || var.get_value() == base->var_map[var_name].get_value())) {
// Don't store variable if it's not modified in a derived plan.
// Variable is considered modified when it's marked as changed and its value is different from the base plan.
continue;
}
p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(var.get_type(), "var/" + var_name + "/value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/hint_string", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
// * Mapping
if (is_mapping_enabled()) {
p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "mapping/", PROPERTY_USAGE_GROUP));
for (const Pair<StringName, BBVariable> &p : var_list) {
if (_is_var_private(p.first, p.second)) {
continue;
}
if (unlikely(has_property_binding(p.first))) {
p_list->push_back(PropertyInfo(Variant::STRING, "mapping/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
} else {
// Serialize only non-empty mappings.
PropertyUsageFlags usage = has_mapping(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR;
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", usage));
}
}
}
// * Binding
p_list->push_back(PropertyInfo(Variant::NIL, "Binding", PROPERTY_HINT_NONE, "binding/", PROPERTY_USAGE_GROUP));
for (const Pair<StringName, BBVariable> &p : var_list) {
if (_is_var_nil(p.second) || _is_var_private(p.first, p.second)) {
continue;
}
if (unlikely(has_mapping(p.first))) {
p_list->push_back(PropertyInfo(Variant::STRING, "binding/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
} else {
PropertyUsageFlags usage = has_property_binding(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR;
// PROPERTY_HINT_LINK is used to signal that NodePath should point to a property.
// Our inspector plugin will know how to handle it.
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "binding/" + p.first, PROPERTY_HINT_LINK, itos(p.second.get_type()), usage));
}
}
}
bool BlackboardPlan::_property_can_revert(const StringName &p_name) const {
if (String(p_name).begins_with("mapping/")) {
return true;
}
return base.is_valid() && base->var_map.has(p_name);
}
bool BlackboardPlan::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (String(p_name).begins_with("mapping/")) {
r_property = StringName();
return true;
}
if (base->var_map.has(p_name)) {
r_property = base->var_map[p_name].get_value();
return true;
}
return false;
}
void BlackboardPlan::set_base_plan(const Ref<BlackboardPlan> &p_base) {
if (p_base == this) {
WARN_PRINT_ED("BlackboardPlan: Using same resource for derived blackboard plan is not supported.");
base.unref();
} else {
base = p_base;
}
sync_with_base_plan();
notify_property_list_changed();
}
void BlackboardPlan::set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider) {
parent_scope_plan_provider = p_parent_scope_plan_provider;
notify_property_list_changed();
}
bool BlackboardPlan::has_mapping(const StringName &p_name) const {
return is_mapping_enabled() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName();
}
void BlackboardPlan::set_property_binding(const StringName &p_name, const NodePath &p_path) {
property_bindings[p_name] = p_path;
emit_changed();
}
void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) {
prefetch_nodepath_vars = p_enable;
emit_changed();
}
bool BlackboardPlan::is_prefetching_nodepath_vars() const {
if (is_derived()) {
return base->is_prefetching_nodepath_vars();
} else {
return prefetch_nodepath_vars;
}
}
void BlackboardPlan::add_var(const StringName &p_name, const BBVariable &p_var) {
ERR_FAIL_COND(p_name == StringName());
ERR_FAIL_COND(var_map.has(p_name));
var_map.insert(p_name, p_var);
var_list.push_back(Pair<StringName, BBVariable>(p_name, p_var));
notify_property_list_changed();
emit_changed();
}
void BlackboardPlan::remove_var(const StringName &p_name) {
ERR_FAIL_COND(!var_map.has(p_name));
var_list.erase(Pair<StringName, BBVariable>(p_name, var_map[p_name]));
var_map.erase(p_name);
notify_property_list_changed();
emit_changed();
}
BBVariable BlackboardPlan::get_var(const StringName &p_name) {
ERR_FAIL_COND_V(!var_map.has(p_name), BBVariable());
return var_map.get(p_name);
}
Pair<StringName, BBVariable> BlackboardPlan::get_var_by_index(int p_index) {
Pair<StringName, BBVariable> ret;
ERR_FAIL_INDEX_V(p_index, (int)var_map.size(), ret);
return var_list.get(p_index);
}
TypedArray<StringName> BlackboardPlan::list_vars() const {
TypedArray<StringName> ret;
for (const Pair<StringName, BBVariable> &p : var_list) {
ret.append(p.first);
}
return ret;
}
StringName BlackboardPlan::get_var_name(const BBVariable &p_var) const {
for (const Pair<StringName, BBVariable> &p : var_list) {
if (p.second == p_var) {
return p.first;
}
}
return StringName();
}
bool BlackboardPlan::is_valid_var_name(const StringName &p_name) const {
String name_str = p_name;
if (name_str.begins_with("resource_")) {
return false;
}
return name_str.is_valid_identifier() && !var_map.has(p_name);
}
void BlackboardPlan::rename_var(const StringName &p_name, const StringName &p_new_name) {
if (p_name == p_new_name) {
return;
}
ERR_FAIL_COND(!is_valid_var_name(p_new_name));
ERR_FAIL_COND(!var_map.has(p_name));
ERR_FAIL_COND(var_map.has(p_new_name));
BBVariable var = var_map[p_name];
Pair<StringName, BBVariable> new_entry(p_new_name, var);
Pair<StringName, BBVariable> old_entry(p_name, var);
var_list.find(old_entry)->set(new_entry);
var_map.erase(p_name);
var_map.insert(p_new_name, var);
if (parent_scope_mapping.has(p_name)) {
parent_scope_mapping[p_new_name] = parent_scope_mapping[p_name];
parent_scope_mapping.erase(p_name);
}
notify_property_list_changed();
emit_changed();
}
void BlackboardPlan::move_var(int p_index, int p_new_index) {
ERR_FAIL_INDEX(p_index, (int)var_map.size());
ERR_FAIL_INDEX(p_new_index, (int)var_map.size());
if (p_index == p_new_index) {
return;
}
List<Pair<StringName, BBVariable>>::Element *E = var_list.front();
for (int i = 0; i < p_index; i++) {
E = E->next();
}
List<Pair<StringName, BBVariable>>::Element *E2 = var_list.front();
for (int i = 0; i < p_new_index; i++) {
E2 = E2->next();
}
var_list.move_before(E, E2);
if (p_new_index > p_index) {
var_list.move_before(E2, E);
}
notify_property_list_changed();
emit_changed();
}
void BlackboardPlan::sync_with_base_plan() {
if (base.is_null()) {
return;
}
bool changed = false;
// Sync variables with the base plan.
for (const Pair<StringName, BBVariable> &p : base->var_list) {
const StringName &base_name = p.first;
const BBVariable &base_var = p.second;
if (!var_map.has(base_name)) {
add_var(base_name, base_var.duplicate());
changed = true;
continue;
}
BBVariable var = var_map[base_name];
if (!var.is_same_prop_info(base_var)) {
var.copy_prop_info(base_var);
changed = true;
}
if ((!var.is_value_changed() && var.get_value() != base_var.get_value()) ||
(var.get_value().get_type() != base_var.get_type())) {
// Reset value according to base plan.
var.set_value(base_var.get_value());
var.reset_value_changed();
changed = true;
}
}
// Erase variables that do not exist in the base plan.
List<StringName> erase_list;
for (const Pair<StringName, BBVariable> &p : var_list) {
if (!base->has_var(p.first)) {
erase_list.push_back(p.first);
changed = true;
}
}
while (erase_list.size()) {
remove_var(erase_list.front()->get());
erase_list.pop_front();
}
// Sync order of variables.
// Glossary: E - element of current plan, B - element of base plan, F - element of current plan (used for forward search).
ERR_FAIL_COND(base->var_list.size() != var_list.size());
List<Pair<StringName, BBVariable>>::Element *B = base->var_list.front();
for (List<Pair<StringName, BBVariable>>::Element *E = var_list.front(); E; E = E->next()) {
if (E->get().first != B->get().first) {
List<Pair<StringName, BBVariable>>::Element *F = E->next();
while (F) {
if (F->get().first == B->get().first) {
var_list.move_before(F, E);
E = F;
break;
}
F = F->next();
}
}
B = B->next();
}
if (changed) {
notify_property_list_changed();
emit_changed();
}
}
Ref<Blackboard> BlackboardPlan::create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope, Node *p_prefetch_root_for_base_plan) {
ERR_FAIL_COND_V(p_prefetch_root == nullptr && prefetch_nodepath_vars, memnew(Blackboard));
Ref<Blackboard> bb = memnew(Blackboard);
bb->set_parent(p_parent_scope);
populate_blackboard(bb, true, p_prefetch_root, p_prefetch_root_for_base_plan);
return bb;
}
void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan) {
ERR_FAIL_COND(p_prefetch_root == nullptr && prefetch_nodepath_vars);
ERR_FAIL_COND(p_blackboard.is_null());
for (const Pair<StringName, BBVariable> &p : var_list) {
if (p_blackboard->has_local_var(p.first) && !overwrite) {
#ifdef DEBUG_ENABLED
Variant::Type existing_type = p_blackboard->get_var(p.first).get_type();
Variant::Type planned_type = p.second.get_type();
if (existing_type != planned_type && existing_type != Variant::NIL && planned_type != Variant::NIL && !(existing_type == Variant::OBJECT && planned_type == Variant::NODE_PATH)) {
WARN_PRINT(vformat("BlackboardPlan: Not overwriting %s as it already exists in the blackboard, but it has a different type than planned (%s vs %s). File: %s",
LimboUtility::get_singleton()->decorate_var(p.first), Variant::get_type_name(existing_type), Variant::get_type_name(planned_type), get_path()));
}
#endif
continue;
}
bool is_bound = has_property_binding(p.first) || (is_derived() && get_base_plan()->has_property_binding(p.first));
bool has_mapping = parent_scope_mapping.has(p.first);
bool do_prefetch = !is_bound && !has_mapping && prefetch_nodepath_vars;
// Add a variable duplicate to the blackboard, optionally with NodePath prefetch.
BBVariable var = p.second.duplicate(true);
if (unlikely(do_prefetch && p.second.get_type() == Variant::NODE_PATH)) {
Node *prefetch_root = !p_prefetch_root_for_base_plan || !is_derived() || is_derived_var_changed(p.first) ? p_prefetch_root : p_prefetch_root_for_base_plan;
Node *n = prefetch_root->get_node_or_null(p.second.get_value());
if (n != nullptr) {
var.set_value(n);
} else {
ERR_PRINT(vformat("BlackboardPlan: Prefetch failed for variable $%s with value: %s", p.first, p.second.get_value()));
var.set_value(Variant());
}
}
p_blackboard->assign_var(p.first, var);
if (has_mapping) {
StringName target_var = parent_scope_mapping[p.first];
if (target_var != StringName()) {
ERR_CONTINUE_MSG(p_blackboard->get_parent().is_null(), vformat("BlackboardPlan: Cannot link variable %s to parent scope because the parent scope is not set.", LimboUtility::get_singleton()->decorate_var(p.first)));
p_blackboard->link_var(p.first, p_blackboard->get_parent(), target_var);
}
} else if (is_bound) {
// Bind variable to a property of a scene node.
NodePath binding_path;
Node *binding_root;
if (has_property_binding(p.first)) {
binding_path = property_bindings[p.first];
binding_root = p_prefetch_root;
} else {
binding_path = get_base_plan()->property_bindings[p.first];
binding_root = p_prefetch_root_for_base_plan;
}
ERR_CONTINUE_MSG(binding_path.get_subname_count() != 1, vformat("BlackboardPlan: Can't bind variable %s using property path that contains multiple sub-names: %s", LimboUtility::get_singleton()->decorate_var(p.first), binding_path));
NodePath node_path{ binding_path.get_concatenated_names() };
StringName prop_name = binding_path.get_subname(0);
// TODO: Implement binding for base plan as well.
Node *n = binding_root->get_node_or_null(node_path);
ERR_CONTINUE_MSG(n == nullptr, vformat("BlackboardPlan: Binding failed for variable %s using property path: %s", LimboUtility::get_singleton()->decorate_var(p.first), binding_path));
var.bind(n, prop_name);
}
}
}
void BlackboardPlan::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "enable"), &BlackboardPlan::set_prefetch_nodepath_vars);
ClassDB::bind_method(D_METHOD("is_prefetching_nodepath_vars"), &BlackboardPlan::is_prefetching_nodepath_vars);
ClassDB::bind_method(D_METHOD("set_base_plan", "blackboard_plan"), &BlackboardPlan::set_base_plan);
ClassDB::bind_method(D_METHOD("get_base_plan"), &BlackboardPlan::get_base_plan);
ClassDB::bind_method(D_METHOD("is_derived"), &BlackboardPlan::is_derived);
ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan);
ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider);
ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider);
ClassDB::bind_method(D_METHOD("create_blackboard", "prefetch_root", "parent_scope", "prefetch_root_for_base_plan"), &BlackboardPlan::create_blackboard, DEFVAL(Ref<Blackboard>()), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "prefetch_root", "prefetch_root_for_base_plan"), &BlackboardPlan::populate_blackboard, DEFVAL(Variant()));
// To avoid cluttering the member namespace, we do not export unnecessary properties in this class.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_prefetch_nodepath_vars", "is_prefetching_nodepath_vars");
}
BlackboardPlan::BlackboardPlan() {
}

View File

@ -0,0 +1,111 @@
/**
* blackboard_plan.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BLACKBOARD_PLAN_H
#define BLACKBOARD_PLAN_H
#include "bb_variable.h"
#include "blackboard.h"
#ifdef LIMBOAI_MODULE
#include "core/io/resource.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/resource.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
class BlackboardPlan : public Resource {
GDCLASS(BlackboardPlan, Resource);
private:
List<Pair<StringName, BBVariable>> var_list;
HashMap<StringName, BBVariable> var_map;
// When base is not null, the plan is considered to be derived from the base plan.
// A derived plan can only have variables that exist in the base plan,
// and only the values can be different in those variables.
// The derived plan is synced with the base plan to maintain consistency.
Ref<BlackboardPlan> base;
// Mapping between variables in this plan and their parent scope names.
// Used for linking variables to their parent scope counterparts upon Blackboard creation/population.
HashMap<StringName, StringName> parent_scope_mapping;
// Fetcher function for the parent scope plan. Function should return a Ref<BlackboardPlan>.
// Used in the inspector: enables mapping feature when set.
Callable parent_scope_plan_provider;
// Bindings to properties in the scene to which this plan belongs.
HashMap<StringName, NodePath> property_bindings;
bool property_binding_enabled = false;
// If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population).
bool prefetch_nodepath_vars = true;
_FORCE_INLINE_ bool _is_var_nil(const BBVariable &p_var) const { return p_var.get_type() == Variant::NIL; }
_FORCE_INLINE_ bool _is_var_private(const String &p_name, const BBVariable &p_var) const { return is_derived() && p_name.begins_with("_"); }
protected:
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
public:
void set_base_plan(const Ref<BlackboardPlan> &p_base);
Ref<BlackboardPlan> get_base_plan() const { return base; }
void set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider);
Callable get_parent_scope_plan_provider() const { return parent_scope_plan_provider; }
bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid() && (parent_scope_plan_provider.call() != Ref<BlackboardPlan>()); }
bool has_mapping(const StringName &p_name) const;
bool has_property_binding(const StringName &p_name) const { return property_bindings.has(p_name); }
void set_property_binding(const StringName &p_name, const NodePath &p_path);
NodePath get_property_binding(const StringName &p_name) const { return property_bindings.has(p_name) ? property_bindings[p_name] : NodePath(); }
void set_prefetch_nodepath_vars(bool p_enable);
bool is_prefetching_nodepath_vars() const;
void add_var(const StringName &p_name, const BBVariable &p_var);
void remove_var(const StringName &p_name);
BBVariable get_var(const StringName &p_name);
Pair<StringName, BBVariable> get_var_by_index(int p_index);
_FORCE_INLINE_ bool has_var(const StringName &p_name) { return var_map.has(p_name); }
_FORCE_INLINE_ bool is_empty() const { return var_map.is_empty(); }
int get_var_count() const { return var_map.size(); }
TypedArray<StringName> list_vars() const;
StringName get_var_name(const BBVariable &p_var) const;
bool is_valid_var_name(const StringName &p_name) const;
void rename_var(const StringName &p_name, const StringName &p_new_name);
void move_var(int p_index, int p_new_index);
void sync_with_base_plan();
_FORCE_INLINE_ bool is_derived() const { return base.is_valid(); }
_FORCE_INLINE_ bool is_derived_var_changed(const StringName &p_name) const { return base.is_valid() && var_map.has(p_name) && var_map[p_name].is_value_changed(); }
Ref<Blackboard> create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope = Ref<Blackboard>(), Node *p_prefetch_root_for_base_plan = nullptr);
void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan = nullptr);
BlackboardPlan();
};
#endif // BLACKBOARD_PLAN_H

View File

@ -1,7 +1,7 @@
/**
* behavior_tree.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -11,6 +11,8 @@
#include "behavior_tree.h"
#include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h"
#include "core/object/class_db.h"
@ -22,6 +24,44 @@
#include "godot_cpp/core/error_macros.hpp"
#endif // ! LIMBOAI_GDEXTENSION
void BehaviorTree::set_description(const String &p_value) {
description = p_value;
emit_changed();
}
void BehaviorTree::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
if (blackboard_plan == p_plan) {
return;
}
if (Engine::get_singleton()->is_editor_hint() && blackboard_plan.is_valid() &&
blackboard_plan->is_connected(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed))) {
blackboard_plan->disconnect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
}
blackboard_plan = p_plan;
if (blackboard_plan.is_null()) {
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
}
if (Engine::get_singleton()->is_editor_hint()) {
blackboard_plan->connect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
}
_plan_changed();
}
void BehaviorTree::set_root_task(const Ref<BTTask> &p_value) {
#ifdef TOOLS_ENABLED
_unset_editor_behavior_tree_hint();
#endif // TOOLS_ENABLED
root_task = p_value;
#ifdef TOOLS_ENABLED
_set_editor_behavior_tree_hint();
#endif // TOOLS_ENABLED
emit_changed();
}
Ref<BehaviorTree> BehaviorTree::clone() const {
Ref<BehaviorTree> copy = duplicate(false);
copy->set_path("");
@ -37,22 +77,63 @@ void BehaviorTree::copy_other(const Ref<BehaviorTree> &p_other) {
root_task = p_other->get_root_task();
}
Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const {
ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task.");
Ref<BTTask> inst = root_task->clone();
inst->initialize(p_agent, p_blackboard);
return inst;
Ref<BTInstance> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root) const {
ERR_FAIL_COND_V_MSG(root_task.is_null(), nullptr, "BehaviorTree: Instantiation failed - BT has no valid root task.");
ERR_FAIL_NULL_V_MSG(p_agent, nullptr, "BehaviorTree: Instantiation failed - agent can't be null.");
ERR_FAIL_NULL_V_MSG(p_instance_owner, nullptr, "BehaviorTree: Instantiation failed -- instance owner can't be null.");
ERR_FAIL_COND_V_MSG(p_blackboard.is_null(), nullptr, "BehaviorTree: Instantiation failed - blackboard can't be null.");
Node *scene_root = p_custom_scene_root ? p_custom_scene_root : p_instance_owner->get_owner();
ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - unable to establish scene root. This is likely due to the instance owner not being owned by a scene node and custom_scene_root being null.");
Ref<BTTask> root_copy = root_task->clone();
root_copy->initialize(p_agent, p_blackboard, scene_root);
return BTInstance::create(root_copy, get_path(), p_instance_owner);
}
void BehaviorTree::_plan_changed() {
emit_signal(LW_NAME(plan_changed));
emit_changed();
}
#ifdef TOOLS_ENABLED
void BehaviorTree::_set_editor_behavior_tree_hint() {
if (root_task.is_valid()) {
root_task->data.behavior_tree_id = this->get_instance_id();
}
}
void BehaviorTree::_unset_editor_behavior_tree_hint() {
if (root_task.is_valid()) {
root_task->data.behavior_tree_id = ObjectID();
}
}
#endif // TOOLS_ENABLED
void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_description", "p_value"), &BehaviorTree::set_description);
ClassDB::bind_method(D_METHOD("set_description", "description"), &BehaviorTree::set_description);
ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description);
ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task);
ClassDB::bind_method(D_METHOD("set_blackboard_plan", "plan"), &BehaviorTree::set_blackboard_plan);
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BehaviorTree::get_blackboard_plan);
ClassDB::bind_method(D_METHOD("set_root_task", "task"), &BehaviorTree::set_root_task);
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
ClassDB::bind_method(D_METHOD("copy_other", "p_other"), &BehaviorTree::copy_other);
ClassDB::bind_method(D_METHOD("instantiate", "p_agent", "p_blackboard"), &BehaviorTree::instantiate);
ClassDB::bind_method(D_METHOD("copy_other", "other"), &BehaviorTree::copy_other);
ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard", "instance_owner", "custom_scene_root"), &BehaviorTree::instantiate, DEFVAL(Variant()));
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_task", PROPERTY_HINT_RESOURCE_TYPE, "BTTask", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_root_task", "get_root_task");
ADD_SIGNAL(MethodInfo("plan_changed"));
}
BehaviorTree::BehaviorTree() {
}
BehaviorTree::~BehaviorTree() {
if (Engine::get_singleton()->is_editor_hint() && blackboard_plan.is_valid() &&
blackboard_plan->is_connected(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed))) {
blackboard_plan->disconnect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
}
}

View File

@ -1,7 +1,7 @@
/**
* behavior_tree.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -12,11 +12,12 @@
#ifndef BEHAVIOR_TREE_H
#define BEHAVIOR_TREE_H
#include "../blackboard/blackboard_plan.h"
#include "bt_instance.h"
#include "tasks/bt_task.h"
#ifdef LIMBOAI_MODULE
#include "core/io/resource.h"
#include "modules/limboai/blackboard/blackboard.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
@ -29,31 +30,43 @@ class BehaviorTree : public Resource {
private:
String description;
Ref<BlackboardPlan> blackboard_plan;
Ref<BTTask> root_task;
void _plan_changed();
#ifdef TOOLS_ENABLED
void _set_editor_behavior_tree_hint();
void _unset_editor_behavior_tree_hint();
#endif // TOOLS_ENABLED
protected:
static void _bind_methods();
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
public:
#ifdef LIMBOAI_MODULE
virtual bool editor_can_reload_from_file() override { return false; }
#endif
void set_description(String p_value) {
description = p_value;
emit_changed();
}
void set_description(const String &p_value);
String get_description() const { return description; }
void set_root_task(const Ref<BTTask> &p_value) {
root_task = p_value;
emit_changed();
}
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
void set_root_task(const Ref<BTTask> &p_value);
Ref<BTTask> get_root_task() const { return root_task; }
Ref<BehaviorTree> clone() const;
void copy_other(const Ref<BehaviorTree> &p_other);
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
Ref<BTInstance> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root = nullptr) const;
BehaviorTree();
~BehaviorTree();
};
#endif // BEHAVIOR_TREE_H

156
bt/bt_instance.cpp Normal file
View File

@ -0,0 +1,156 @@
/**
* bt_instance.cpp
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#include "bt_instance.h"
#include "../editor/debugger/limbo_debugger.h"
#include "behavior_tree.h"
#ifdef LIMBOAI_MODULE
#include "core/os/time.h"
#include "main/performance.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/performance.hpp>
#include <godot_cpp/classes/time.hpp>
#endif
Ref<BTInstance> BTInstance::create(Ref<BTTask> p_root_task, String p_source_bt_path, Node *p_owner_node) {
ERR_FAIL_COND_V(p_root_task.is_null(), nullptr);
ERR_FAIL_NULL_V(p_owner_node, nullptr);
Ref<BTInstance> inst;
inst.instantiate();
inst->root_task = p_root_task;
inst->owner_node_id = p_owner_node->get_instance_id();
inst->source_bt_path = p_source_bt_path;
return inst;
}
BT::Status BTInstance::update(double p_delta) {
ERR_FAIL_COND_V(!root_task.is_valid(), BT::FRESH);
#ifdef DEBUG_ENABLED
double start = Time::get_singleton()->get_ticks_usec();
#endif
const Ref<BTInstance> keep_alive{ this }; // keep instance alive until update is finished
last_status = root_task->execute(p_delta);
emit_signal(LW_NAME(updated), last_status);
#ifdef DEBUG_ENABLED
double end = Time::get_singleton()->get_ticks_usec();
update_time_acc += (end - start);
update_time_n += 1.0;
#endif
return last_status;
}
void BTInstance::set_monitor_performance(bool p_monitor) {
#ifdef DEBUG_ENABLED
monitor_performance = p_monitor;
if (monitor_performance) {
_add_custom_monitor();
} else {
_remove_custom_monitor();
}
#endif
}
bool BTInstance::get_monitor_performance() const {
#ifdef DEBUG_ENABLED
return monitor_performance;
#else
return false;
#endif
}
void BTInstance::register_with_debugger() {
#ifdef DEBUG_ENABLED
if (LimboDebugger::get_singleton()->is_active()) {
LimboDebugger::get_singleton()->register_bt_instance(get_instance_id());
}
#endif
}
void BTInstance::unregister_with_debugger() {
#ifdef DEBUG_ENABLED
if (LimboDebugger::get_singleton() && LimboDebugger::get_singleton()->is_active()) {
LimboDebugger::get_singleton()->unregister_bt_instance(get_instance_id());
}
#endif
}
#ifdef DEBUG_ENABLED
double BTInstance::_get_mean_update_time_msec_and_reset() {
if (update_time_n) {
double mean_time_msec = (update_time_acc * 0.001) / update_time_n;
update_time_acc = 0.0;
update_time_n = 0.0;
return mean_time_msec;
}
return 0.0;
}
void BTInstance::_add_custom_monitor() {
ERR_FAIL_NULL(get_owner_node());
ERR_FAIL_COND(root_task.is_null());
ERR_FAIL_NULL(root_task->get_agent());
if (monitor_id == StringName()) {
monitor_id = vformat("LimboAI/update_ms|%s_%s_%s", root_task->get_agent()->get_name(), get_owner_node()->get_name(),
String(itos(get_instance_id())).md5_text().substr(0, 4));
}
if (!Performance::get_singleton()->has_custom_monitor(monitor_id)) {
PERFORMANCE_ADD_CUSTOM_MONITOR(monitor_id, callable_mp(this, &BTInstance::_get_mean_update_time_msec_and_reset));
}
}
void BTInstance::_remove_custom_monitor() {
if (monitor_id != StringName() && Performance::get_singleton()->has_custom_monitor(monitor_id)) {
Performance::get_singleton()->remove_custom_monitor(monitor_id);
}
}
#endif // * DEBUG_ENABLED
void BTInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_task"), &BTInstance::get_root_task);
ClassDB::bind_method(D_METHOD("get_owner_node"), &BTInstance::get_owner_node);
ClassDB::bind_method(D_METHOD("get_last_status"), &BTInstance::get_last_status);
ClassDB::bind_method(D_METHOD("get_source_bt_path"), &BTInstance::get_source_bt_path);
ClassDB::bind_method(D_METHOD("get_agent"), &BTInstance::get_agent);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTInstance::get_blackboard);
ClassDB::bind_method(D_METHOD("is_instance_valid"), &BTInstance::is_instance_valid);
ClassDB::bind_method(D_METHOD("set_monitor_performance", "monitor"), &BTInstance::set_monitor_performance);
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTInstance::get_monitor_performance);
ClassDB::bind_method(D_METHOD("update", "delta"), &BTInstance::update);
ClassDB::bind_method(D_METHOD("register_with_debugger"), &BTInstance::register_with_debugger);
ClassDB::bind_method(D_METHOD("unregister_with_debugger"), &BTInstance::unregister_with_debugger);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "status")));
ADD_SIGNAL(MethodInfo("freed"));
}
BTInstance::~BTInstance() {
emit_signal(LW_NAME(freed));
#ifdef DEBUG_ENABLED
_remove_custom_monitor();
unregister_with_debugger();
#endif
}

68
bt/bt_instance.h Normal file
View File

@ -0,0 +1,68 @@
/**
* bt_instance.h
* =============================================================================
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BT_INSTANCE_H
#define BT_INSTANCE_H
#include "tasks/bt_task.h"
class BTInstance : public RefCounted {
GDCLASS(BTInstance, RefCounted);
private:
Ref<BTTask> root_task;
uint64_t owner_node_id = 0;
String source_bt_path;
BT::Status last_status = BT::FRESH;
#ifdef DEBUG_ENABLED
bool monitor_performance = false;
StringName monitor_id;
double update_time_acc = 0.0;
double update_time_n = 0.0;
double _get_mean_update_time_msec_and_reset();
void _add_custom_monitor();
void _remove_custom_monitor();
#endif // * DEBUG_ENABLED
protected:
static void _bind_methods();
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
public:
_FORCE_INLINE_ Ref<BTTask> get_root_task() const { return root_task; }
_FORCE_INLINE_ Node *get_owner_node() const { return owner_node_id ? Object::cast_to<Node>(OBJECT_DB_GET_INSTANCE(owner_node_id)) : nullptr; }
_FORCE_INLINE_ BT::Status get_last_status() const { return last_status; }
_FORCE_INLINE_ String get_source_bt_path() const { return source_bt_path; }
_FORCE_INLINE_ Node *get_agent() const { return root_task.is_valid() ? root_task->get_agent() : nullptr; }
_FORCE_INLINE_ Ref<Blackboard> get_blackboard() const { return root_task.is_valid() ? root_task->get_blackboard() : Ref<Blackboard>(); }
_FORCE_INLINE_ bool is_instance_valid() const { return root_task.is_valid(); }
BT::Status update(double p_delta);
void set_monitor_performance(bool p_monitor);
bool get_monitor_performance() const;
void register_with_debugger();
void unregister_with_debugger();
static Ref<BTInstance> create(Ref<BTTask> p_root_task, String p_source_bt_path, Node *p_owner_node);
BTInstance() = default;
~BTInstance();
};
#endif // BT_INSTANCE_H

View File

@ -1,7 +1,7 @@
/**
* bt_player.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -11,7 +11,6 @@
#include "bt_player.h"
#include "../editor/debugger/limbo_debugger.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_string_names.h"
@ -43,33 +42,104 @@
VARIANT_ENUM_CAST(BTPlayer::UpdateMode);
void BTPlayer::_load_tree() {
void BTPlayer::_instantiate_bt() {
bt_instance.unref();
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Initialization failed - needs a valid behavior tree.");
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Initialization failed - behavior tree has no valid root task.");
Node *agent = GET_NODE(this, agent_node);
ERR_FAIL_NULL_MSG(agent, vformat("BTPlayer: Initialization failed - can't get agent with path '%s'.", agent_node));
Node *scene_root = _get_scene_root();
ERR_FAIL_COND_MSG(scene_root == nullptr,
"BTPlayer: Initialization failed - unable to establish scene root. This is likely due to BTPlayer not being owned by a scene node. Check BTPlayer.set_scene_root_hint().");
bt_instance = behavior_tree->instantiate(agent, blackboard, this, scene_root);
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTPlayer: Failed to instantiate behavior tree.");
#ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
bt_instance->set_monitor_performance(monitor_performance);
bt_instance->register_with_debugger();
#endif // DEBUG_ENABLED
}
void BTPlayer::_update_blackboard_plan() {
if (blackboard_plan.is_null()) {
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
} else if (!RESOURCE_IS_BUILT_IN(blackboard_plan)) {
WARN_PRINT_ED("BTPlayer: Using external resource for derived blackboard plan is not supported. Converted to built-in resource.");
blackboard_plan = blackboard_plan->duplicate();
}
#endif
tree_instance.unref();
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Needs a valid behavior tree.");
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Behavior tree has no valid root task.");
if (prefetch_nodepath_vars == true) {
blackboard->prefetch_nodepath_vars(this);
blackboard_plan->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
}
void BTPlayer::_initialize() {
if (blackboard.is_null()) {
blackboard = Ref<Blackboard>(memnew(Blackboard));
}
tree_instance = behavior_tree->instantiate(get_owner(), blackboard);
if (blackboard_plan.is_valid()) {
// Don't overwrite existing blackboard values as they may be initialized from code.
blackboard_plan->populate_blackboard(blackboard, false, this, _get_scene_root());
}
if (behavior_tree.is_valid()) {
_instantiate_bt();
}
}
void BTPlayer::set_bt_instance(const Ref<BTInstance> &p_bt_instance) {
ERR_FAIL_COND_MSG(p_bt_instance.is_null(), "BTPlayer: Failed to set behavior tree instance - instance is null.");
ERR_FAIL_COND_MSG(!p_bt_instance->is_instance_valid(), "BTPlayer: Failed to set behavior tree instance - instance is not valid.");
bt_instance = p_bt_instance;
blackboard = p_bt_instance->get_blackboard();
agent_node = p_bt_instance->get_agent()->get_path();
#ifdef DEBUG_ENABLED
if (IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
bt_instance->set_monitor_performance(monitor_performance);
bt_instance->register_with_debugger();
#endif // DEBUG_ENABLED
blackboard_plan.unref();
behavior_tree.unref();
}
void BTPlayer::set_scene_root_hint(Node *p_scene_root) {
ERR_FAIL_NULL_MSG(p_scene_root, "BTPlayer: Failed to set scene root hint - scene root is null.");
if (bt_instance.is_valid()) {
ERR_PRINT("BTPlayer: Scene root hint shouldn't be set after the behavior tree is instantiated. This change will not affect the current behavior tree instance.");
}
#endif
scene_root_hint = p_scene_root;
}
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
behavior_tree = p_tree;
if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) {
_load_tree();
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
}
if (p_tree.is_valid()) {
p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
}
behavior_tree = p_tree;
_update_blackboard_plan();
} else {
behavior_tree = p_tree;
if (get_owner() && is_inside_tree()) {
_update_blackboard_plan();
_initialize();
}
}
}
void BTPlayer::set_agent_node(const NodePath &p_agent_node) {
agent_node = p_agent_node;
if (bt_instance.is_valid()) {
ERR_PRINT("BTPlayer: Agent node cannot be set after the behavior tree is instantiated. This change will not affect the behavior tree instance.");
}
}
void BTPlayer::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
blackboard_plan = p_plan;
_update_blackboard_plan();
}
void BTPlayer::set_update_mode(UpdateMode p_mode) {
update_mode = p_mode;
set_active(active);
@ -84,70 +154,38 @@ void BTPlayer::set_active(bool p_active) {
}
void BTPlayer::update(double p_delta) {
if (!tree_instance.is_valid()) {
if (!bt_instance.is_valid()) {
ERR_PRINT_ONCE(vformat("BTPlayer doesn't have a behavior tree with a valid root task to execute (owner: %s)", get_owner()));
return;
}
#ifdef DEBUG_ENABLED
double start = GET_TICKS_USEC();
#endif
if (active) {
last_status = tree_instance->execute(p_delta);
emit_signal(LimboStringNames::get_singleton()->updated, last_status);
if (last_status == BTTask::SUCCESS || last_status == BTTask::FAILURE) {
emit_signal(LimboStringNames::get_singleton()->behavior_tree_finished, last_status);
BT::Status status = bt_instance->update(p_delta);
emit_signal(LW_NAME(updated), status);
#ifndef DISABLE_DEPRECATED
if (status == BTTask::SUCCESS || status == BTTask::FAILURE) {
emit_signal(LW_NAME(behavior_tree_finished), status);
}
#endif // DISABLE_DEPRECATED
}
#ifdef DEBUG_ENABLED
double end = GET_TICKS_USEC();
update_time_acc += (end - start);
update_time_n += 1.0;
#endif
}
void BTPlayer::restart() {
tree_instance->abort();
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTPlayer: Restart failed - no valid tree instance. Make sure the BTPlayer has a valid behavior tree with a valid root task.");
bt_instance->get_root_task()->abort();
set_active(true);
}
#ifdef DEBUG_ENABLED
void BTPlayer::_set_monitor_performance(bool p_monitor_performance) {
void BTPlayer::set_monitor_performance(bool p_monitor_performance) {
monitor_performance = p_monitor_performance;
if (!get_owner()) {
return;
}
Performance *perf = Performance::get_singleton();
if (monitor_performance) {
if (monitor_id == StringName()) {
monitor_id = vformat("limboai/update_ms|%s_%s_%s", get_owner()->get_name(), get_name(),
String(itos(get_instance_id())).md5_text().substr(0, 4));
}
if (!perf->has_custom_monitor(monitor_id)) {
PERFORMANCE_ADD_CUSTOM_MONITOR(monitor_id, callable_mp(this, &BTPlayer::_get_mean_update_time_msec));
}
} else if (monitor_id != StringName() && perf->has_custom_monitor(monitor_id)) {
perf->remove_custom_monitor(monitor_id);
#ifdef DEBUG_ENABLED
if (bt_instance.is_valid()) {
bt_instance->set_monitor_performance(monitor_performance);
}
#endif
}
double BTPlayer::_get_mean_update_time_msec() {
if (update_time_n) {
double mean_time_msec = (update_time_acc * 0.001) / update_time_n;
update_time_acc = 0.0;
update_time_n = 0.0;
return mean_time_msec;
}
return 0.0;
}
#endif // ! DEBUG_ENABLED
void BTPlayer::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_PROCESS: {
@ -160,72 +198,85 @@ void BTPlayer::_notification(int p_notification) {
} break;
case NOTIFICATION_READY: {
if (!Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid()) {
_load_tree();
}
set_active(active);
#ifdef DEBUG_ENABLED
_set_monitor_performance(monitor_performance);
#endif
_initialize();
} else {
_update_blackboard_plan();
}
set_active(active);
} break;
#ifdef DEBUG_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
#ifdef DEBUG_ENABLED
if (bt_instance.is_valid()) {
bt_instance->set_monitor_performance(monitor_performance);
bt_instance->register_with_debugger();
}
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_EXIT_TREE: {
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
#ifdef DEBUG_ENABLED
if (bt_instance.is_valid()) {
bt_instance->set_monitor_performance(false);
bt_instance->unregister_with_debugger();
}
#endif // DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
}
}
} break;
#endif // DEBUG_ENABLED
}
}
void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_behavior_tree", "p_path"), &BTPlayer::set_behavior_tree);
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTPlayer::set_behavior_tree);
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTPlayer::get_behavior_tree);
ClassDB::bind_method(D_METHOD("set_update_mode", "p_mode"), &BTPlayer::set_update_mode);
ClassDB::bind_method(D_METHOD("set_agent_node", "agent_node"), &BTPlayer::set_agent_node);
ClassDB::bind_method(D_METHOD("get_agent_node"), &BTPlayer::get_agent_node);
ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &BTPlayer::set_update_mode);
ClassDB::bind_method(D_METHOD("get_update_mode"), &BTPlayer::get_update_mode);
ClassDB::bind_method(D_METHOD("set_active", "p_active"), &BTPlayer::set_active);
ClassDB::bind_method(D_METHOD("set_active", "active"), &BTPlayer::set_active);
ClassDB::bind_method(D_METHOD("get_active"), &BTPlayer::get_active);
ClassDB::bind_method(D_METHOD("set_blackboard", "p_blackboard"), &BTPlayer::set_blackboard);
ClassDB::bind_method(D_METHOD("set_blackboard", "blackboard"), &BTPlayer::set_blackboard);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTPlayer::get_blackboard);
ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "p_value"), &BTPlayer::set_prefetch_nodepath_vars);
ClassDB::bind_method(D_METHOD("get_prefetch_nodepath_vars"), &BTPlayer::get_prefetch_nodepath_vars);
ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &BTPlayer::_set_blackboard_data);
ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &BTPlayer::_get_blackboard_data);
ClassDB::bind_method(D_METHOD("set_blackboard_plan", "plan"), &BTPlayer::set_blackboard_plan);
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BTPlayer::get_blackboard_plan);
ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update);
ClassDB::bind_method(D_METHOD("set_monitor_performance", "enable"), &BTPlayer::set_monitor_performance);
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTPlayer::get_monitor_performance);
ClassDB::bind_method(D_METHOD("update", "delta"), &BTPlayer::update);
ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart);
ClassDB::bind_method(D_METHOD("get_last_status"), &BTPlayer::get_last_status);
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTPlayer::get_bt_instance);
ClassDB::bind_method(D_METHOD("set_bt_instance", "bt_instance"), &BTPlayer::set_bt_instance);
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTPlayer::set_scene_root_hint);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent_node"), "set_agent_node", "get_agent_node");
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT | PROPERTY_USAGE_ALWAYS_DUPLICATE), "set_blackboard_plan", "get_blackboard_plan");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
BIND_ENUM_CONSTANT(IDLE);
BIND_ENUM_CONSTANT(PHYSICS);
BIND_ENUM_CONSTANT(MANUAL);
ADD_SIGNAL(MethodInfo("behavior_tree_finished", PropertyInfo(Variant::INT, "p_status")));
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "p_status")));
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "status")));
#ifdef DEBUG_ENABLED
ClassDB::bind_method(D_METHOD("_set_monitor_performance", "p_value"), &BTPlayer::_set_monitor_performance);
ClassDB::bind_method(D_METHOD("_get_monitor_performance"), &BTPlayer::_get_monitor_performance);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "_set_monitor_performance", "_get_monitor_performance");
#endif // DEBUG_ENABLED
#ifndef DISABLE_DEPRECATED
ADD_SIGNAL(MethodInfo("behavior_tree_finished", PropertyInfo(Variant::INT, "status")));
#endif
}
BTPlayer::BTPlayer() {
blackboard = Ref<Blackboard>(memnew(Blackboard));
agent_node = LW_NAME(node_pp);
}
BTPlayer::~BTPlayer() {

View File

@ -1,7 +1,7 @@
/**
* bt_player.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -13,7 +13,9 @@
#define BT_PLAYER_H
#include "../blackboard/blackboard.h"
#include "../blackboard/blackboard_plan.h"
#include "behavior_tree.h"
#include "bt_instance.h"
#include "tasks/bt_task.h"
#ifdef LIMBOAI_MODULE
@ -36,28 +38,40 @@ public:
private:
Ref<BehaviorTree> behavior_tree;
NodePath agent_node;
Ref<BlackboardPlan> blackboard_plan;
UpdateMode update_mode = UpdateMode::PHYSICS;
bool active = true;
Ref<Blackboard> blackboard;
bool prefetch_nodepath_vars = true;
int last_status = -1;
Node *scene_root_hint = nullptr;
bool monitor_performance = false;
Ref<BTTask> tree_instance;
Ref<BTInstance> bt_instance;
void _load_tree();
void _instantiate_bt();
void _update_blackboard_plan();
void _initialize();
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
protected:
static void _bind_methods();
void _set_blackboard_data(Dictionary p_value) { blackboard->set_data(p_value.duplicate()); }
Dictionary _get_blackboard_data() const { return blackboard->get_data(); }
void _notification(int p_notification);
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return String(get_name()) + ":<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
public:
void set_behavior_tree(const Ref<BehaviorTree> &p_tree);
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; };
void set_agent_node(const NodePath &p_agent_node);
NodePath get_agent_node() const { return agent_node; }
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
void set_update_mode(UpdateMode p_mode);
UpdateMode get_update_mode() const { return update_mode; }
@ -67,29 +81,19 @@ public:
Ref<Blackboard> get_blackboard() const { return blackboard; }
void set_blackboard(const Ref<Blackboard> &p_blackboard) { blackboard = p_blackboard; }
void set_prefetch_nodepath_vars(bool p_value) { prefetch_nodepath_vars = p_value; }
bool get_prefetch_nodepath_vars() const { return prefetch_nodepath_vars; }
void set_monitor_performance(bool p_monitor_performance);
bool get_monitor_performance() const { return monitor_performance; }
void update(double p_delta);
void restart();
int get_last_status() const { return last_status; }
Ref<BTInstance> get_bt_instance() { return bt_instance; }
void set_bt_instance(const Ref<BTInstance> &p_bt_instance);
void set_scene_root_hint(Node *p_scene_root);
BTPlayer();
~BTPlayer();
#ifdef DEBUG_ENABLED // Performance monitoring
private:
bool monitor_performance = false;
StringName monitor_id;
double update_time_acc = 0.0;
double update_time_n = 0.0;
void _set_monitor_performance(bool p_monitor_performance);
bool _get_monitor_performance() const { return monitor_performance; }
double _get_mean_update_time_msec();
#endif // DEBUG_ENABLED
};
#endif // BT_PLAYER_H

View File

@ -1,7 +1,7 @@
/**
* bt_state.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -11,81 +11,155 @@
#include "bt_state.h"
#include "../editor/debugger/limbo_debugger.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.h"
#include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine_debugger.hpp>
#endif // LIMBOAI_GDEXTENSION
void BTState::_setup() {
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
void BTState::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
}
if (p_tree.is_valid()) {
p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
}
behavior_tree = p_tree;
} else {
behavior_tree = p_tree;
}
_update_blackboard_plan();
}
void BTState::set_scene_root_hint(Node *p_scene_root) {
ERR_FAIL_NULL_MSG(p_scene_root, "BTState: Failed to set scene root hint - scene root is null.");
ERR_FAIL_COND_MSG(bt_instance.is_valid(), "BTState: Scene root hint shouldn't be set after initialization. This change will not affect the current behavior tree instance.");
scene_root_hint = p_scene_root;
}
void BTState::set_monitor_performance(bool p_monitor) {
monitor_performance = p_monitor;
#ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
if (bt_instance.is_valid()) {
bt_instance->set_monitor_performance(monitor_performance);
}
#endif
}
void BTState::_update_blackboard_plan() {
if (get_blackboard_plan().is_null()) {
set_blackboard_plan(memnew(BlackboardPlan));
} else if (!RESOURCE_IS_BUILT_IN(get_blackboard_plan())) {
WARN_PRINT_ED("BTState: Using external resource for derived blackboard plan is not supported. Converted to built-in resource.");
set_blackboard_plan(get_blackboard_plan()->duplicate());
} else {
get_blackboard_plan()->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
}
}
Node *BTState::_get_prefetch_root_for_base_plan() {
return _get_scene_root();
}
void BTState::_setup() {
LimboState::_setup();
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
Node *scene_root = _get_scene_root();
ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - unable to establish scene root. This is likely due to BTState not being owned by a scene node. Check BTState.set_scene_root_hint().");
bt_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), this, scene_root);
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree.");
#ifdef DEBUG_ENABLED
bt_instance->register_with_debugger();
bt_instance->set_monitor_performance(monitor_performance);
#endif
}
void BTState::_exit() {
ERR_FAIL_COND(tree_instance == nullptr);
tree_instance->abort();
if (bt_instance.is_valid()) {
bt_instance->get_root_task()->abort();
} else {
ERR_PRINT_ONCE("BTState: BehaviorTree is not assigned.");
}
LimboState::_exit();
}
void BTState::_update(double p_delta) {
ERR_FAIL_COND(tree_instance == nullptr);
int status = tree_instance->execute(p_delta);
emit_signal(LimboStringNames::get_singleton()->updated, p_delta);
GDVIRTUAL_CALL(_update, p_delta);
if (!is_active()) {
// Bail out if a transition happened in the meantime.
return;
}
ERR_FAIL_COND(bt_instance.is_null());
BT::Status status = bt_instance->update(p_delta);
if (status == BTTask::SUCCESS) {
get_root()->dispatch(success_event, Variant());
} else if (status == BTTask::FAILURE) {
get_root()->dispatch(failure_event, Variant());
}
emit_signal(LW_NAME(updated), p_delta);
}
#ifdef DEBUG_ENABLED
void BTState::_notification(int p_notification) {
switch (p_notification) {
#ifdef DEBUG_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
if (bt_instance.is_valid()) {
bt_instance->register_with_debugger();
bt_instance->set_monitor_performance(monitor_performance);
}
} break;
#endif // DEBUG_ENABLED
case NOTIFICATION_EXIT_TREE: {
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
#ifdef DEBUG_ENABLED
if (bt_instance.is_valid()) {
bt_instance->unregister_with_debugger();
bt_instance->set_monitor_performance(false);
}
#endif // DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
}
}
} break;
}
}
#endif // DEBUG_ENABLED
void BTState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_behavior_tree", "p_value"), &BTState::set_behavior_tree);
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTState::set_behavior_tree);
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTState::get_behavior_tree);
ClassDB::bind_method(D_METHOD("set_success_event", "p_event_name"), &BTState::set_success_event);
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTState::get_bt_instance);
ClassDB::bind_method(D_METHOD("set_success_event", "event"), &BTState::set_success_event);
ClassDB::bind_method(D_METHOD("get_success_event"), &BTState::get_success_event);
ClassDB::bind_method(D_METHOD("set_failure_event", "p_event_name"), &BTState::set_failure_event);
ClassDB::bind_method(D_METHOD("set_failure_event", "event"), &BTState::set_failure_event);
ClassDB::bind_method(D_METHOD("get_failure_event"), &BTState::get_failure_event);
ClassDB::bind_method(D_METHOD("set_monitor_performance", "enable"), &BTState::set_monitor_performance);
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTState::get_monitor_performance);
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTState::set_scene_root_hint);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "success_event"), "set_success_event", "get_success_event");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "failure_event"), "set_failure_event", "get_failure_event");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "success_event"), "set_success_event", "get_success_event");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "failure_event"), "set_failure_event", "get_failure_event");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
}
BTState::BTState() {
success_event = "success";
failure_event = "failure";
success_event = LW_NAME(EVENT_SUCCESS);
failure_event = LW_NAME(EVENT_FAILURE);
}

View File

@ -1,7 +1,7 @@
/**
* bt_state.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -22,34 +22,45 @@ class BTState : public LimboState {
private:
Ref<BehaviorTree> behavior_tree;
Ref<BTTask> tree_instance;
String success_event;
String failure_event;
Ref<BTInstance> bt_instance;
StringName success_event;
StringName failure_event;
Node *scene_root_hint = nullptr;
bool monitor_performance = false;
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
protected:
static void _bind_methods();
void _notification(int p_notification);
virtual bool _should_use_new_scope() const override { return true; }
virtual void _update_blackboard_plan() override;
virtual Node *_get_prefetch_root_for_base_plan() override;
virtual void _setup() override;
virtual void _exit() override;
virtual void _update(double p_delta) override;
public:
void set_behavior_tree(const Ref<BehaviorTree> &p_value) { behavior_tree = p_value; }
void set_behavior_tree(const Ref<BehaviorTree> &p_value);
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; }
void set_success_event(String p_success_event) { success_event = p_success_event; }
String get_success_event() const { return success_event; }
Ref<BTInstance> get_bt_instance() const { return bt_instance; }
void set_failure_event(String p_failure_event) { failure_event = p_failure_event; }
String get_failure_event() const { return failure_event; }
void set_success_event(const StringName &p_success_event) { success_event = p_success_event; }
StringName get_success_event() const { return success_event; }
void set_failure_event(const StringName &p_failure_event) { failure_event = p_failure_event; }
StringName get_failure_event() const { return failure_event; }
void set_monitor_performance(bool p_monitor);
bool get_monitor_performance() const { return monitor_performance; }
void set_scene_root_hint(Node *p_node);
BTState();
#ifdef DEBUG_ENABLED
protected:
void _notification(int p_notification);
#endif
};
#endif // BT_STATE_H

View File

@ -1,7 +1,7 @@
/**
* bt_check_trigger.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -13,28 +13,28 @@
#include "../../../util/limbo_utility.h"
void BTCheckTrigger::set_variable(String p_variable) {
void BTCheckTrigger::set_variable(const StringName &p_variable) {
variable = p_variable;
emit_changed();
}
PackedStringArray BTCheckTrigger::get_configuration_warnings() {
PackedStringArray warnings = BTCondition::get_configuration_warnings();
if (variable.is_empty()) {
if (variable == StringName()) {
warnings.append("Variable is not set.");
}
return warnings;
}
String BTCheckTrigger::_generate_name() {
if (variable.is_empty()) {
if (variable == StringName()) {
return "CheckTrigger ???";
}
return "CheckTrigger " + LimboUtility::get_singleton()->decorate_var(variable);
}
BT::Status BTCheckTrigger::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(variable.is_empty(), FAILURE, "BBCheckVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BBCheckVar: `variable` is not set.");
Variant trigger_value = get_blackboard()->get_var(variable, false);
if (trigger_value == Variant(true)) {
get_blackboard()->set_var(variable, false);
@ -44,8 +44,8 @@ BT::Status BTCheckTrigger::_tick(double p_delta) {
}
void BTCheckTrigger::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_variable", "p_variable"), &BTCheckTrigger::set_variable);
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTCheckTrigger::set_variable);
ClassDB::bind_method(D_METHOD("get_variable"), &BTCheckTrigger::get_variable);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable"), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
}

View File

@ -1,7 +1,7 @@
/**
* bt_check_trigger.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -19,7 +19,7 @@ class BTCheckTrigger : public BTCondition {
TASK_CATEGORY(Blackboard);
private:
String variable;
StringName variable;
protected:
static void _bind_methods();
@ -28,10 +28,10 @@ protected:
virtual Status _tick(double p_delta) override;
public:
void set_variable(String p_variable);
String get_variable() const { return variable; }
void set_variable(const StringName &p_variable);
StringName get_variable() const { return variable; }
virtual PackedStringArray get_configuration_warnings() override;
};
#endif // BT_CHECK_TRIGGER
#endif // BT_CHECK_TRIGGER

View File

@ -1,7 +1,7 @@
/**
* bt_check_var.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -11,7 +11,7 @@
#include "bt_check_var.h"
void BTCheckVar::set_variable(String p_variable) {
void BTCheckVar::set_variable(const StringName &p_variable) {
variable = p_variable;
emit_changed();
}
@ -21,17 +21,18 @@ void BTCheckVar::set_check_type(LimboUtility::CheckType p_check_type) {
emit_changed();
}
void BTCheckVar::set_value(Ref<BBVariant> p_value) {
void BTCheckVar::set_value(const Ref<BBVariant> &p_value) {
value = p_value;
emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
if (Engine::get_singleton()->is_editor_hint() && value.is_valid() &&
!value->is_connected(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed))) {
value->connect(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed));
}
}
PackedStringArray BTCheckVar::get_configuration_warnings() {
PackedStringArray warnings = BTCondition::get_configuration_warnings();
if (variable.is_empty()) {
if (variable == StringName()) {
warnings.append("`variable` should be assigned.");
}
if (!value.is_valid()) {
@ -41,7 +42,7 @@ PackedStringArray BTCheckVar::get_configuration_warnings() {
}
String BTCheckVar::_generate_name() {
if (variable.is_empty()) {
if (variable == StringName()) {
return "CheckVar ???";
}
@ -51,26 +52,26 @@ String BTCheckVar::_generate_name() {
}
BT::Status BTCheckVar::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(variable.is_empty(), FAILURE, "BTCheckVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BTCheckVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTCheckVar: `value` is not set.");
ERR_FAIL_COND_V_MSG(!get_blackboard()->has_var(variable), FAILURE, vformat("BTCheckVar: Blackboard variable doesn't exist: \"%s\". Returning FAILURE.", variable));
Variant left_value = get_blackboard()->get_var(variable, Variant());
Variant right_value = value->get_value(get_agent(), get_blackboard());
Variant right_value = value->get_value(get_scene_root(), get_blackboard());
return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE;
}
void BTCheckVar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_variable", "p_variable"), &BTCheckVar::set_variable);
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTCheckVar::set_variable);
ClassDB::bind_method(D_METHOD("get_variable"), &BTCheckVar::get_variable);
ClassDB::bind_method(D_METHOD("set_check_type", "p_check_type"), &BTCheckVar::set_check_type);
ClassDB::bind_method(D_METHOD("set_check_type", "check_type"), &BTCheckVar::set_check_type);
ClassDB::bind_method(D_METHOD("get_check_type"), &BTCheckVar::get_check_type);
ClassDB::bind_method(D_METHOD("set_value", "p_value"), &BTCheckVar::set_value);
ClassDB::bind_method(D_METHOD("set_value", "value"), &BTCheckVar::set_value);
ClassDB::bind_method(D_METHOD("get_value"), &BTCheckVar::get_value);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable"), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "check_type", PROPERTY_HINT_ENUM, "Equal,Less Than,Less Than Or Equal,Greater Than,Greater Than Or Equal,Not Equal"), "set_check_type", "get_check_type");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "value", PROPERTY_HINT_RESOURCE_TYPE, "BBVariant"), "set_value", "get_value");
}

View File

@ -1,7 +1,7 @@
/**
* bt_check_var.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -22,7 +22,7 @@ class BTCheckVar : public BTCondition {
TASK_CATEGORY(Blackboard);
private:
String variable;
StringName variable;
LimboUtility::CheckType check_type = LimboUtility::CheckType::CHECK_EQUAL;
Ref<BBVariant> value;
@ -35,14 +35,14 @@ protected:
public:
virtual PackedStringArray get_configuration_warnings() override;
void set_variable(String p_variable);
String get_variable() const { return variable; }
void set_variable(const StringName &p_variable);
StringName get_variable() const { return variable; }
void set_check_type(LimboUtility::CheckType p_check_type);
LimboUtility::CheckType get_check_type() const { return check_type; }
void set_value(Ref<BBVariant> p_value);
void set_value(const Ref<BBVariant> &p_value);
Ref<BBVariant> get_value() const { return value; }
};
#endif // BT_CHECK_VAR_H
#endif // BT_CHECK_VAR_H

View File

@ -1,7 +1,7 @@
/**
* bt_set_var.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -12,7 +12,7 @@
#include "bt_set_var.h"
String BTSetVar::_generate_name() {
if (variable.is_empty()) {
if (variable == StringName()) {
return "SetVar ???";
}
return vformat("Set %s %s= %s",
@ -22,11 +22,11 @@ String BTSetVar::_generate_name() {
}
BT::Status BTSetVar::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(variable.is_empty(), FAILURE, "BTSetVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BTSetVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set.");
Variant result;
Variant error_result = LW_NAME(error_value);
Variant right_value = value->get_value(get_agent(), get_blackboard(), error_result);
Variant right_value = value->get_value(get_scene_root(), get_blackboard(), error_result);
ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE.");
if (operation == LimboUtility::OPERATION_NONE) {
result = right_value;
@ -40,16 +40,17 @@ BT::Status BTSetVar::_tick(double p_delta) {
return SUCCESS;
};
void BTSetVar::set_variable(const String &p_variable) {
void BTSetVar::set_variable(const StringName &p_variable) {
variable = p_variable;
emit_changed();
}
void BTSetVar::set_value(Ref<BBVariant> p_value) {
void BTSetVar::set_value(const Ref<BBVariant> &p_value) {
value = p_value;
emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
if (Engine::get_singleton()->is_editor_hint() && value.is_valid() &&
!value->is_connected(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed))) {
value->connect(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed));
}
}
@ -60,7 +61,7 @@ void BTSetVar::set_operation(LimboUtility::Operation p_operation) {
PackedStringArray BTSetVar::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings();
if (variable.is_empty()) {
if (variable == StringName()) {
warnings.append("`variable` should be assigned.");
}
if (!value.is_valid()) {
@ -70,14 +71,14 @@ PackedStringArray BTSetVar::get_configuration_warnings() {
}
void BTSetVar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_variable", "p_variable"), &BTSetVar::set_variable);
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTSetVar::set_variable);
ClassDB::bind_method(D_METHOD("get_variable"), &BTSetVar::get_variable);
ClassDB::bind_method(D_METHOD("set_value", "p_value"), &BTSetVar::set_value);
ClassDB::bind_method(D_METHOD("set_value", "value"), &BTSetVar::set_value);
ClassDB::bind_method(D_METHOD("get_value"), &BTSetVar::get_value);
ClassDB::bind_method(D_METHOD("get_operation"), &BTSetVar::get_operation);
ClassDB::bind_method(D_METHOD("set_operation", "p_operation"), &BTSetVar::set_operation);
ClassDB::bind_method(D_METHOD("set_operation", "operation"), &BTSetVar::set_operation);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable"), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "value", PROPERTY_HINT_RESOURCE_TYPE, "BBVariant"), "set_value", "get_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "None,Addition,Subtraction,Multiplication,Division,Modulo,Power,Bitwise Shift Left,Bitwise Shift Right,Bitwise AND,Bitwise OR,Bitwise XOR"), "set_operation", "get_operation");
}

View File

@ -1,7 +1,7 @@
/**
* bt_set_var.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -22,7 +22,7 @@ class BTSetVar : public BTAction {
TASK_CATEGORY(Blackboard);
private:
String variable;
StringName variable;
Ref<BBVariant> value;
LimboUtility::Operation operation = LimboUtility::OPERATION_NONE;
@ -35,14 +35,14 @@ protected:
public:
virtual PackedStringArray get_configuration_warnings() override;
void set_variable(const String &p_variable);
String get_variable() const { return variable; }
void set_variable(const StringName &p_variable);
StringName get_variable() const { return variable; }
void set_value(Ref<BBVariant> p_value);
void set_value(const Ref<BBVariant> &p_value);
Ref<BBVariant> get_value() const { return value; }
void set_operation(LimboUtility::Operation p_operation);
LimboUtility::Operation get_operation() const { return operation; }
};
#endif // BT_SET_VAR
#endif // BT_SET_VAR

View File

@ -1,7 +1,7 @@
/**
* bt_action.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at

View File

@ -1,7 +1,7 @@
/**
* bt_action.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -17,6 +17,9 @@
class BTAction : public BTTask {
GDCLASS(BTAction, BTTask);
protected:
static void _bind_methods() {}
public:
virtual PackedStringArray get_configuration_warnings() override;
};

View File

@ -1,7 +1,7 @@
/**
* bt_comment.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -30,7 +30,7 @@ PackedStringArray BTComment::get_configuration_warnings() {
if (get_child_count_excluding_comments() > 0) {
warnings.append("Can only have other comment tasks as children.");
}
if (get_parent() == nullptr) {
if (get_parent().is_null()) {
warnings.append("Can't be the root task.");
}
return warnings;

View File

@ -1,7 +1,7 @@
/**
* bt_comment.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,6 +18,9 @@ class BTComment : public BTTask {
GDCLASS(BTComment, BTTask);
TASK_CATEGORY(Utility);
protected:
static void _bind_methods() {}
public:
virtual Ref<BTTask> clone() const override;
virtual PackedStringArray get_configuration_warnings() override;

View File

@ -1,7 +1,7 @@
/**
* bt_composite.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at

View File

@ -1,7 +1,7 @@
/**
* bt_composite.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -17,6 +17,9 @@
class BTComposite : public BTTask {
GDCLASS(BTComposite, BTTask);
protected:
static void _bind_methods() {}
public:
virtual PackedStringArray get_configuration_warnings() override;
};

View File

@ -1,7 +1,7 @@
/**
* bt_condition.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at

View File

@ -1,7 +1,7 @@
/**
* bt_condition.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -17,6 +17,9 @@
class BTCondition : public BTTask {
GDCLASS(BTCondition, BTTask);
protected:
static void _bind_methods() {}
public:
virtual PackedStringArray get_configuration_warnings() override;
};

View File

@ -1,7 +1,7 @@
/**
* bt_decorator.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -18,3 +18,8 @@ PackedStringArray BTDecorator::get_configuration_warnings() {
}
return warnings;
}
BT::Status BTDecorator::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator doesn't have a child.");
return get_child(0)->execute(p_delta);
}

View File

@ -1,7 +1,7 @@
/**
* bt_decorator.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -17,6 +17,11 @@
class BTDecorator : public BTTask {
GDCLASS(BTDecorator, BTTask)
protected:
static void _bind_methods() {}
virtual Status _tick(double p_delta) override;
public:
virtual PackedStringArray get_configuration_warnings() override;
};

View File

@ -1,7 +1,7 @@
/**
* bt_task.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -14,6 +14,7 @@
#include "../../blackboard/blackboard.h"
#include "../../util/limbo_string_names.h"
#include "../../util/limbo_utility.h"
#include "../behavior_tree.h"
#include "bt_comment.h"
#ifdef LIMBOAI_MODULE
@ -76,34 +77,73 @@ Array BTTask::_get_children() const {
}
void BTTask::_set_children(Array p_children) {
data.children.clear();
const int num_children = p_children.size();
int num_null = 0;
data.children.clear();
data.children.resize(num_children);
for (int i = 0; i < num_children; i++) {
Variant task_var = p_children[i];
Ref<BTTask> task_ref = task_var;
task_ref->data.parent = this;
task_ref->data.index = i;
data.children.set(i, task_var);
Ref<BTTask> task = p_children[i];
if (task.is_null()) {
ERR_PRINT("Invalid BTTask reference.");
num_null += 1;
continue;
}
if (task->data.parent != nullptr && task->data.parent != this) {
task = task->clone();
if (task.is_null()) {
// * BTComment::clone() returns nullptr at runtime - we omit those.
num_null += 1;
continue;
}
}
int idx = i - num_null;
task->data.parent = this;
task->data.index = idx;
data.children.set(idx, task);
}
if (num_null > 0) {
data.children.resize(num_children - num_null);
}
}
void BTTask::set_display_collapsed(bool p_display_collapsed) {
data.display_collapsed = p_display_collapsed;
}
bool BTTask::is_displayed_collapsed() const {
return data.display_collapsed;
}
String BTTask::get_task_name() {
if (data.custom_name.is_empty()) {
#ifdef LIMBOAI_MODULE
if (get_script_instance() && get_script_instance()->has_method(LW_NAME(_generate_name))) {
if (unlikely(!get_script_instance()->get_script()->is_tool())) {
ERR_PRINT(vformat("BTTask: Task script should be a \"tool\" script!"));
} else {
return get_script_instance()->call(LimboStringNames::get_singleton()->_generate_name);
}
}
return _generate_name();
#elif LIMBOAI_GDEXTENSION
return call(LimboStringNames::get_singleton()->_generate_name);
#endif
if (!data.custom_name.is_empty()) {
return data.custom_name;
}
return data.custom_name;
Ref<Script> task_script = get_script();
if (task_script.is_valid()) {
// ! CURSED: Currently, has_method() doesn't return true for ClassDB-registered native virtual methods. This may break in the future.
bool has_generate_method = has_method(LW_NAME(_generate_name));
ERR_FAIL_COND_V_MSG(has_generate_method && !task_script->is_tool(), _generate_name(), vformat("BTTask: @tool annotation is required if _generate_name is defined: %s", task_script->get_path()));
if (task_script->is_tool() && has_generate_method) {
String call_result;
GDVIRTUAL_CALL(_generate_name, call_result);
if (call_result.is_empty() || call_result == "<null>") {
// Force reset script instance.
set_script(Variant());
set_script(task_script);
// Retry.
GDVIRTUAL_CALL(_generate_name, call_result);
}
ERR_FAIL_COND_V_MSG(call_result.is_empty() || call_result == "<null>", _generate_name(), vformat("BTTask: _generate_name() failed to return a proper name string (%s)", task_script->get_path()));
return call_result;
}
}
return _generate_name();
}
Ref<BTTask> BTTask::get_root() const {
@ -121,93 +161,67 @@ void BTTask::set_custom_name(const String &p_name) {
}
};
void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
ERR_FAIL_COND(p_agent == nullptr);
ERR_FAIL_COND(p_blackboard == nullptr);
void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) {
ERR_FAIL_NULL(p_agent);
ERR_FAIL_COND(p_blackboard.is_null());
ERR_FAIL_NULL(p_scene_root);
data.agent = p_agent;
data.blackboard = p_blackboard;
data.scene_root = p_scene_root;
for (int i = 0; i < data.children.size(); i++) {
get_child(i)->initialize(p_agent, p_blackboard);
get_child(i)->initialize(p_agent, p_blackboard, p_scene_root);
}
VCALL_OR_NATIVE(_setup);
_setup();
GDVIRTUAL_CALL(_setup);
}
Ref<BTTask> BTTask::clone() const {
Ref<BTTask> inst = duplicate(false);
inst->data.parent = nullptr;
inst->data.agent = nullptr;
inst->data.blackboard.unref();
int num_null = 0;
for (int i = 0; i < data.children.size(); i++) {
Ref<BTTask> c = get_child(i)->clone();
if (c.is_valid()) {
c->data.parent = inst.ptr();
c->data.index = i;
inst->data.children.set(i - num_null, c);
} else {
num_null += 1;
}
}
if (num_null > 0) {
// * BTComment tasks return nullptr at runtime - we remove those.
inst->data.children.resize(data.children.size() - num_null);
}
// * Children are duplicated via children property. See _set_children().
// * Make BBParam properties unique.
HashMap<Ref<Resource>, Ref<Resource>> duplicates;
#ifdef LIMBOAI_MODULE
// Make BBParam properties unique.
List<PropertyInfo> props;
inst->get_property_list(&props);
HashMap<Ref<Resource>, Ref<Resource>> duplicates;
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
Variant v = inst->get(E->get().name);
if (v.is_ref_counted()) {
Ref<RefCounted> ref = v;
if (ref.is_valid()) {
Ref<Resource> res = ref;
if (res.is_valid() && res->is_class("BBParam")) {
if (!duplicates.has(res)) {
duplicates[res] = res->duplicate();
}
res = duplicates[res];
inst->set(E->get().name, res);
}
}
}
}
PropertyInfo prop = E->get();
#elif LIMBOAI_GDEXTENSION
// Make BBParam properties unique.
TypedArray<Dictionary> props = inst->get_property_list();
HashMap<Ref<Resource>, Ref<Resource>> duplicates;
for (int i = 0; i < props.size(); i++) {
Dictionary prop = props[i];
if (!(int(prop["usage"]) & PROPERTY_USAGE_STORAGE)) {
PropertyInfo prop = PropertyInfo::from_dict(props[i]);
#endif
if (!(prop.usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
StringName prop_name = prop["name"];
Variant v = inst->get(prop_name);
if (v.get_type() == Variant::OBJECT && int(prop["hint"]) == PROPERTY_HINT_RESOURCE_TYPE) {
Ref<RefCounted> ref = v;
if (ref.is_valid()) {
Ref<Resource> res = ref;
if (res.is_valid() && res->is_class("BBParam")) {
if (!duplicates.has(res)) {
duplicates[res] = res->duplicate();
Variant prop_value = inst->get(prop.name);
Ref<Resource> res = prop_value;
if (res.is_valid() && res->is_class("BBParam")) {
// Duplicate BBParam
if (!duplicates.has(res)) {
duplicates[res] = res->duplicate();
}
res = duplicates[res];
inst->set(prop.name, res);
} else if (prop_value.get_type() == Variant::ARRAY) {
// Duplicate BBParams instances inside an array.
// - This code doesn't handle arrays of arrays.
// - A partial workaround for: https://github.com/godotengine/godot/issues/74918
// - We actually don't want to duplicate resources in clone() except for BBParam subtypes.
Array arr = prop_value;
if (arr.is_typed() && ClassDB::is_parent_class(arr.get_typed_class_name(), LW_NAME(BBParam))) {
for (int j = 0; j < arr.size(); j++) {
Ref<Resource> bb_param = arr[j];
if (bb_param.is_valid()) {
arr[j] = bb_param->duplicate();
}
res = duplicates[res];
inst->set(prop_name, res);
}
}
}
}
#endif // LIMBOAI_MODULE & LIMBOAI_GDEXTENSION
return inst;
}
@ -220,22 +234,21 @@ BT::Status BTTask::execute(double p_delta) {
data.children.get(i)->abort();
}
}
VCALL_OR_NATIVE(_enter);
// First native, then script.
_enter();
GDVIRTUAL_CALL(_enter);
} else {
data.elapsed += p_delta;
}
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) {
data.status = _tick(p_delta);
}
#elif LIMBOAI_GDEXTENSION
data.status = (Status)(int)call(LimboStringNames::get_singleton()->_tick, p_delta);
#endif
if (data.status != RUNNING) {
VCALL_OR_NATIVE(_exit);
// First script, then native.
GDVIRTUAL_CALL(_exit);
_exit();
data.elapsed = 0.0;
}
return data.status;
@ -246,7 +259,9 @@ void BTTask::abort() {
get_child(i)->abort();
}
if (data.status == RUNNING) {
VCALL_OR_NATIVE(_exit);
// First script, then native.
GDVIRTUAL_CALL(_exit);
_exit();
}
data.status = FRESH;
data.elapsed = 0.0;
@ -275,9 +290,9 @@ void BTTask::add_child_at_index(Ref<BTTask> p_child, int p_idx) {
if (p_idx < 0 || p_idx > data.children.size()) {
p_idx = data.children.size();
}
data.children.insert(p_idx, p_child);
p_child->data.parent = this;
p_child->data.index = p_idx;
data.children.insert(p_idx, p_child);
for (int i = p_idx + 1; i < data.children.size(); i++) {
get_child(i)->data.index = i;
}
@ -335,8 +350,12 @@ PackedStringArray BTTask::get_configuration_warnings() {
PackedStringArray ret;
PackedStringArray warnings;
VCALL_V(_get_configuration_warnings, warnings); // Get script warnings.
Ref<Script> task_script = get_script();
if (task_script.is_valid() && task_script->is_tool()) {
GDVIRTUAL_CALL(_get_configuration_warnings, warnings); // Get script warnings.
}
ret.append_array(warnings);
ret.append_array(_get_configuration_warnings());
return ret;
}
@ -354,63 +373,77 @@ void BTTask::print_tree(int p_initial_tabs) {
}
}
Ref<BehaviorTree> BTTask::editor_get_behavior_tree() {
#ifdef TOOLS_ENABLED
BTTask *task = this;
while (task->data.behavior_tree_id.is_null() && task->get_parent().is_valid()) {
task = task->data.parent;
}
return Object::cast_to<BehaviorTree>(ObjectDB::get_instance(task->data.behavior_tree_id));
#else
ERR_PRINT("BTTask::editor_get_behavior_tree: Not available in release builds.");
return Ref<BehaviorTree>();
#endif
}
#ifdef TOOLS_ENABLED
void BTTask::editor_set_behavior_tree(const Ref<BehaviorTree> &p_bt) {
data.behavior_tree_id = p_bt->get_instance_id();
}
#endif // TOOLS_ENABLED
void BTTask::_bind_methods() {
// Public Methods.
ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root);
ClassDB::bind_method(D_METHOD("get_root"), &BTTask::get_root);
ClassDB::bind_method(D_METHOD("initialize", "p_agent", "p_blackboard"), &BTTask::initialize);
ClassDB::bind_method(D_METHOD("initialize", "agent", "blackboard", "scene_root"), &BTTask::initialize);
ClassDB::bind_method(D_METHOD("clone"), &BTTask::clone);
ClassDB::bind_method(D_METHOD("execute", "p_delta"), &BTTask::execute);
ClassDB::bind_method(D_METHOD("get_child", "p_idx"), &BTTask::get_child);
ClassDB::bind_method(D_METHOD("execute", "delta"), &BTTask::execute);
ClassDB::bind_method(D_METHOD("get_child", "idx"), &BTTask::get_child);
ClassDB::bind_method(D_METHOD("get_child_count"), &BTTask::get_child_count);
ClassDB::bind_method(D_METHOD("get_child_count_excluding_comments"), &BTTask::get_child_count_excluding_comments);
ClassDB::bind_method(D_METHOD("add_child", "p_child"), &BTTask::add_child);
ClassDB::bind_method(D_METHOD("add_child_at_index", "p_child", "p_idx"), &BTTask::add_child_at_index);
ClassDB::bind_method(D_METHOD("remove_child", "p_child"), &BTTask::remove_child);
ClassDB::bind_method(D_METHOD("remove_child_at_index", "p_idx"), &BTTask::remove_child_at_index);
ClassDB::bind_method(D_METHOD("has_child", "p_child"), &BTTask::has_child);
ClassDB::bind_method(D_METHOD("is_descendant_of", "p_task"), &BTTask::is_descendant_of);
ClassDB::bind_method(D_METHOD("add_child", "task"), &BTTask::add_child);
ClassDB::bind_method(D_METHOD("add_child_at_index", "task", "idx"), &BTTask::add_child_at_index);
ClassDB::bind_method(D_METHOD("remove_child", "task"), &BTTask::remove_child);
ClassDB::bind_method(D_METHOD("remove_child_at_index", "idx"), &BTTask::remove_child_at_index);
ClassDB::bind_method(D_METHOD("has_child", "task"), &BTTask::has_child);
ClassDB::bind_method(D_METHOD("is_descendant_of", "task"), &BTTask::is_descendant_of);
ClassDB::bind_method(D_METHOD("get_index"), &BTTask::get_index);
ClassDB::bind_method(D_METHOD("next_sibling"), &BTTask::next_sibling);
ClassDB::bind_method(D_METHOD("print_tree", "p_initial_tabs"), &BTTask::print_tree, Variant(0));
ClassDB::bind_method(D_METHOD("print_tree", "initial_tabs"), &BTTask::print_tree, Variant(0));
ClassDB::bind_method(D_METHOD("get_task_name"), &BTTask::get_task_name);
ClassDB::bind_method(D_METHOD("abort"), &BTTask::abort);
ClassDB::bind_method(D_METHOD("editor_get_behavior_tree"), &BTTask::editor_get_behavior_tree);
// Properties, setters and getters.
ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent);
ClassDB::bind_method(D_METHOD("set_agent", "p_agent"), &BTTask::set_agent);
ClassDB::bind_method(D_METHOD("set_agent", "agent"), &BTTask::set_agent);
ClassDB::bind_method(D_METHOD("get_scene_root"), &BTTask::get_scene_root);
ClassDB::bind_method(D_METHOD("_get_children"), &BTTask::_get_children);
ClassDB::bind_method(D_METHOD("_set_children", "p_children"), &BTTask::_set_children);
ClassDB::bind_method(D_METHOD("_set_children", "children"), &BTTask::_set_children);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard);
ClassDB::bind_method(D_METHOD("get_parent"), &BTTask::get_parent);
ClassDB::bind_method(D_METHOD("get_status"), &BTTask::get_status);
ClassDB::bind_method(D_METHOD("get_elapsed_time"), &BTTask::get_elapsed_time);
ClassDB::bind_method(D_METHOD("get_custom_name"), &BTTask::get_custom_name);
ClassDB::bind_method(D_METHOD("set_custom_name", "p_name"), &BTTask::set_custom_name);
ClassDB::bind_method(D_METHOD("set_custom_name", "name"), &BTTask::set_custom_name);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_NODE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_scene_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children");
ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_elapsed_time");
#ifdef LIMBOAI_MODULE
GDVIRTUAL_BIND(_setup);
GDVIRTUAL_BIND(_enter);
GDVIRTUAL_BIND(_exit);
GDVIRTUAL_BIND(_tick, "p_delta");
GDVIRTUAL_BIND(_tick, "delta");
GDVIRTUAL_BIND(_generate_name);
GDVIRTUAL_BIND(_get_configuration_warnings);
#elif LIMBOAI_GDEXTENSION
// TODO: Until virtual functions are implemented in godot-cpp, we do this. Replace this code when possible.
ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup);
ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter);
ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit);
ClassDB::bind_method(D_METHOD("_tick", "p_delta"), &BTTask::_tick);
ClassDB::bind_method(D_METHOD("_generate_name"), &BTTask::_generate_name);
ClassDB::bind_method(D_METHOD("_get_configuration_warnings"), &BTTask::_get_configuration_warnings);
#endif
}
BTTask::BTTask() {

View File

@ -1,7 +1,7 @@
/**
* bt_task.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -37,11 +37,14 @@
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/core/gdvirtual.gen.inc>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
class BehaviorTree;
/**
* Base class for BTTask.
* Note: In order to properly return Status in the _tick virtual method (GDVIRTUAL1R...)
@ -75,11 +78,16 @@ private:
int index = -1;
String custom_name;
Node *agent = nullptr;
Node *scene_root = nullptr;
Ref<Blackboard> blackboard;
BTTask *parent = nullptr;
Vector<Ref<BTTask>> children;
Status status = FRESH;
double elapsed = 0.0;
bool display_collapsed = false;
#ifdef TOOLS_ENABLED
ObjectID behavior_tree_id;
#endif
} data;
Array _get_children() const;
@ -96,14 +104,16 @@ protected:
virtual void _exit() {}
virtual Status _tick(double p_delta) { return FAILURE; }
#ifdef LIMBOAI_MODULE
GDVIRTUAL0RC(String, _generate_name);
GDVIRTUAL0(_setup);
GDVIRTUAL0(_enter);
GDVIRTUAL0(_exit);
GDVIRTUAL1R(Status, _tick, double);
GDVIRTUAL0RC(PackedStringArray, _get_configuration_warnings);
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
#endif
public:
// TODO: GDExtension doesn't have this method hmm...
@ -115,6 +125,11 @@ public:
_FORCE_INLINE_ Node *get_agent() const { return data.agent; }
void set_agent(Node *p_agent) { data.agent = p_agent; }
_FORCE_INLINE_ Node *get_scene_root() const { return data.scene_root; }
void set_display_collapsed(bool p_display_collapsed);
bool is_displayed_collapsed() const;
String get_custom_name() const { return data.custom_name; }
void set_custom_name(const String &p_name);
String get_task_name();
@ -122,7 +137,7 @@ public:
Ref<BTTask> get_root() const;
virtual Ref<BTTask> clone() const;
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard);
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root);
virtual PackedStringArray get_configuration_warnings(); // ! Native version.
Status execute(double p_delta);
@ -155,6 +170,11 @@ public:
void print_tree(int p_initial_tabs = 0);
Ref<BehaviorTree> editor_get_behavior_tree();
#ifdef TOOLS_ENABLED
void editor_set_behavior_tree(const Ref<BehaviorTree> &p_bt);
#endif
BTTask();
~BTTask();
};

View File

@ -1,7 +1,7 @@
/**
* bt_dynamic_selector.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -31,4 +31,4 @@ BT::Status BTDynamicSelector::_tick(double p_delta) {
}
last_running_idx = i;
return status;
}
}

View File

@ -1,7 +1,7 @@
/**
* bt_dynamic_selector.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -22,8 +22,10 @@ private:
int last_running_idx = 0;
protected:
static void _bind_methods() {}
virtual void _enter() override;
virtual Status _tick(double p_delta) override;
};
#endif // BT_DYNAMIC_SELECTOR_H
#endif // BT_DYNAMIC_SELECTOR_H

View File

@ -1,7 +1,7 @@
/**
* bt_dynamic_sequence.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at

View File

@ -1,7 +1,7 @@
/**
* bt_dynamic_sequence.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -22,6 +22,8 @@ private:
int last_running_idx = 0;
protected:
static void _bind_methods() {}
virtual void _enter() override;
virtual Status _tick(double p_delta) override;
};

View File

@ -1,7 +1,7 @@
/**
* bt_parallel.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
@ -49,11 +49,11 @@ BT::Status BTParallel::_tick(double p_delta) {
void BTParallel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_num_successes_required"), &BTParallel::get_num_successes_required);
ClassDB::bind_method(D_METHOD("set_num_successes_required", "p_value"), &BTParallel::set_num_successes_required);
ClassDB::bind_method(D_METHOD("set_num_successes_required", "value"), &BTParallel::set_num_successes_required);
ClassDB::bind_method(D_METHOD("get_num_failures_required"), &BTParallel::get_num_failures_required);
ClassDB::bind_method(D_METHOD("set_num_failures_required", "p_value"), &BTParallel::set_num_failures_required);
ClassDB::bind_method(D_METHOD("set_num_failures_required", "value"), &BTParallel::set_num_failures_required);
ClassDB::bind_method(D_METHOD("get_repeat"), &BTParallel::get_repeat);
ClassDB::bind_method(D_METHOD("set_repeat", "p_value"), &BTParallel::set_repeat);
ClassDB::bind_method(D_METHOD("set_repeat", "enable"), &BTParallel::set_repeat);
ADD_PROPERTY(PropertyInfo(Variant::INT, "num_successes_required"), "set_num_successes_required", "get_num_successes_required");
ADD_PROPERTY(PropertyInfo(Variant::INT, "num_failures_required"), "set_num_failures_required", "get_num_failures_required");

Some files were not shown because too many files have changed in this diff Show More