Merge pull request #15 from limbonaut/gdextension

Implement GDExtension support
This commit is contained in:
Serhii Snitsaruk 2024-01-13 21:19:15 +01:00 committed by GitHub
commit cc16879a45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
169 changed files with 3729 additions and 1080 deletions

View File

@ -0,0 +1,24 @@
name: Setup version
runs:
using: "composite"
steps:
- name: Set GDEXTENSION_VERSION & LIMBOAI_VERSION
shell: bash
run: |
cd godot-cpp
GDEXTENSION_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1/g' )
if [[ ${GDEXTENSION_VERSION} == godot-* ]]; then
GDEXTENSION_VERSION=${GDEXTENSION_VERSION#"godot-"}
fi
echo "GDEXTENSION_VERSION=${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"
cd ../limboai
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1/g' )" >> "$GITHUB_ENV"
- name: Set NAME_PREFIX
shell: bash
run: echo "NAME_PREFIX=gdextension-${GDEXTENSION_VERSION}.limboai+${LIMBOAI_VERSION}" >> "$GITHUB_ENV"

209
.github/workflows/gdextension.yml vendored Normal file
View File

@ -0,0 +1,209 @@
name: 🔌 GDExtension
on:
workflow_call:
inputs:
godot-cpp-treeish:
description: A tag, branch or commit hash in the godot-cpp repository.
type: string
default: 4.2
limboai-treeish:
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?
type: boolean
default: false
workflow_dispatch:
inputs:
godot-cpp-treeish:
description: A tag, branch or commit hash in the godot-cpp repository.
type: string
default: 4.2
limboai-treeish:
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?
type: boolean
default: false
# Global Settings
env:
SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: dev_build=no debug_symbols=no
jobs:
gdextension:
runs-on: ${{ matrix.opts.runner }}
name: ${{ matrix.opts.name }}
strategy:
fail-fast: false
matrix:
opts:
- name: 🐧 Linux (x86_64, release)
runner: ubuntu-20.04
platform: linux
target: template_release
arch: x86_64
should-build: true
- name: 🐧 Linux (x86_64, debug)
runner: ubuntu-20.04
platform: linux
target: editor
arch: x86_64
should-build: true
- name: 🪟 Windows (x86_64, release)
runner: windows-latest
platform: windows
target: template_release
arch: x86_64
should-build: true
- name: 🪟 Windows (x86_64, debug)
runner: windows-latest
platform: windows
target: editor
arch: x86_64
should-build: true
- name: 🍎 macOS (universal, release)
runner: macos-latest
platform: macos
target: template_release
arch: universal
should-build: true
- name: 🍎 macOS (universal, debug)
runner: macos-latest
platform: macos
target: editor
arch: universal
should-build: true
exclude:
- { opts: {should-build: false }}
env:
BIN: liblimboai.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
steps:
- 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 }}
# Inits GDEXTENSION_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./limboai/.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: 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: Set up Python 3.x
if: matrix.opts.platform == 'windows' || matrix.opts.platform == 'macos'
uses: actions/setup-python@v4
with:
python-version: '3.x'
architecture: 'x64'
- name: Set up scons
if: matrix.opts.platform == 'windows' || matrix.opts.platform == 'macos'
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 on Windows
if: matrix.opts.platform == 'windows'
uses: ammaraskar/msvc-problem-matcher@master
- name: Set up scons cache
uses: actions/cache@v3
with:
path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-cpp-treeish}}-${{inputs.limboai-treeish}}-${{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/
- name: Compilation
shell: bash
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.SCONSFLAGS}}
- name: Prepare artifact
shell: bash
run: |
mkdir out
mv demo/addons/ out/
rm -f out/addons/limboai/bin/*.{exp,lib,pdb}
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
env:
NAME: ${{env.NAME_PREFIX}}
with:
name: ${{ env.NAME }}
path: out/*

View File

@ -10,11 +10,6 @@ on:
- "**/*.png" - "**/*.png"
- "demo/*" - "demo/*"
- "doc/*" - "doc/*"
inputs:
godot-treeish:
description: A tag, branch or commit hash in the Godot repository.
type: string
default: 4.2.1-stable
pull_request: pull_request:
branches: [ master ] branches: [ master ]
@ -23,11 +18,12 @@ on:
- "LICENSE" - "LICENSE"
- "**/*.png" - "**/*.png"
- "demo/*" - "demo/*"
inputs: - "doc/*"
godot-treeish:
description: A tag, branch or commit hash in the Godot repository. # Global Settings.
type: string env:
default: 4.2.1-stable GODOT_REF: "4.2.1-stable"
GODOT_CPP_REF: "4.2"
jobs: jobs:
unit-tests: unit-tests:
@ -45,7 +41,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: godotengine/godot repository: godotengine/godot
ref: ${{ inputs.godot-treeish }} ref: ${{ env.GODOT_REF }}
- name: Clone LimboAI module - name: Clone LimboAI module
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -67,11 +63,11 @@ jobs:
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: ${{github.workspace}}/.scons_cache/ path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-treeish}}-${{github.ref}}-${{github.sha}} key: ${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}-${{github.sha}}
restore-keys: | restore-keys: |
${{env.BIN}}-${{inputs.godot-treeish}}-${{github.ref}}-${{github.sha}} ${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}-${{github.sha}}
${{env.BIN}}-${{inputs.godot-treeish}}-${{github.ref}} ${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}
${{env.BIN}}-${{inputs.godot-treeish}} ${{env.BIN}}-${{env.GODOT_REF}}
continue-on-error: true continue-on-error: true
- name: Set up Python 3.x - name: Set up Python 3.x
@ -107,26 +103,50 @@ jobs:
run: | run: |
bin/${{ env.BIN }} --test --headless bin/${{ env.BIN }} --test --headless
cache-env:
runs-on: ubuntu-latest
outputs:
godot-ref: ${{ steps.cache-env.outputs.godot-ref }}
godot-cpp-ref: ${{ steps.cache-env.outputs.godot-cpp-ref }}
steps:
- name: Cache env
id: cache-env
run: |
echo "godot-ref=${GODOT_REF}" >> "$GITHUB_OUTPUT"
echo "godot-cpp-ref=${GODOT_CPP_REF}" >> "$GITHUB_OUTPUT"
linux-test-build: linux-test-build:
name: 🐧 Linux test build name: 🐧 Linux
needs: cache-env
uses: ./.github/workflows/linux.yml uses: ./.github/workflows/linux.yml
with: with:
godot-treeish: ${{ inputs.godot-treeish }} godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }} limboai-treeish: ${{ github.sha }}
test-build: true test-build: true
windows-test-build: windows-test-build:
name: 🪟 Windows test build name: 🪟 Windows
needs: cache-env
uses: ./.github/workflows/windows.yml uses: ./.github/workflows/windows.yml
with: with:
godot-treeish: ${{ inputs.godot-treeish }} godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }} limboai-treeish: ${{ github.sha }}
test-build: true test-build: true
macos-test-build: macos-test-build:
name: 🍎 macOS test build name: 🍎 macOS
needs: cache-env
uses: ./.github/workflows/macos.yml uses: ./.github/workflows/macos.yml
with: with:
godot-treeish: ${{ inputs.godot-treeish }} godot-treeish: ${{ needs.cache-env.outputs.godot-ref }}
limboai-treeish: ${{ github.sha }}
test-build: true
gdextension:
name: 🔌 GDExtension
needs: cache-env
uses: ./.github/workflows/gdextension.yml
with:
godot-cpp-treeish: ${{ needs.cache-env.outputs.godot-cpp-ref }}
limboai-treeish: ${{ github.sha }} limboai-treeish: ${{ github.sha }}
test-build: true test-build: true

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
# LimboAI-specific
demo/addons/
icons/*.import
# Godot auto generated files # Godot auto generated files
*.gen.* *.gen.*
.import/ .import/

2
SCsub
View File

@ -5,6 +5,8 @@ Import("env_modules")
module_env = env.Clone() module_env = env.Clone()
module_env.Append(CPPDEFINES = ['LIMBOAI_MODULE'])
module_env.add_source_files(env.modules_sources, "*.cpp") module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.add_source_files(env.modules_sources, "blackboard/*.cpp") module_env.add_source_files(env.modules_sources, "blackboard/*.cpp")
module_env.add_source_files(env.modules_sources, "blackboard/bb_param/*.cpp") module_env.add_source_files(env.modules_sources, "blackboard/bb_param/*.cpp")

View File

@ -13,7 +13,6 @@
#define BB_AABB_H #define BB_AABB_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBAabb : public BBParam { class BBAabb : public BBParam {
GDCLASS(BBAabb, BBParam); GDCLASS(BBAabb, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_ARRAY_H #define BB_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBArray : public BBParam { class BBArray : public BBParam {
GDCLASS(BBArray, BBParam); GDCLASS(BBArray, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_BASIS_H #define BB_BASIS_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBBasis : public BBParam { class BBBasis : public BBParam {
GDCLASS(BBBasis, BBParam); GDCLASS(BBBasis, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_BOOL_H #define BB_BOOL_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBBool : public BBParam { class BBBool : public BBParam {
GDCLASS(BBBool, BBParam); GDCLASS(BBBool, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_BYTE_ARRAY_H #define BB_BYTE_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBByteArray : public BBParam { class BBByteArray : public BBParam {
GDCLASS(BBByteArray, BBParam); GDCLASS(BBByteArray, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_COLOR_H #define BB_COLOR_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBColor : public BBParam { class BBColor : public BBParam {
GDCLASS(BBColor, BBParam); GDCLASS(BBColor, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_COLOR_ARRAY_H #define BB_COLOR_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBColorArray : public BBParam { class BBColorArray : public BBParam {
GDCLASS(BBColorArray, BBParam); GDCLASS(BBColorArray, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_DICTIONARY_H #define BB_DICTIONARY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBDictionary : public BBParam { class BBDictionary : public BBParam {
GDCLASS(BBDictionary, BBParam); GDCLASS(BBDictionary, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_FLOAT_H #define BB_FLOAT_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBFloat : public BBParam { class BBFloat : public BBParam {
GDCLASS(BBFloat, BBParam); GDCLASS(BBFloat, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_FLOAT_ARRAY_H #define BB_FLOAT_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBFloatArray : public BBParam { class BBFloatArray : public BBParam {
GDCLASS(BBFloatArray, BBParam); GDCLASS(BBFloatArray, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_INT_H #define BB_INT_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBInt : public BBParam { class BBInt : public BBParam {
GDCLASS(BBInt, BBParam); GDCLASS(BBInt, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_INT_ARRAY_H #define BB_INT_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBIntArray : public BBParam { class BBIntArray : public BBParam {
GDCLASS(BBIntArray, BBParam); GDCLASS(BBIntArray, BBParam);

View File

@ -10,9 +10,15 @@
*/ */
#include "bb_node.h" #include "bb_node.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/variant/variant.h"
#include "scene/main/node.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) { 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_agent == nullptr, Variant());
@ -28,7 +34,7 @@ Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard,
if (val.get_type() == Variant::NODE_PATH) { if (val.get_type() == Variant::NODE_PATH) {
Node *agent = Object::cast_to<Node>(p_agent); Node *agent = Object::cast_to<Node>(p_agent);
ERR_FAIL_COND_V_MSG(agent == nullptr, Variant(), "BBNode: p_agent must be a Node."); ERR_FAIL_COND_V_MSG(agent == nullptr, Variant(), "BBNode: p_agent must be a Node.");
return agent->get_node(val); return agent->get_node_or_null(val);
} else { } else {
Object *obj = val; Object *obj = val;
if (unlikely(obj == nullptr && val.get_type() != Variant::NIL)) { if (unlikely(obj == nullptr && val.get_type() != Variant::NIL)) {

View File

@ -13,7 +13,6 @@
#define BB_NODE_H #define BB_NODE_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBNode : public BBParam { class BBNode : public BBParam {
GDCLASS(BBNode, BBParam); GDCLASS(BBNode, BBParam);

View File

@ -11,14 +11,20 @@
#include "bb_param.h" #include "bb_param.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "core/core_bind.h" #include "core/core_bind.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/object/object.h" #include "core/object/object.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "core/variant/variant_utility.h" #include "core/variant/variant_utility.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
VARIANT_ENUM_CAST(BBParam::ValueSource); VARIANT_ENUM_CAST(BBParam::ValueSource);
@ -49,18 +55,22 @@ void BBParam::set_variable(const String &p_value) {
emit_changed(); emit_changed();
} }
#ifdef LIMBOAI_MODULE
String BBParam::to_string() { String BBParam::to_string() {
#elif LIMBOAI_GDEXTENSION
String BBParam::_to_string() {
#endif
if (value_source == SAVED_VALUE) { if (value_source == SAVED_VALUE) {
String s = saved_value.stringify(); String s = saved_value.stringify();
switch (get_type()) { switch (get_type()) {
case Variant::STRING: { case Variant::STRING: {
s = s.c_escape().quote(); s = "\"" + s.c_escape() + "\"";
} break; } break;
case Variant::STRING_NAME: { case Variant::STRING_NAME: {
s = "&" + s.c_escape().quote(); s = "&\"" + s.c_escape() + "\"";
} break; } break;
case Variant::NODE_PATH: { case Variant::NODE_PATH: {
s = "^" + s.c_escape().quote(); s = "^\"" + s.c_escape() + "\"";
} break; } break;
default: { default: {
} break; } break;

View File

@ -12,13 +12,22 @@
#ifndef BB_PARAM_H #ifndef BB_PARAM_H
#define BB_PARAM_H #define BB_PARAM_H
#include "modules/limboai/blackboard/blackboard.h" #include "../../blackboard/blackboard.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/object/object.h" #include "core/object/object.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#include "core/variant/variant.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 { class BBParam : public Resource {
GDCLASS(BBParam, Resource); GDCLASS(BBParam, Resource);
@ -42,8 +51,12 @@ protected:
static void _bind_methods(); static void _bind_methods();
_FORCE_INLINE_ void _assign_default_value() { _FORCE_INLINE_ void _assign_default_value() {
#ifdef LIMBOAI_MODULE
Callable::CallError err; Callable::CallError err;
Variant::construct(get_type(), saved_value, nullptr, 0, err); Variant::construct(get_type(), saved_value, nullptr, 0, err);
#elif LIMBOAI_GDEXTENSION
saved_value.clear();
#endif
} }
void _get_property_list(List<PropertyInfo> *p_list) const; void _get_property_list(List<PropertyInfo> *p_list) const;
@ -60,7 +73,11 @@ public:
void set_variable(const String &p_value); void set_variable(const String &p_value);
String get_variable() const { return variable; } String get_variable() const { return variable; }
#ifdef LIMBOAI_MODULE
virtual String to_string() override; virtual String to_string() override;
#elif LIMBOAI_GDEXTENSION
virtual String _to_string();
#endif
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()); virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());

View File

@ -13,7 +13,6 @@
#define BB_PLANE_H #define BB_PLANE_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBPlane : public BBParam { class BBPlane : public BBParam {
GDCLASS(BBPlane, BBParam); GDCLASS(BBPlane, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_QUATERNION_H #define BB_QUATERNION_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBQuaternion : public BBParam { class BBQuaternion : public BBParam {
GDCLASS(BBQuaternion, BBParam); GDCLASS(BBQuaternion, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_RECT2_H #define BB_RECT2_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBRect2 : public BBParam { class BBRect2 : public BBParam {
GDCLASS(BBRect2, BBParam); GDCLASS(BBRect2, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_RECT2I_H #define BB_RECT2I_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBRect2i : public BBParam { class BBRect2i : public BBParam {
GDCLASS(BBRect2i, BBParam); GDCLASS(BBRect2i, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_STRING_H #define BB_STRING_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBString : public BBParam { class BBString : public BBParam {
GDCLASS(BBString, BBParam); GDCLASS(BBString, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_STRING_ARRAY_H #define BB_STRING_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBStringArray : public BBParam { class BBStringArray : public BBParam {
GDCLASS(BBStringArray, BBParam); GDCLASS(BBStringArray, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_STRING_NAME_H #define BB_STRING_NAME_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBStringName : public BBParam { class BBStringName : public BBParam {
GDCLASS(BBStringName, BBParam); GDCLASS(BBStringName, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_TRANSFORM2D_H #define BB_TRANSFORM2D_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBTransform2D : public BBParam { class BBTransform2D : public BBParam {
GDCLASS(BBTransform2D, BBParam); GDCLASS(BBTransform2D, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_TRANSFORM3D_H #define BB_TRANSFORM3D_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBTransform3D : public BBParam { class BBTransform3D : public BBParam {
GDCLASS(BBTransform3D, BBParam); GDCLASS(BBTransform3D, BBParam);

View File

@ -10,8 +10,6 @@
*/ */
#include "bb_variant.h" #include "bb_variant.h"
#include "core/object/object.h"
#include "core/variant/variant.h"
void BBVariant::set_type(Variant::Type p_type) { void BBVariant::set_type(Variant::Type p_type) {
if (type != p_type) { if (type != p_type) {

View File

@ -13,8 +13,6 @@
#define BB_VARIANT_H #define BB_VARIANT_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
#include "core/variant/variant.h"
class BBVariant : public BBParam { class BBVariant : public BBParam {
GDCLASS(BBVariant, BBParam); GDCLASS(BBVariant, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR2_H #define BB_VECTOR2_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector2 : public BBParam { class BBVector2 : public BBParam {
GDCLASS(BBVector2, BBParam); GDCLASS(BBVector2, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR2_ARRAY_H #define BB_VECTOR2_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector2Array : public BBParam { class BBVector2Array : public BBParam {
GDCLASS(BBVector2Array, BBParam); GDCLASS(BBVector2Array, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR2I_H #define BB_VECTOR2I_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector2i : public BBParam { class BBVector2i : public BBParam {
GDCLASS(BBVector2i, BBParam); GDCLASS(BBVector2i, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR3_H #define BB_VECTOR3_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector3 : public BBParam { class BBVector3 : public BBParam {
GDCLASS(BBVector3, BBParam); GDCLASS(BBVector3, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR3_ARRAY_H #define BB_VECTOR3_ARRAY_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector3Array : public BBParam { class BBVector3Array : public BBParam {
GDCLASS(BBVector3Array, BBParam); GDCLASS(BBVector3Array, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR3I_H #define BB_VECTOR3I_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector3i : public BBParam { class BBVector3i : public BBParam {
GDCLASS(BBVector3i, BBParam); GDCLASS(BBVector3i, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR4_H #define BB_VECTOR4_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector4 : public BBParam { class BBVector4 : public BBParam {
GDCLASS(BBVector4, BBParam); GDCLASS(BBVector4, BBParam);

View File

@ -13,7 +13,6 @@
#define BB_VECTOR4I_H #define BB_VECTOR4I_H
#include "bb_param.h" #include "bb_param.h"
#include "core/object/object.h"
class BBVector4i : public BBParam { class BBVector4i : public BBParam {
GDCLASS(BBVector4i, BBParam); GDCLASS(BBVector4i, BBParam);

View File

@ -11,9 +11,20 @@
#include "blackboard.h" #include "blackboard.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#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> Blackboard::top() const {
Ref<Blackboard> bb(this); Ref<Blackboard> bb(this);
@ -25,7 +36,7 @@ Ref<Blackboard> Blackboard::top() const {
Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const { Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const {
if (data.has(p_key)) { if (data.has(p_key)) {
return data.get_valid(p_key); return data.get(p_key, Variant());
} else if (parent.is_valid()) { } else if (parent.is_valid()) {
return parent->get_var(p_key, p_default); return parent->get_var(p_key, p_default);
} else { } else {
@ -57,7 +68,7 @@ void Blackboard::prefetch_nodepath_vars(Node *p_node) {
} }
} }
} }
}; }
void Blackboard::_bind_methods() { void Blackboard::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data); ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data);

View File

@ -12,11 +12,22 @@
#ifndef BLACKBOARD_H #ifndef BLACKBOARD_H
#define BLACKBOARD_H #define BLACKBOARD_H
#ifdef LIMBOAI_MODULE
#include "core/object/object.h" #include "core/object/object.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/variant/dictionary.h" #include "core/variant/dictionary.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#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 // LIMBOAI_GDEXTENSION
class Blackboard : public RefCounted { class Blackboard : public RefCounted {
GDCLASS(Blackboard, RefCounted); GDCLASS(Blackboard, RefCounted);

View File

@ -11,10 +11,16 @@
#include "behavior_tree.h" #include "behavior_tree.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/templates/list.h" #include "core/templates/list.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/core/error_macros.hpp"
#endif // ! LIMBOAI_GDEXTENSION
Ref<BehaviorTree> BehaviorTree::clone() const { Ref<BehaviorTree> BehaviorTree::clone() const {
Ref<BehaviorTree> copy = duplicate(false); Ref<BehaviorTree> copy = duplicate(false);
@ -25,6 +31,12 @@ Ref<BehaviorTree> BehaviorTree::clone() const {
return copy; return copy;
} }
void BehaviorTree::copy_other(const Ref<BehaviorTree> &p_other) {
ERR_FAIL_COND(p_other.is_null());
description = p_other->get_description();
root_task = p_other->get_root_task();
}
Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const { 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."); 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(); Ref<BTTask> inst = root_task->clone();
@ -38,6 +50,7 @@ void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task); ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task);
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_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("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("instantiate", "p_agent", "p_blackboard"), &BehaviorTree::instantiate);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");

View File

@ -12,11 +12,18 @@
#ifndef BEHAVIOR_TREE_H #ifndef BEHAVIOR_TREE_H
#define BEHAVIOR_TREE_H #define BEHAVIOR_TREE_H
#include "core/io/resource.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "tasks/bt_task.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
#include <godot_cpp/classes/resource.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
class BehaviorTree : public Resource { class BehaviorTree : public Resource {
GDCLASS(BehaviorTree, Resource); GDCLASS(BehaviorTree, Resource);
@ -28,7 +35,9 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
#ifdef LIMBOAI_MODULE
virtual bool editor_can_reload_from_file() override { return false; } virtual bool editor_can_reload_from_file() override { return false; }
#endif
void set_description(String p_value) { void set_description(String p_value) {
description = p_value; description = p_value;
@ -43,6 +52,7 @@ public:
Ref<BTTask> get_root_task() const { return root_task; } Ref<BTTask> get_root_task() const { return root_task; }
Ref<BehaviorTree> clone() const; 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<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
}; };

View File

@ -11,10 +11,11 @@
#include "bt_player.h" #include "bt_player.h"
#include "modules/limboai/blackboard/blackboard.h" #include "../editor/debugger/limbo_debugger.h"
#include "modules/limboai/editor/debugger/limbo_debugger.h" #include "../util/limbo_compat.h"
#include "modules/limboai/util/limbo_string_names.h" #include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/config/engine.h" #include "core/config/engine.h"
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
@ -25,11 +26,26 @@
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "main/performance.h" #include "main/performance.h"
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
#define GET_TICKS_USEC() (OS::get_singleton()->get_ticks_usec())
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine_debugger.hpp>
#include <godot_cpp/classes/performance.hpp>
#include <godot_cpp/classes/time.hpp>
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
#define GET_TICKS_USEC() (Time::get_singleton()->get_ticks_usec())
#endif // ! LIMBOAI_GDEXTENSION
VARIANT_ENUM_CAST(BTPlayer::UpdateMode); VARIANT_ENUM_CAST(BTPlayer::UpdateMode);
void BTPlayer::_load_tree() { void BTPlayer::_load_tree() {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
} }
#endif #endif
@ -41,7 +57,7 @@ void BTPlayer::_load_tree() {
} }
tree_instance = behavior_tree->instantiate(get_owner(), blackboard); tree_instance = behavior_tree->instantiate(get_owner(), blackboard);
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (EngineDebugger::is_active()) { if (IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
#endif #endif
@ -74,7 +90,7 @@ void BTPlayer::update(double p_delta) {
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
double start = OS::get_singleton()->get_ticks_usec(); double start = GET_TICKS_USEC();
#endif #endif
if (active) { if (active) {
@ -86,7 +102,7 @@ void BTPlayer::update(double p_delta) {
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
double end = OS::get_singleton()->get_ticks_usec(); double end = GET_TICKS_USEC();
update_time_acc += (end - start); update_time_acc += (end - start);
update_time_n += 1.0; update_time_n += 1.0;
#endif #endif
@ -113,7 +129,7 @@ void BTPlayer::_set_monitor_performance(bool p_monitor_performance) {
String(itos(get_instance_id())).md5_text().substr(0, 4)); String(itos(get_instance_id())).md5_text().substr(0, 4));
} }
if (!perf->has_custom_monitor(monitor_id)) { if (!perf->has_custom_monitor(monitor_id)) {
perf->add_custom_monitor(monitor_id, callable_mp(this, &BTPlayer::_get_mean_update_time_msec), Vector<Variant>()); 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)) { } else if (monitor_id != StringName() && perf->has_custom_monitor(monitor_id)) {
perf->remove_custom_monitor(monitor_id); perf->remove_custom_monitor(monitor_id);
@ -130,7 +146,7 @@ double BTPlayer::_get_mean_update_time_msec() {
return 0.0; return 0.0;
} }
#endif // DEBUG_ENABLED #endif // ! DEBUG_ENABLED
void BTPlayer::_notification(int p_notification) { void BTPlayer::_notification(int p_notification) {
switch (p_notification) { switch (p_notification) {
@ -155,16 +171,16 @@ void BTPlayer::_notification(int p_notification) {
} break; } break;
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
} }
} break; } break;
#endif #endif // DEBUG_ENABLED
} }
} }
@ -205,7 +221,6 @@ void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_monitor_performance", "p_value"), &BTPlayer::_set_monitor_performance); 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); 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"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "_set_monitor_performance", "_get_monitor_performance");
ADD_PROPERTY_DEFAULT("monitor_performance", false);
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
} }

View File

@ -12,19 +12,25 @@
#ifndef BT_PLAYER_H #ifndef BT_PLAYER_H
#define BT_PLAYER_H #define BT_PLAYER_H
#include "scene/main/node.h" #include "../blackboard/blackboard.h"
#include "behavior_tree.h" #include "behavior_tree.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "tasks/bt_task.h" #include "tasks/bt_task.h"
#ifdef LIMBOAI_MODULE
#include "scene/main/node.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#endif
class BTPlayer : public Node { class BTPlayer : public Node {
GDCLASS(BTPlayer, Node); GDCLASS(BTPlayer, Node);
public: public:
enum UpdateMode : unsigned int { enum UpdateMode : unsigned int {
IDLE, // automatically call update() during NOTIFICATION_PROCESS IDLE, // automatically call update() during NOTIFICATION_PROCESS
PHYSICS, //# automatically call update() during NOTIFICATION_PHYSICS PHYSICS, // automatically call update() during NOTIFICATION_PHYSICS
MANUAL, // manually update state machine, user must call update(delta) MANUAL, // manually update state machine, user must call update(delta)
}; };
@ -71,8 +77,8 @@ public:
BTPlayer(); BTPlayer();
~BTPlayer(); ~BTPlayer();
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED // Performance monitoring
// Performace monitoring.
private: private:
bool monitor_performance = false; bool monitor_performance = false;
StringName monitor_id; StringName monitor_id;

View File

@ -11,21 +11,27 @@
#include "bt_state.h" #include "bt_state.h"
#include "modules/limboai/editor/debugger/limbo_debugger.h" #include "../editor/debugger/limbo_debugger.h"
#include "modules/limboai/hsm/limbo_state.h" #include "../util/limbo_compat.h"
#include "modules/limboai/util/limbo_string_names.h" #include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/variant/variant.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() { void BTState::_setup() {
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
#endif #endif
@ -51,12 +57,12 @@ void BTState::_update(double p_delta) {
void BTState::_notification(int p_notification) { void BTState::_notification(int p_notification) {
switch (p_notification) { switch (p_notification) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
} }
} break; } break;

View File

@ -12,10 +12,10 @@
#ifndef BT_STATE_H #ifndef BT_STATE_H
#define BT_STATE_H #define BT_STATE_H
#include "modules/limboai/hsm/limbo_state.h" #include "../hsm/limbo_state.h"
#include "modules/limboai/bt/behavior_tree.h" #include "../bt/behavior_tree.h"
#include "modules/limboai/bt/tasks/bt_task.h" #include "../bt/tasks/bt_task.h"
class BTState : public LimboState { class BTState : public LimboState {
GDCLASS(BTState, LimboState); GDCLASS(BTState, LimboState);
@ -30,7 +30,6 @@ protected:
static void _bind_methods(); static void _bind_methods();
virtual void _setup() override; virtual void _setup() override;
// virtual void _enter() override {}
virtual void _exit() override; virtual void _exit() override;
virtual void _update(double p_delta) override; virtual void _update(double p_delta) override;

View File

@ -11,16 +11,14 @@
#include "bt_check_trigger.h" #include "bt_check_trigger.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
#include "core/variant/variant.h"
void BTCheckTrigger::set_variable(String p_variable) { void BTCheckTrigger::set_variable(String p_variable) {
variable = p_variable; variable = p_variable;
emit_changed(); emit_changed();
} }
PackedStringArray BTCheckTrigger::get_configuration_warnings() const { PackedStringArray BTCheckTrigger::get_configuration_warnings() {
PackedStringArray warnings = BTCondition::get_configuration_warnings(); PackedStringArray warnings = BTCondition::get_configuration_warnings();
if (variable.is_empty()) { if (variable.is_empty()) {
warnings.append("Variable is not set."); warnings.append("Variable is not set.");
@ -28,7 +26,7 @@ PackedStringArray BTCheckTrigger::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTCheckTrigger::_generate_name() const { String BTCheckTrigger::_generate_name() {
if (variable.is_empty()) { if (variable.is_empty()) {
return "CheckTrigger ???"; return "CheckTrigger ???";
} }

View File

@ -14,8 +14,6 @@
#include "../bt_condition.h" #include "../bt_condition.h"
#include "core/string/ustring.h"
class BTCheckTrigger : public BTCondition { class BTCheckTrigger : public BTCondition {
GDCLASS(BTCheckTrigger, BTCondition); GDCLASS(BTCheckTrigger, BTCondition);
TASK_CATEGORY(Blackboard); TASK_CATEGORY(Blackboard);
@ -26,14 +24,14 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
void set_variable(String p_variable); void set_variable(String p_variable);
String get_variable() const { return variable; } String get_variable() const { return variable; }
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_CHECK_TRIGGER #endif // BT_CHECK_TRIGGER

View File

@ -11,10 +11,6 @@
#include "bt_check_var.h" #include "bt_check_var.h"
#include "modules/limboai/util/limbo_utility.h"
#include "core/variant/callable.h"
void BTCheckVar::set_variable(String p_variable) { void BTCheckVar::set_variable(String p_variable) {
variable = p_variable; variable = p_variable;
emit_changed(); emit_changed();
@ -29,11 +25,11 @@ void BTCheckVar::set_value(Ref<BBVariant> p_value) {
value = p_value; value = p_value;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
PackedStringArray BTCheckVar::get_configuration_warnings() const { PackedStringArray BTCheckVar::get_configuration_warnings() {
PackedStringArray warnings = BTCondition::get_configuration_warnings(); PackedStringArray warnings = BTCondition::get_configuration_warnings();
if (variable.is_empty()) { if (variable.is_empty()) {
warnings.append("`variable` should be assigned."); warnings.append("`variable` should be assigned.");
@ -44,7 +40,7 @@ PackedStringArray BTCheckVar::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTCheckVar::_generate_name() const { String BTCheckVar::_generate_name() {
if (variable.is_empty()) { if (variable.is_empty()) {
return "CheckVar ???"; return "CheckVar ???";
} }

View File

@ -14,8 +14,8 @@
#include "../bt_condition.h" #include "../bt_condition.h"
#include "modules/limboai/blackboard/bb_param/bb_variant.h" #include "../../../blackboard/bb_param/bb_variant.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
class BTCheckVar : public BTCondition { class BTCheckVar : public BTCondition {
GDCLASS(BTCheckVar, BTCondition); GDCLASS(BTCheckVar, BTCondition);
@ -29,11 +29,11 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
void set_variable(String p_variable); void set_variable(String p_variable);
String get_variable() const { return variable; } String get_variable() const { return variable; }

View File

@ -11,13 +11,7 @@
#include "bt_set_var.h" #include "bt_set_var.h"
#include "modules/limboai/blackboard/bb_param/bb_param.h" String BTSetVar::_generate_name() {
#include "modules/limboai/util/limbo_utility.h"
#include "core/variant/callable.h"
#include "core/variant/variant.h"
String BTSetVar::_generate_name() const {
if (variable.is_empty()) { if (variable.is_empty()) {
return "SetVar ???"; return "SetVar ???";
} }
@ -31,7 +25,7 @@ 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.is_empty(), FAILURE, "BTSetVar: `variable` is not set.");
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set."); ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set.");
Variant result; Variant result;
Variant error_result = SNAME("Error: BTSetVar failed to get value!"); 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_agent(), get_blackboard(), error_result);
ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE."); ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE.");
if (operation == LimboUtility::OPERATION_NONE) { if (operation == LimboUtility::OPERATION_NONE) {
@ -55,7 +49,7 @@ void BTSetVar::set_value(Ref<BBVariant> p_value) {
value = p_value; value = p_value;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
@ -64,7 +58,7 @@ void BTSetVar::set_operation(LimboUtility::Operation p_operation) {
emit_changed(); emit_changed();
} }
PackedStringArray BTSetVar::get_configuration_warnings() const { PackedStringArray BTSetVar::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings(); PackedStringArray warnings = BTAction::get_configuration_warnings();
if (variable.is_empty()) { if (variable.is_empty()) {
warnings.append("`variable` should be assigned."); warnings.append("`variable` should be assigned.");

View File

@ -14,10 +14,8 @@
#include "../bt_action.h" #include "../bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_variant.h" #include "../../../blackboard/bb_param/bb_variant.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
#include "core/string/ustring.h"
class BTSetVar : public BTAction { class BTSetVar : public BTAction {
GDCLASS(BTSetVar, BTAction); GDCLASS(BTSetVar, BTAction);
@ -31,11 +29,11 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
void set_variable(const String &p_variable); void set_variable(const String &p_variable);
String get_variable() const { return variable; } String get_variable() const { return variable; }

View File

@ -11,7 +11,7 @@
#include "bt_action.h" #include "bt_action.h"
PackedStringArray BTAction::get_configuration_warnings() const { PackedStringArray BTAction::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 0) { if (get_child_count_excluding_comments() != 0) {
warnings.append("Action can't have child tasks."); warnings.append("Action can't have child tasks.");

View File

@ -18,7 +18,7 @@ class BTAction : public BTTask {
GDCLASS(BTAction, BTTask); GDCLASS(BTAction, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_ACTION_H #endif // BT_ACTION_H

View File

@ -13,6 +13,11 @@
#include "bt_task.h" #include "bt_task.h"
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine.hpp>
using namespace godot;
#endif
Ref<BTTask> BTComment::clone() const { Ref<BTTask> BTComment::clone() const {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
return BTTask::clone(); return BTTask::clone();
@ -20,7 +25,7 @@ Ref<BTTask> BTComment::clone() const {
return nullptr; return nullptr;
} }
PackedStringArray BTComment::get_configuration_warnings() const { PackedStringArray BTComment::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() > 0) { if (get_child_count_excluding_comments() > 0) {
warnings.append("Can only have other comment tasks as children."); warnings.append("Can only have other comment tasks as children.");

View File

@ -20,7 +20,7 @@ class BTComment : public BTTask {
public: public:
virtual Ref<BTTask> clone() const override; virtual Ref<BTTask> clone() const override;
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_COMMENT #endif // BT_COMMENT_H

View File

@ -11,7 +11,7 @@
#include "bt_composite.h" #include "bt_composite.h"
PackedStringArray BTComposite::get_configuration_warnings() const { PackedStringArray BTComposite::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() < 1) { if (get_child_count_excluding_comments() < 1) {
warnings.append("Composite should have at least one child task."); warnings.append("Composite should have at least one child task.");

View File

@ -18,7 +18,7 @@ class BTComposite : public BTTask {
GDCLASS(BTComposite, BTTask); GDCLASS(BTComposite, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_COMPOSITE_H #endif // BT_COMPOSITE_H

View File

@ -11,7 +11,7 @@
#include "bt_condition.h" #include "bt_condition.h"
PackedStringArray BTCondition::get_configuration_warnings() const { PackedStringArray BTCondition::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 0) { if (get_child_count_excluding_comments() != 0) {
warnings.append("Condition task can't have child tasks."); warnings.append("Condition task can't have child tasks.");

View File

@ -18,7 +18,7 @@ class BTCondition : public BTTask {
GDCLASS(BTCondition, BTTask); GDCLASS(BTCondition, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_CONDITION_H #endif // BT_CONDITION_H

View File

@ -11,7 +11,7 @@
#include "bt_decorator.h" #include "bt_decorator.h"
PackedStringArray BTDecorator::get_configuration_warnings() const { PackedStringArray BTDecorator::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 1) { if (get_child_count_excluding_comments() != 1) {
warnings.append("Decorator should have a single child task."); warnings.append("Decorator should have a single child task.");

View File

@ -18,7 +18,7 @@ class BTDecorator : public BTTask {
GDCLASS(BTDecorator, BTTask) GDCLASS(BTDecorator, BTTask)
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_DECORATOR_H #endif // BT_DECORATOR_H

View File

@ -11,11 +11,12 @@
#include "bt_task.h" #include "bt_task.h"
#include "../../blackboard/blackboard.h"
#include "../../util/limbo_string_names.h"
#include "../../util/limbo_utility.h"
#include "bt_comment.h" #include "bt_comment.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "modules/limboai/util/limbo_string_names.h"
#include "modules/limboai/util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
@ -25,6 +26,19 @@
#include "core/string/ustring.h" #include "core/string/ustring.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/classes/global_constants.hpp"
#include "godot_cpp/core/class_db.hpp"
#include "godot_cpp/variant/dictionary.hpp"
#include "godot_cpp/variant/string_name.hpp"
#include "godot_cpp/variant/typed_array.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "godot_cpp/variant/variant.hpp"
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/script.hpp>
#endif // LIMBOAI_GDEXTENSION
void BT::_bind_methods() { void BT::_bind_methods() {
BIND_ENUM_CONSTANT(FRESH); BIND_ENUM_CONSTANT(FRESH);
@ -33,19 +47,21 @@ void BT::_bind_methods() {
BIND_ENUM_CONSTANT(SUCCESS); BIND_ENUM_CONSTANT(SUCCESS);
} }
String BTTask::_generate_name() const { String BTTask::_generate_name() {
if (get_script_instance()) { String ret;
if (get_script_instance()->has_method(LimboStringNames::get_singleton()->_generate_name)) {
ERR_FAIL_COND_V_MSG(!get_script_instance()->get_script()->is_tool(), "ERROR: not a tool script", "Task script should be a \"tool\" script!"); // Generate name based on script path.
return get_script_instance()->call(LimboStringNames::get_singleton()->_generate_name); Ref<Script> sc = GET_SCRIPT(this);
if (sc.is_valid() && sc->get_path().is_absolute_path()) {
ret = sc->get_path().get_basename().get_file().to_pascal_case();
} }
String script_path = get_script_instance()->get_script()->get_path();
if (!script_path.is_empty()) { // Generate name based on core class name.
// Generate name based on script file if (ret.is_empty()) {
return script_path.get_basename().get_file().trim_prefix("BT").to_pascal_case(); ret = get_class();
} }
}
return get_class().trim_prefix("BT"); return ret.trim_prefix("BT");
} }
Array BTTask::_get_children() const { Array BTTask::_get_children() const {
@ -72,9 +88,20 @@ void BTTask::_set_children(Array p_children) {
} }
} }
String BTTask::get_task_name() const { String BTTask::get_task_name() {
if (data.custom_name.is_empty()) { 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(); return _generate_name();
#elif LIMBOAI_GDEXTENSION
return call(LimboStringNames::get_singleton()->_generate_name);
#endif
} }
return data.custom_name; return data.custom_name;
} }
@ -103,9 +130,7 @@ void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
get_child(i)->initialize(p_agent, p_blackboard); get_child(i)->initialize(p_agent, p_blackboard);
} }
if (!GDVIRTUAL_CALL(_setup)) { VCALL_OR_NATIVE(_setup);
_setup();
}
} }
Ref<BTTask> BTTask::clone() const { Ref<BTTask> BTTask::clone() const {
@ -129,6 +154,7 @@ Ref<BTTask> BTTask::clone() const {
inst->data.children.resize(data.children.size() - num_null); inst->data.children.resize(data.children.size() - num_null);
} }
#ifdef LIMBOAI_MODULE
// Make BBParam properties unique. // Make BBParam properties unique.
List<PropertyInfo> props; List<PropertyInfo> props;
inst->get_property_list(&props); inst->get_property_list(&props);
@ -154,6 +180,34 @@ Ref<BTTask> BTTask::clone() const {
} }
} }
} }
#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)) {
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();
}
res = duplicates[res];
inst->set(prop_name, res);
}
}
}
}
#endif // LIMBOAI_MODULE & LIMBOAI_GDEXTENSION
return inst; return inst;
} }
@ -166,21 +220,22 @@ BT::Status BTTask::execute(double p_delta) {
data.children.get(i)->abort(); data.children.get(i)->abort();
} }
} }
if (!GDVIRTUAL_CALL(_enter)) {
_enter(); VCALL_OR_NATIVE(_enter);
}
} else { } else {
data.elapsed += p_delta; data.elapsed += p_delta;
} }
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) { if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) {
data.status = _tick(p_delta); data.status = _tick(p_delta);
} }
#elif LIMBOAI_GDEXTENSION
data.status = (Status)(int)call(LimboStringNames::get_singleton()->_tick, p_delta);
#endif
if (data.status != RUNNING) { if (data.status != RUNNING) {
if (!GDVIRTUAL_CALL(_exit)) { VCALL_OR_NATIVE(_exit);
_exit();
}
data.elapsed = 0.0; data.elapsed = 0.0;
} }
return data.status; return data.status;
@ -191,9 +246,7 @@ void BTTask::abort() {
get_child(i)->abort(); get_child(i)->abort();
} }
if (data.status == RUNNING) { if (data.status == RUNNING) {
if (!GDVIRTUAL_CALL(_exit)) { VCALL_OR_NATIVE(_exit);
_exit();
}
} }
data.status = FRESH; data.status = FRESH;
data.elapsed = 0.0; data.elapsed = 0.0;
@ -202,7 +255,7 @@ void BTTask::abort() {
int BTTask::get_child_count_excluding_comments() const { int BTTask::get_child_count_excluding_comments() const {
int count = 0; int count = 0;
for (int i = 0; i < data.children.size(); i++) { for (int i = 0; i < data.children.size(); i++) {
if (!data.children[i]->is_class_ptr(BTComment::get_class_ptr_static())) { if (!IS_CLASS(data.children[i], BTComment)) {
count += 1; count += 1;
} }
} }
@ -274,23 +327,28 @@ Ref<BTTask> BTTask::next_sibling() const {
return Ref<BTTask>(); return Ref<BTTask>();
} }
PackedStringArray BTTask::get_configuration_warnings() const { PackedStringArray BTTask::_get_configuration_warnings() {
return PackedStringArray();
}
PackedStringArray BTTask::get_configuration_warnings() {
PackedStringArray ret; PackedStringArray ret;
PackedStringArray warnings; PackedStringArray warnings;
if (GDVIRTUAL_CALL(_get_configuration_warning, warnings)) { VCALL_V(_get_configuration_warnings, warnings); // Get script warnings.
ret.append_array(warnings); ret.append_array(warnings);
}
return ret; return ret;
} }
void BTTask::print_tree(int p_initial_tabs) const { void BTTask::print_tree(int p_initial_tabs) {
String tabs = "--"; String tabs = "--";
for (int i = 0; i < p_initial_tabs; i++) { for (int i = 0; i < p_initial_tabs; i++) {
tabs += "--"; tabs += "--";
} }
print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
PRINT_LINE(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
get_child(i)->print_tree(p_initial_tabs + 1); get_child(i)->print_tree(p_initial_tabs + 1);
} }
@ -333,17 +391,26 @@ void BTTask::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_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, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard");
// ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "BTTask", 0), "", "get_parent");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children"); 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::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"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_elapsed_time");
#ifdef LIMBOAI_MODULE
GDVIRTUAL_BIND(_setup); GDVIRTUAL_BIND(_setup);
GDVIRTUAL_BIND(_enter); GDVIRTUAL_BIND(_enter);
GDVIRTUAL_BIND(_exit); GDVIRTUAL_BIND(_exit);
GDVIRTUAL_BIND(_tick, "p_delta"); GDVIRTUAL_BIND(_tick, "p_delta");
GDVIRTUAL_BIND(_generate_name); GDVIRTUAL_BIND(_generate_name);
GDVIRTUAL_BIND(_get_configuration_warning); 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() { BTTask::BTTask() {

View File

@ -9,15 +9,22 @@
* ============================================================================= * =============================================================================
*/ */
#ifndef BTTASK_H #ifndef BT_TASK_H
#define BTTASK_H #define BT_TASK_H
#include "modules/limboai/blackboard/blackboard.h" #include "../../blackboard/blackboard.h"
#include "modules/limboai/util/limbo_task_db.h" #include "../../util/limbo_compat.h"
#include "../../util/limbo_string_names.h"
#include "../../util/limbo_task_db.h"
#ifdef LIMBOAI_MODULE
#include "core/config/engine.h"
#include "core/error/error_macros.h"
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/math/math_funcs.h"
#include "core/object/object.h" #include "core/object/object.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/os/memory.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
#include "core/templates/vector.h" #include "core/templates/vector.h"
#include "core/typedefs.h" #include "core/typedefs.h"
@ -25,6 +32,15 @@
#include "core/variant/binder_common.h" #include "core/variant/binder_common.h"
#include "core/variant/dictionary.h" #include "core/variant/dictionary.h"
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
/** /**
* Base class for BTTask. * Base class for BTTask.
@ -54,7 +70,7 @@ class BTTask : public BT {
private: private:
friend class BehaviorTree; friend class BehaviorTree;
// Avoid namespace pollution in derived classes. // Avoid namespace pollution in the derived classes.
struct Data { struct Data {
int index = -1; int index = -1;
String custom_name; String custom_name;
@ -69,37 +85,45 @@ private:
Array _get_children() const; Array _get_children() const;
void _set_children(Array children); void _set_children(Array children);
PackedStringArray _get_configuration_warnings(); // ! Scripts only.
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const; virtual String _generate_name();
virtual void _setup() {} virtual void _setup() {}
virtual void _enter() {} virtual void _enter() {}
virtual void _exit() {} virtual void _exit() {}
virtual Status _tick(double p_delta) { return FAILURE; } virtual Status _tick(double p_delta) { return FAILURE; }
#ifdef LIMBOAI_MODULE
GDVIRTUAL0RC(String, _generate_name); GDVIRTUAL0RC(String, _generate_name);
GDVIRTUAL0(_setup); GDVIRTUAL0(_setup);
GDVIRTUAL0(_enter); GDVIRTUAL0(_enter);
GDVIRTUAL0(_exit); GDVIRTUAL0(_exit);
GDVIRTUAL1R(Status, _tick, double); GDVIRTUAL1R(Status, _tick, double);
GDVIRTUAL0RC(PackedStringArray, _get_configuration_warning); GDVIRTUAL0RC(PackedStringArray, _get_configuration_warnings);
#endif // LIMBOAI_MODULE
public: public:
// TODO: GDExtension doesn't have this method hmm...
#ifdef LIMBOAI_MODULE
virtual bool editor_can_reload_from_file() override { return false; } virtual bool editor_can_reload_from_file() override { return false; }
#endif // LIMBOAI_MODULE
_FORCE_INLINE_ Node *get_agent() const { return data.agent; } _FORCE_INLINE_ Node *get_agent() const { return data.agent; }
void set_agent(Node *p_agent) { data.agent = p_agent; } void set_agent(Node *p_agent) { data.agent = p_agent; }
String get_custom_name() const { return data.custom_name; } String get_custom_name() const { return data.custom_name; }
void set_custom_name(const String &p_name); void set_custom_name(const String &p_name);
String get_task_name() const; String get_task_name();
Ref<BTTask> get_root() const; Ref<BTTask> get_root() const;
virtual Ref<BTTask> clone() 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);
virtual PackedStringArray get_configuration_warnings() const; virtual PackedStringArray get_configuration_warnings(); // ! Native version.
Status execute(double p_delta); Status execute(double p_delta);
void abort(); void abort();
@ -129,10 +153,10 @@ public:
bool is_descendant_of(const Ref<BTTask> &p_task) const; bool is_descendant_of(const Ref<BTTask> &p_task) const;
Ref<BTTask> next_sibling() const; Ref<BTTask> next_sibling() const;
void print_tree(int p_initial_tabs = 0) const; void print_tree(int p_initial_tabs = 0);
BTTask(); BTTask();
~BTTask(); ~BTTask();
}; };
#endif // BTTASK_H #endif // BT_TASK_H

View File

@ -11,8 +11,6 @@
#include "bt_parallel.h" #include "bt_parallel.h"
#include "core/object/class_db.h"
void BTParallel::_enter() { void BTParallel::_enter() {
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
get_child(i)->abort(); get_child(i)->abort();

View File

@ -11,25 +11,23 @@
#include "bt_probability_selector.h" #include "bt_probability_selector.h"
#include "modules/limboai/bt/tasks/bt_task.h" #include "../../../util/limbo_compat.h"
#include "core/error/error_macros.h"
double BTProbabilitySelector::get_weight(int p_index) const { double BTProbabilitySelector::get_weight(int p_index) const {
ERR_FAIL_INDEX_V(p_index, get_child_count(), 0.0); ERR_FAIL_INDEX_V(p_index, get_child_count(), 0.0);
ERR_FAIL_COND_V(get_child(p_index)->is_class_ptr(BTComment::get_class_ptr_static()), 0.0); ERR_FAIL_COND_V(IS_CLASS(get_child(p_index), BTComment), 0.0);
return _get_weight(p_index); return _get_weight(p_index);
} }
void BTProbabilitySelector::set_weight(int p_index, double p_weight) { void BTProbabilitySelector::set_weight(int p_index, double p_weight) {
ERR_FAIL_INDEX(p_index, get_child_count()); ERR_FAIL_INDEX(p_index, get_child_count());
ERR_FAIL_COND(get_child(p_index)->is_class_ptr(BTComment::get_class_ptr_static())); ERR_FAIL_COND(IS_CLASS(get_child(p_index), BTComment));
_set_weight(p_index, p_weight); _set_weight(p_index, p_weight);
} }
double BTProbabilitySelector::get_probability(int p_index) const { double BTProbabilitySelector::get_probability(int p_index) const {
ERR_FAIL_INDEX_V(p_index, get_child_count(), 0.0); ERR_FAIL_INDEX_V(p_index, get_child_count(), 0.0);
ERR_FAIL_COND_V(get_child(p_index)->is_class_ptr(BTComment::get_class_ptr_static()), 0.0); ERR_FAIL_COND_V(IS_CLASS(get_child(p_index), BTComment), 0.0);
double total = _get_total_weight(); double total = _get_total_weight();
return total == 0.0 ? 0.0 : _get_weight(p_index) / total; return total == 0.0 ? 0.0 : _get_weight(p_index) / total;
} }
@ -38,7 +36,7 @@ void BTProbabilitySelector::set_probability(int p_index, double p_probability) {
ERR_FAIL_INDEX(p_index, get_child_count()); ERR_FAIL_INDEX(p_index, get_child_count());
ERR_FAIL_COND(p_probability < 0.0); ERR_FAIL_COND(p_probability < 0.0);
ERR_FAIL_COND(p_probability >= 1.0); ERR_FAIL_COND(p_probability >= 1.0);
ERR_FAIL_COND(get_child(p_index)->is_class_ptr(BTComment::get_class_ptr_static())); ERR_FAIL_COND(IS_CLASS(get_child(p_index), BTComment));
double others_total = _get_total_weight() - _get_weight(p_index); double others_total = _get_total_weight() - _get_weight(p_index);
double others_probability = 1.0 - p_probability; double others_probability = 1.0 - p_probability;
@ -52,7 +50,7 @@ void BTProbabilitySelector::set_probability(int p_index, double p_probability) {
bool BTProbabilitySelector::has_probability(int p_index) const { bool BTProbabilitySelector::has_probability(int p_index) const {
ERR_FAIL_INDEX_V(p_index, get_child_count(), false); ERR_FAIL_INDEX_V(p_index, get_child_count(), false);
return !get_child(p_index)->is_class_ptr(BTComment::get_class_ptr_static()); return !IS_CLASS(get_child(p_index), BTComment);
} }
void BTProbabilitySelector::set_abort_on_failure(bool p_abort_on_failure) { void BTProbabilitySelector::set_abort_on_failure(bool p_abort_on_failure) {
@ -98,7 +96,7 @@ void BTProbabilitySelector::_select_task() {
remaining_tasks_weight -= _get_weight(task); remaining_tasks_weight -= _get_weight(task);
} }
double roll = Math::random(0.0, remaining_tasks_weight); double roll = RAND_RANGE(0.0, remaining_tasks_weight);
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
Ref<BTTask> task = get_child(i); Ref<BTTask> task = get_child(i);
if (failed_tasks.has(task)) { if (failed_tasks.has(task)) {

View File

@ -12,11 +12,18 @@
#ifndef BT_PROBABILITY_SELECTOR_H #ifndef BT_PROBABILITY_SELECTOR_H
#define BT_PROBABILITY_SELECTOR_H #define BT_PROBABILITY_SELECTOR_H
#include "modules/limboai/bt/tasks/bt_comment.h" #include "../../../util/limbo_compat.h"
#include "modules/limboai/bt/tasks/bt_composite.h" #include "../bt_comment.h"
#include "../bt_composite.h"
#ifdef LIMBOAI_MODULE
#include "core/core_string_names.h" #include "core/core_string_names.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/templates/hash_set.hpp>
#endif // LIMBOAI_GDEXTENSION
class BTProbabilitySelector : public BTComposite { class BTProbabilitySelector : public BTComposite {
GDCLASS(BTProbabilitySelector, BTComposite); GDCLASS(BTProbabilitySelector, BTComposite);
@ -28,17 +35,17 @@ private:
bool abort_on_failure = false; bool abort_on_failure = false;
void _select_task(); void _select_task();
#define SNAME(m_arg) ([]() -> const StringName & { static StringName sname = _scs_create(m_arg, true); return sname; })()
_FORCE_INLINE_ double _get_weight(int p_index) const { return get_child(p_index)->get_meta(SNAME("_weight_"), 1.0); } _FORCE_INLINE_ double _get_weight(int p_index) const { return get_child(p_index)->get_meta(LW_NAME(_weight_), 1.0); }
_FORCE_INLINE_ double _get_weight(Ref<BTTask> p_task) const { return p_task->get_meta(SNAME("_weight_"), 1.0); } _FORCE_INLINE_ double _get_weight(Ref<BTTask> p_task) const { return p_task->get_meta(LW_NAME(_weight_), 1.0); }
_FORCE_INLINE_ void _set_weight(int p_index, double p_weight) { _FORCE_INLINE_ void _set_weight(int p_index, double p_weight) {
get_child(p_index)->set_meta(SNAME("_weight_"), Variant(p_weight)); get_child(p_index)->set_meta(LW_NAME(_weight_), Variant(p_weight));
get_child(p_index)->emit_signal(CoreStringNames::get_singleton()->changed); get_child(p_index)->emit_signal(LW_NAME(changed));
} }
_FORCE_INLINE_ double _get_total_weight() const { _FORCE_INLINE_ double _get_total_weight() const {
double total = 0.0; double total = 0.0;
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
if (!get_child(i)->is_class_ptr(BTComment::get_class_ptr_static())) { if (!IS_CLASS(get_child(i), BTComment)) {
total += _get_weight(i); total += _get_weight(i);
} }
} }

View File

@ -16,7 +16,7 @@ void BTRandomSelector::_enter() {
if (indicies.size() != get_child_count()) { if (indicies.size() != get_child_count()) {
indicies.resize(get_child_count()); indicies.resize(get_child_count());
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
indicies.set(i, i); indicies[i] = i;
} }
} }
indicies.shuffle(); indicies.shuffle();

View File

@ -14,8 +14,6 @@
#include "../bt_composite.h" #include "../bt_composite.h"
#include "core/templates/vector.h"
class BTRandomSelector : public BTComposite { class BTRandomSelector : public BTComposite {
GDCLASS(BTRandomSelector, BTComposite); GDCLASS(BTRandomSelector, BTComposite);
TASK_CATEGORY(Composites); TASK_CATEGORY(Composites);
@ -28,4 +26,5 @@ protected:
virtual void _enter() override; virtual void _enter() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
}; };
#endif // BT_RANDOM_SELECTOR_H #endif // BT_RANDOM_SELECTOR_H

View File

@ -1,7 +1,7 @@
/** /**
* bt_random_sequence.cpp * bt_random_sequence.cpp
* ============================================================================= * =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk * Copyright 2021-2024 Serhii Snitsaruk
* *
* Use of this source code is governed by an MIT-style * Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
@ -16,7 +16,7 @@ void BTRandomSequence::_enter() {
if (indicies.size() != get_child_count()) { if (indicies.size() != get_child_count()) {
indicies.resize(get_child_count()); indicies.resize(get_child_count());
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
indicies.set(i, i); indicies[i] = i;
} }
} }
indicies.shuffle(); indicies.shuffle();

View File

@ -14,8 +14,6 @@
#include "../bt_composite.h" #include "../bt_composite.h"
#include "core/templates/vector.h"
class BTRandomSequence : public BTComposite { class BTRandomSequence : public BTComposite {
GDCLASS(BTRandomSequence, BTComposite); GDCLASS(BTRandomSequence, BTComposite);
TASK_CATEGORY(Composites); TASK_CATEGORY(Composites);
@ -28,4 +26,5 @@ protected:
virtual void _enter() override; virtual void _enter() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
}; };
#endif // BT_RANDOM_SEQUENCE_H #endif // BT_RANDOM_SEQUENCE_H

View File

@ -11,10 +11,13 @@
#include "bt_cooldown.h" #include "bt_cooldown.h"
#include "core/math/math_funcs.h" #ifdef LIMBOAI_MODULE
#include "core/object/class_db.h"
#include "core/variant/array.h"
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/scene_tree.hpp>
#endif
//**** Setters / Getters //**** Setters / Getters
@ -45,7 +48,7 @@ void BTCooldown::set_cooldown_state_var(String p_value) {
//**** Task Implementation //**** Task Implementation
String BTCooldown::_generate_name() const { String BTCooldown::_generate_name() {
return vformat("Cooldown %s sec", Math::snapped(duration, 0.001)); return vformat("Cooldown %s sec", Math::snapped(duration, 0.001));
} }
@ -76,8 +79,9 @@ void BTCooldown::_chill() {
if (timer.is_valid()) { if (timer.is_valid()) {
timer->set_time_left(duration); timer->set_time_left(duration);
} else { } else {
timer = SceneTree::get_singleton()->create_timer(duration, process_pause); timer = SCENE_TREE()->create_timer(duration, process_pause);
timer->connect("timeout", callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT); ERR_FAIL_NULL(timer);
timer->connect(LW_NAME(timeout), callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT);
} }
} }

View File

@ -14,7 +14,13 @@
#include "../bt_decorator.h" #include "../bt_decorator.h"
#ifdef LIMBOAI_MODULE
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/scene_tree_timer.hpp>
#endif
class BTCooldown : public BTDecorator { class BTCooldown : public BTDecorator {
GDCLASS(BTCooldown, BTDecorator); GDCLASS(BTCooldown, BTDecorator);
@ -35,7 +41,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _setup() override; virtual void _setup() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;

View File

@ -11,19 +11,12 @@
#include "bt_delay.h" #include "bt_delay.h"
#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/variant/array.h"
#include "core/variant/variant.h"
void BTDelay::set_seconds(double p_value) { void BTDelay::set_seconds(double p_value) {
seconds = p_value; seconds = p_value;
emit_changed(); emit_changed();
} }
String BTDelay::_generate_name() const { String BTDelay::_generate_name() {
return vformat("Delay %s sec", Math::snapped(seconds, 0.001)); return vformat("Delay %s sec", Math::snapped(seconds, 0.001));
} }

View File

@ -24,7 +24,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:

View File

@ -11,12 +11,12 @@
#include "bt_for_each.h" #include "bt_for_each.h"
#include "modules/limboai/blackboard/blackboard.h" #include "../../../blackboard/blackboard.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_list.h" #include "core/error/error_list.h"
#include "core/error/error_macros.h" #endif
#include "core/variant/variant.h"
//**** Setters / Getters //**** Setters / Getters
@ -32,7 +32,7 @@ void BTForEach::set_save_var(String p_value) {
//**** Task Implementation //**** Task Implementation
String BTForEach::_generate_name() const { String BTForEach::_generate_name() {
return vformat("ForEach %s in %s", return vformat("ForEach %s in %s",
LimboUtility::get_singleton()->decorate_var(save_var), LimboUtility::get_singleton()->decorate_var(save_var),
LimboUtility::get_singleton()->decorate_var(array_var)); LimboUtility::get_singleton()->decorate_var(array_var));
@ -51,7 +51,7 @@ BT::Status BTForEach::_tick(double p_delta) {
if (arr.size() == 0) { if (arr.size() == 0) {
return SUCCESS; return SUCCESS;
} }
Variant elem = arr.get(current_idx); Variant elem = arr[current_idx];
get_blackboard()->set_var(save_var, elem); get_blackboard()->set_var(save_var, elem);
Status status = get_child(0)->execute(p_delta); Status status = get_child(0)->execute(p_delta);

View File

@ -27,7 +27,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _enter() override; virtual void _enter() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;

View File

@ -11,12 +11,6 @@
#include "bt_new_scope.h" #include "bt_new_scope.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "core/error/error_macros.h"
#include "core/os/memory.h"
#include "core/string/ustring.h"
void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) { void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_COND(p_agent == nullptr);
ERR_FAIL_COND(p_blackboard == nullptr); ERR_FAIL_COND(p_blackboard == nullptr);

View File

@ -11,18 +11,20 @@
#include "bt_probability.h" #include "bt_probability.h"
#include "../../../util/limbo_compat.h"
void BTProbability::set_run_chance(float p_value) { void BTProbability::set_run_chance(float p_value) {
run_chance = p_value; run_chance = p_value;
emit_changed(); emit_changed();
} }
String BTProbability::_generate_name() const { String BTProbability::_generate_name() {
return vformat("Probability %.1f%%", run_chance); return vformat("Probability %.1f%%", run_chance);
} }
BT::Status BTProbability::_tick(double p_delta) { BT::Status BTProbability::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator has no child."); ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator has no child.");
if (get_child(0)->get_status() == RUNNING || Math::randf() <= run_chance) { if (get_child(0)->get_status() == RUNNING || RANDF() <= run_chance) {
return get_child(0)->execute(p_delta); return get_child(0)->execute(p_delta);
} }
return FAILURE; return FAILURE;

View File

@ -24,7 +24,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:

View File

@ -11,18 +11,9 @@
#include "bt_repeat.h" #include "bt_repeat.h"
#include "core/object/object.h" String BTRepeat::_generate_name() {
#include "core/string/ustring.h"
#include "core/variant/variant.h"
static String repeat_forever_str;
String BTRepeat::_generate_name() const {
if (forever) { if (forever) {
if (repeat_forever_str.is_empty()) { return LW_NAME(repeat_forever);
repeat_forever_str.parse_utf8("Repeat ∞");
}
return repeat_forever_str;
} }
return vformat("Repeat x%s", times); return vformat("Repeat x%s", times);
} }
@ -81,3 +72,6 @@ void BTRepeat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "times", PROPERTY_HINT_RANGE, "1,65535", PROPERTY_USAGE_NONE), "set_times", "get_times"); ADD_PROPERTY(PropertyInfo(Variant::INT, "times", PROPERTY_HINT_RANGE, "1,65535", PROPERTY_USAGE_NONE), "set_times", "get_times");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "abort_on_failure", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_abort_on_failure", "get_abort_on_failure"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "abort_on_failure", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_abort_on_failure", "get_abort_on_failure");
} }
BTRepeat::BTRepeat() {
}

View File

@ -29,7 +29,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const; void _get_property_list(List<PropertyInfo> *p_list) const;
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _enter() override; virtual void _enter() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
@ -42,6 +42,8 @@ public:
void set_abort_on_failure(bool p_value); void set_abort_on_failure(bool p_value);
bool get_abort_on_failure() const { return abort_on_failure; } bool get_abort_on_failure() const { return abort_on_failure; }
BTRepeat();
}; };
#endif // BT_REPEAT_H #endif // BT_REPEAT_H

View File

@ -16,7 +16,7 @@ void BTRunLimit::set_run_limit(int p_value) {
emit_changed(); emit_changed();
} }
String BTRunLimit::_generate_name() const { String BTRunLimit::_generate_name() {
return vformat("RunLimit x%d", run_limit); return vformat("RunLimit x%d", run_limit);
} }

View File

@ -25,7 +25,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:

View File

@ -11,20 +11,12 @@
#include "bt_subtree.h" #include "bt_subtree.h"
#include "bt_new_scope.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "core/config/engine.h"
#include "core/error/error_macros.h"
#include "core/typedefs.h"
#include "core/variant/variant.h"
void BTSubtree::set_subtree(const Ref<BehaviorTree> &p_value) { void BTSubtree::set_subtree(const Ref<BehaviorTree> &p_value) {
subtree = p_value; subtree = p_value;
emit_changed(); emit_changed();
} }
String BTSubtree::_generate_name() const { String BTSubtree::_generate_name() {
String s; String s;
if (subtree.is_null()) { if (subtree.is_null()) {
s = "(unassigned)"; s = "(unassigned)";
@ -51,7 +43,7 @@ BT::Status BTSubtree::_tick(double p_delta) {
return get_child(0)->execute(p_delta); return get_child(0)->execute(p_delta);
} }
PackedStringArray BTSubtree::get_configuration_warnings() const { PackedStringArray BTSubtree::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); // ! BTDecorator skipped intentionally PackedStringArray warnings = BTTask::get_configuration_warnings(); // ! BTDecorator skipped intentionally
if (subtree.is_null()) { if (subtree.is_null()) {
warnings.append("Subtree needs to be assigned."); warnings.append("Subtree needs to be assigned.");

View File

@ -14,7 +14,7 @@
#include "bt_new_scope.h" #include "bt_new_scope.h"
#include "modules/limboai/bt/behavior_tree.h" #include "../../../bt/behavior_tree.h"
class BTSubtree : public BTNewScope { class BTSubtree : public BTNewScope {
GDCLASS(BTSubtree, BTNewScope); GDCLASS(BTSubtree, BTNewScope);
@ -26,7 +26,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
@ -34,7 +34,7 @@ public:
Ref<BehaviorTree> get_subtree() const { return subtree; } Ref<BehaviorTree> get_subtree() const { return subtree; }
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) override; virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) override;
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_SUBTREE_H #endif // BT_SUBTREE_H

View File

@ -11,14 +11,12 @@
#include "bt_time_limit.h" #include "bt_time_limit.h"
#include "core/math/math_funcs.h"
void BTTimeLimit::set_time_limit(double p_value) { void BTTimeLimit::set_time_limit(double p_value) {
time_limit = p_value; time_limit = p_value;
emit_changed(); emit_changed();
} }
String BTTimeLimit::_generate_name() const { String BTTimeLimit::_generate_name() {
return vformat("TimeLimit %s sec", Math::snapped(time_limit, 0.001)); return vformat("TimeLimit %s sec", Math::snapped(time_limit, 0.001));
} }

View File

@ -24,7 +24,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:

View File

@ -17,7 +17,7 @@ void BTAwaitAnimation::set_animation_player(Ref<BBNode> p_animation_player) {
animation_player_param = p_animation_player; animation_player_param = p_animation_player;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) {
animation_player_param->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); animation_player_param->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
@ -33,12 +33,12 @@ void BTAwaitAnimation::set_max_time(double p_max_time) {
//**** Task Implementation //**** Task Implementation
PackedStringArray BTAwaitAnimation::get_configuration_warnings() const { PackedStringArray BTAwaitAnimation::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings(); PackedStringArray warnings = BTAction::get_configuration_warnings();
if (animation_player_param.is_null()) { if (animation_player_param.is_null()) {
warnings.append("Animation Player parameter is not set."); warnings.append("Animation Player parameter is not set.");
} else { } else {
if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value().is_zero()) { if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value() == Variant()) {
warnings.append("Path to AnimationPlayer node is not set."); warnings.append("Path to AnimationPlayer node is not set.");
} else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) { } else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) {
warnings.append("AnimationPlayer blackboard variable is not set."); warnings.append("AnimationPlayer blackboard variable is not set.");
@ -53,7 +53,7 @@ PackedStringArray BTAwaitAnimation::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTAwaitAnimation::_generate_name() const { String BTAwaitAnimation::_generate_name() {
return "AwaitAnimation" + return "AwaitAnimation" +
(animation_name != StringName() ? vformat(" \"%s\"", animation_name) : " ???") + (animation_name != StringName() ? vformat(" \"%s\"", animation_name) : " ???") +
vformat(" max_time: %ss", Math::snapped(max_time, 0.001)); vformat(" max_time: %ss", Math::snapped(max_time, 0.001));

View File

@ -14,9 +14,15 @@
#include "../bt_action.h" #include "../bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_node.h" #include "../../../blackboard/bb_param/bb_node.h"
#ifdef LIMBOAI_MODULE
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/animation_player.hpp>
#endif
class BTAwaitAnimation : public BTAction { class BTAwaitAnimation : public BTAction {
GDCLASS(BTAwaitAnimation, BTAction); GDCLASS(BTAwaitAnimation, BTAction);
@ -33,7 +39,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _setup() override; virtual void _setup() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
@ -47,7 +53,7 @@ public:
void set_max_time(double p_max_time); void set_max_time(double p_max_time);
double get_max_time() const { return max_time; } double get_max_time() const { return max_time; }
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_AWAIT_ANIMATION #endif // BT_AWAIT_ANIMATION_H

View File

@ -11,10 +11,6 @@
#include "bt_check_agent_property.h" #include "bt_check_agent_property.h"
#include "modules/limboai/util/limbo_utility.h"
#include "core/variant/callable.h"
void BTCheckAgentProperty::set_property(StringName p_prop) { void BTCheckAgentProperty::set_property(StringName p_prop) {
property = p_prop; property = p_prop;
emit_changed(); emit_changed();
@ -29,11 +25,11 @@ void BTCheckAgentProperty::set_value(Ref<BBVariant> p_value) {
value = p_value; value = p_value;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
PackedStringArray BTCheckAgentProperty::get_configuration_warnings() const { PackedStringArray BTCheckAgentProperty::get_configuration_warnings() {
PackedStringArray warnings = BTCondition::get_configuration_warnings(); PackedStringArray warnings = BTCondition::get_configuration_warnings();
if (property == StringName()) { if (property == StringName()) {
warnings.append("`property` should be assigned."); warnings.append("`property` should be assigned.");
@ -44,7 +40,7 @@ PackedStringArray BTCheckAgentProperty::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTCheckAgentProperty::_generate_name() const { String BTCheckAgentProperty::_generate_name() {
if (property == StringName()) { if (property == StringName()) {
return "CheckAgentProperty ???"; return "CheckAgentProperty ???";
} }
@ -58,9 +54,13 @@ BT::Status BTCheckAgentProperty::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(property == StringName(), FAILURE, "BTCheckAgentProperty: `property` is not set."); ERR_FAIL_COND_V_MSG(property == StringName(), FAILURE, "BTCheckAgentProperty: `property` is not set.");
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTCheckAgentProperty: `value` is not set."); ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTCheckAgentProperty: `value` is not set.");
#ifdef LIMBOAI_MODULE
bool r_valid; bool r_valid;
Variant left_value = get_agent()->get(property, &r_valid); Variant left_value = get_agent()->get(property, &r_valid);
ERR_FAIL_COND_V_MSG(r_valid == false, FAILURE, vformat("BTCheckAgentProperty: Agent has no property named \"%s\"", property)); ERR_FAIL_COND_V_MSG(r_valid == false, FAILURE, vformat("BTCheckAgentProperty: Agent has no property named \"%s\"", property));
#elif LIMBOAI_GDEXTENSION
Variant left_value = get_agent()->get(property);
#endif
Variant right_value = value->get_value(get_agent(), get_blackboard()); Variant right_value = value->get_value(get_agent(), get_blackboard());

View File

@ -14,10 +14,8 @@
#include "../bt_condition.h" #include "../bt_condition.h"
#include "modules/limboai/blackboard/bb_param/bb_variant.h" #include "../../../blackboard/bb_param/bb_variant.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
#include "core/string/string_name.h"
class BTCheckAgentProperty : public BTCondition { class BTCheckAgentProperty : public BTCondition {
GDCLASS(BTCheckAgentProperty, BTCondition); GDCLASS(BTCheckAgentProperty, BTCondition);
@ -31,7 +29,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
@ -44,7 +42,7 @@ public:
void set_value(Ref<BBVariant> p_value); void set_value(Ref<BBVariant> p_value);
Ref<BBVariant> get_value() const { return value; } Ref<BBVariant> get_value() const { return value; }
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_CHECK_AGENT_PROPERTY #endif // BT_CHECK_AGENT_PROPERTY_H

View File

@ -17,18 +17,18 @@ void BTPauseAnimation::set_animation_player(Ref<BBNode> p_animation_player) {
animation_player_param = p_animation_player; animation_player_param = p_animation_player;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) {
animation_player_param->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); animation_player_param->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
//**** Task Implementation //**** Task Implementation
PackedStringArray BTPauseAnimation::get_configuration_warnings() const { PackedStringArray BTPauseAnimation::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings(); PackedStringArray warnings = BTAction::get_configuration_warnings();
if (animation_player_param.is_null()) { if (animation_player_param.is_null()) {
warnings.append("Animation Player parameter is not set."); warnings.append("Animation Player parameter is not set.");
} else { } else {
if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value().is_zero()) { if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value() == Variant()) {
warnings.append("Path to AnimationPlayer node is not set."); warnings.append("Path to AnimationPlayer node is not set.");
} else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) { } else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) {
warnings.append("AnimationPlayer blackboard variable is not set."); warnings.append("AnimationPlayer blackboard variable is not set.");
@ -37,7 +37,7 @@ PackedStringArray BTPauseAnimation::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTPauseAnimation::_generate_name() const { String BTPauseAnimation::_generate_name() {
return "PauseAnimation"; return "PauseAnimation";
} }

View File

@ -14,9 +14,15 @@
#include "../bt_action.h" #include "../bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_node.h" #include "../../../blackboard/bb_param/bb_node.h"
#ifdef LIMBOAI_MODULE
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/animation_player.hpp>
#endif
class BTPauseAnimation : public BTAction { class BTPauseAnimation : public BTAction {
GDCLASS(BTPauseAnimation, BTAction); GDCLASS(BTPauseAnimation, BTAction);
@ -31,7 +37,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _setup() override; virtual void _setup() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
@ -39,7 +45,7 @@ public:
void set_animation_player(Ref<BBNode> p_animation_player); void set_animation_player(Ref<BBNode> p_animation_player);
Ref<BBNode> get_animation_player() const { return animation_player_param; } Ref<BBNode> get_animation_player() const { return animation_player_param; }
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_PAUSE_ANIMATION #endif // BT_PAUSE_ANIMATION

View File

@ -11,15 +11,13 @@
#include "bt_play_animation.h" #include "bt_play_animation.h"
#include "core/math/math_funcs.h"
//**** Setters / Getters //**** Setters / Getters
void BTPlayAnimation::set_animation_player(Ref<BBNode> p_animation_player) { void BTPlayAnimation::set_animation_player(Ref<BBNode> p_animation_player) {
animation_player_param = p_animation_player; animation_player_param = p_animation_player;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) {
animation_player_param->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); animation_player_param->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
@ -50,12 +48,12 @@ void BTPlayAnimation::set_from_end(bool p_from_end) {
//**** Task Implementation //**** Task Implementation
PackedStringArray BTPlayAnimation::get_configuration_warnings() const { PackedStringArray BTPlayAnimation::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings(); PackedStringArray warnings = BTAction::get_configuration_warnings();
if (animation_player_param.is_null()) { if (animation_player_param.is_null()) {
warnings.append("Animation Player parameter is not set."); warnings.append("Animation Player parameter is not set.");
} else { } else {
if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value().is_zero()) { if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value() == Variant()) {
warnings.append("Path to AnimationPlayer node is not set."); warnings.append("Path to AnimationPlayer node is not set.");
} else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) { } else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) {
warnings.append("AnimationPlayer blackboard variable is not set."); warnings.append("AnimationPlayer blackboard variable is not set.");
@ -67,7 +65,7 @@ PackedStringArray BTPlayAnimation::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTPlayAnimation::_generate_name() const { String BTPlayAnimation::_generate_name() {
return "PlayAnimation" + return "PlayAnimation" +
(animation_name != StringName() ? vformat(" \"%s\"", animation_name) : "") + (animation_name != StringName() ? vformat(" \"%s\"", animation_name) : "") +
(blend >= 0.0 ? vformat(" blend: %ss", Math::snapped(blend, 0.001)) : "") + (blend >= 0.0 ? vformat(" blend: %ss", Math::snapped(blend, 0.001)) : "") +

View File

@ -14,9 +14,15 @@
#include "../bt_action.h" #include "../bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_node.h" #include "../../../blackboard/bb_param/bb_node.h"
#ifdef LIMBOAI_MODULE
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/animation_player.hpp>
#endif
class BTPlayAnimation : public BTAction { class BTPlayAnimation : public BTAction {
GDCLASS(BTPlayAnimation, BTAction); GDCLASS(BTPlayAnimation, BTAction);
@ -36,7 +42,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual void _setup() override; virtual void _setup() override;
virtual void _enter() override; virtual void _enter() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
@ -60,7 +66,7 @@ public:
void set_from_end(bool p_from_end); void set_from_end(bool p_from_end);
bool get_from_end() const { return from_end; } bool get_from_end() const { return from_end; }
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_PLAY_ANIMATION #endif // BT_PLAY_ANIMATION_H

View File

@ -20,7 +20,7 @@ void BTSetAgentProperty::set_value(Ref<BBVariant> p_value) {
value = p_value; value = p_value;
emit_changed(); emit_changed();
if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) { if (Engine::get_singleton()->is_editor_hint() && value.is_valid()) {
value->connect(SNAME("changed"), Callable(this, SNAME("emit_changed"))); value->connect(LW_NAME(changed), Callable(this, LW_NAME(emit_changed)));
} }
} }
@ -29,7 +29,7 @@ void BTSetAgentProperty::set_operation(LimboUtility::Operation p_operation) {
emit_changed(); emit_changed();
} }
PackedStringArray BTSetAgentProperty::get_configuration_warnings() const { PackedStringArray BTSetAgentProperty::get_configuration_warnings() {
PackedStringArray warnings = BTAction::get_configuration_warnings(); PackedStringArray warnings = BTAction::get_configuration_warnings();
if (property == StringName()) { if (property == StringName()) {
warnings.append("`property` should be assigned."); warnings.append("`property` should be assigned.");
@ -40,7 +40,7 @@ PackedStringArray BTSetAgentProperty::get_configuration_warnings() const {
return warnings; return warnings;
} }
String BTSetAgentProperty::_generate_name() const { String BTSetAgentProperty::_generate_name() {
if (property == StringName()) { if (property == StringName()) {
return "SetAgentProperty ???"; return "SetAgentProperty ???";
} }
@ -54,21 +54,29 @@ BT::Status BTSetAgentProperty::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetAgentProperty: `value` is not set."); ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetAgentProperty: `value` is not set.");
Variant result; Variant result;
StringName error_value = SNAME("ErrorGettingValue"); StringName error_value = LW_NAME(error_value);
Variant right_value = value->get_value(get_agent(), get_blackboard(), error_value); Variant right_value = value->get_value(get_agent(), get_blackboard(), error_value);
ERR_FAIL_COND_V_MSG(right_value == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter."); ERR_FAIL_COND_V_MSG(right_value == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter.");
bool r_valid; bool r_valid;
if (operation == LimboUtility::OPERATION_NONE) { if (operation == LimboUtility::OPERATION_NONE) {
result = right_value; result = right_value;
} else { } else {
#ifdef LIMBOAI_MODULE
Variant left_value = get_agent()->get(property, &r_valid); Variant left_value = get_agent()->get(property, &r_valid);
ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Failed to get agent's \"%s\" property. Returning FAILURE.", property)); ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Failed to get agent's \"%s\" property. Returning FAILURE.", property));
#elif LIMBOAI_GDEXTENSION
Variant left_value = get_agent()->get(property);
#endif
result = LimboUtility::get_singleton()->perform_operation(operation, left_value, right_value); result = LimboUtility::get_singleton()->perform_operation(operation, left_value, right_value);
ERR_FAIL_COND_V_MSG(result == Variant(), FAILURE, "BTSetAgentProperty: Operation not valid. Returning FAILURE."); ERR_FAIL_COND_V_MSG(result == Variant(), FAILURE, "BTSetAgentProperty: Operation not valid. Returning FAILURE.");
} }
#ifdef LIMBOAI_MODULE
get_agent()->set(property, result, &r_valid); get_agent()->set(property, result, &r_valid);
ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Couldn't set property \"%s\" with value \"%s\"", property, result)); ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Couldn't set property \"%s\" with value \"%s\"", property, result));
#elif LIMBOAI_GDEXTENSION
get_agent()->set(property, result);
#endif
return SUCCESS; return SUCCESS;
} }

View File

@ -14,8 +14,8 @@
#include "../bt_action.h" #include "../bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_variant.h" #include "../../../blackboard/bb_param/bb_variant.h"
#include "modules/limboai/util/limbo_utility.h" #include "../../../util/limbo_utility.h"
class BTSetAgentProperty : public BTAction { class BTSetAgentProperty : public BTAction {
GDCLASS(BTSetAgentProperty, BTAction); GDCLASS(BTSetAgentProperty, BTAction);
@ -29,11 +29,11 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const override; virtual String _generate_name() override;
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
void set_property(StringName p_prop); void set_property(StringName p_prop);
StringName get_property() const { return property; } StringName get_property() const { return property; }
@ -45,4 +45,4 @@ public:
LimboUtility::Operation get_operation() const { return operation; } LimboUtility::Operation get_operation() const { return operation; }
}; };
#endif // BT_SET_AGENT_PROPERTY #endif // BT_SET_AGENT_PROPERTY_H

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