Compare commits

..

20 Commits

Author SHA1 Message Date
Wilson E. Alvarez aa7d8ea50e
Fix GCC warning for unhandled 'PACKED_VECTOR4_ARRAY' in switch 2024-05-05 09:00:09 -04:00
Wilson E. Alvarez 1a228ba88e
Update EditorPlugin header location
Due to upstream change:

	1bcbbe96c4
2024-05-05 09:00:09 -04:00
Wilson E. Alvarez 4fc3f1d9fc
Update EditorHelpBit calls
Due to upstream change:

	a714cb9f65
2024-05-05 09:00:09 -04:00
Wilson E. Alvarez facb813b44
Add missing MarginContainer header
Due to upstream change:

	7884d63281
2024-05-05 09:00:09 -04:00
Wilson E. Alvarez 0d34c4e887
Fix bottom panel visbility calls
Due to upstream change:

	eb6ca91ba6
2024-05-05 09:00:09 -04:00
Wilson E. Alvarez 2a4fd275cc
Migrate to Tree::set_custom_draw_callback.
Due to upstream change:

	a32a2eaedc
2024-05-05 09:00:09 -04:00
Wilson E. Alvarez 1ba6e861f9
Fix upstream EditorScale header locations
Due to upstream change:

	4b55c81eba
2024-05-05 09:00:09 -04:00
Serhii Snitsaruk 5e961ec6fa
Merge pull request #103 from limbonaut/pre-commit
Add pre-commit configuration
2024-05-03 01:31:25 +02:00
Serhii Snitsaruk bc5d5d8610
Add pre-commit configuration
To install git hook scripts:
  pip install pre-commit
  pre-commit install
2024-05-03 00:21:51 +02:00
Serhii Snitsaruk 75e8e68da4
Merge pull request #100 from TranquilMarmot/patch-1
Add note about how to run demo/tutorial
2024-05-01 21:23:18 +02:00
Nate Moore 4fe4049c3a
game -> showcase 2024-05-01 10:01:44 -07:00
Serhii Snitsaruk 69e921be31
Merge pull request #101 from limbonaut/unit-tests
Add tests for nested HSM flow, tests for dispatch() and get_root(), and fix BBParam saved_value initializing to null
2024-05-01 18:43:13 +02:00
Serhii Snitsaruk c6bb5bad74
Fix: BBParam saved_value defaults to null 2024-05-01 18:09:06 +02:00
Serhii Snitsaruk 2c2f2dd4be
Test: BBParam default values 2024-05-01 18:08:59 +02:00
Serhii Snitsaruk dedffc4f22
Test: Nested HSM flow, dispatch() and get_root() 2024-05-01 18:08:40 +02:00
Nate Moore 4491a23d52
Add note about how to run demo/tutorial
Closes https://github.com/limbonaut/limboai/issues/99
2024-04-30 23:26:00 -07:00
Serhii Snitsaruk 0e843d3193
Merge pull request #95 from limbonaut/decorator-default-tick
BTDecorator: Add default `_tick` implementation
2024-04-30 13:14:02 +02:00
Serhii Snitsaruk 769de9a7e2
Merge pull request #89 from limbonaut/blackboard-api-improvements
Blackboard: Add `create` parameter to `bind_var_to_property` and `link_var`
2024-04-30 11:31:22 +02:00
Serhii Snitsaruk e1c8ce4a58
BTDecorator: Add default `_tick` implementation
The default implementation simply ticks the child task and returns its status.
2024-04-22 11:07:50 +02:00
Serhii Snitsaruk c739a876b0
Blackboard: Add `create` parameter to `bind_var_to_property` and `link_var` 2024-04-09 11:34:22 +02:00
16 changed files with 276 additions and 85 deletions

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

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

View File

@ -34,6 +34,7 @@ Behavior Trees are powerful hierarchical structures used to model and control th
[![Demonstration](https://img.youtube.com/vi/NWaMArUg7mY/0.jpg)](https://www.youtube.com/watch?v=NWaMArUg7mY)
>**🛈 Demo project** lives in the `demo` folder and is available separately in [**Releases**](https://github.com/limbonaut/limboai/releases).
> Run `demo/scenes/showcase.tscn` to get started.
> It also contains a tutorial that introduces behavior trees using examples.
## Features

2
SCsub
View File

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

View File

@ -79,6 +79,9 @@ Variant BBParam::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard,
ERR_FAIL_COND_V(!p_blackboard.is_valid(), p_default);
if (value_source == SAVED_VALUE) {
if (saved_value == Variant()) {
_assign_default_value();
}
return saved_value;
} else {
ERR_FAIL_COND_V_MSG(!p_blackboard->has_var(variable), p_default, vformat("BBParam: Blackboard variable \"%s\" doesn't exist.", variable));
@ -114,6 +117,4 @@ void BBParam::_bind_methods() {
BBParam::BBParam() {
value_source = SAVED_VALUE;
_assign_default_value();
}

View File

@ -64,13 +64,19 @@ void Blackboard::erase_var(const StringName &p_name) {
data.erase(p_name);
}
void Blackboard::bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property) {
ERR_FAIL_COND_MSG(!data.has(p_name), "Blackboard: Binding failed - can't bind variable that doesn't exist.");
void Blackboard::bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create) {
if (!data.has(p_name)) {
if (p_create) {
data.insert(p_name, BBVariable());
} else {
ERR_FAIL_MSG("Blackboard: Can't bind variable that doesn't exist (var: " + p_name + ").");
}
}
data[p_name].bind(p_object, p_property);
}
void Blackboard::unbind_var(const StringName &p_name) {
ERR_FAIL_COND_MSG(data.has(p_name), "Blackboard: Can't unbind variable that doesn't exist.");
ERR_FAIL_COND_MSG(data.has(p_name), "Blackboard: Can't unbind variable that doesn't exist (var: " + p_name + ").");
data[p_name].unbind();
}
@ -78,8 +84,14 @@ void Blackboard::assign_var(const StringName &p_name, const BBVariable &p_var) {
data.insert(p_name, p_var);
}
void Blackboard::link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var) {
ERR_FAIL_COND_MSG(!data.has(p_name), "Blackboard: Can't link variable that doesn't exist (var: " + p_name + ").");
void Blackboard::link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create) {
if (!data.has(p_name)) {
if (p_create) {
data.insert(p_name, BBVariable());
} else {
ERR_FAIL_MSG("Blackboard: Can't link variable that doesn't exist (var: " + p_name + ").");
}
}
ERR_FAIL_COND_MSG(p_target_blackboard.is_null(), "Blackboard: Can't link variable to target blackboard that is null (var: " + p_name + ").");
ERR_FAIL_COND_MSG(!p_target_blackboard->data.has(p_target_var), "Blackboard: Can't link variable to non-existent target (var: " + p_name + ", target: " + p_target_var + ").");
data[p_name] = p_target_blackboard->data[p_target_var];
@ -93,7 +105,7 @@ void Blackboard::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_parent"), &Blackboard::get_parent);
ClassDB::bind_method(D_METHOD("erase_var", "var_name"), &Blackboard::erase_var);
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
ClassDB::bind_method(D_METHOD("bind_var_to_property", "var_name", "object", "property"), &Blackboard::bind_var_to_property);
ClassDB::bind_method(D_METHOD("bind_var_to_property", "var_name", "object", "property", "create"), &Blackboard::bind_var_to_property, DEFVAL(false));
ClassDB::bind_method(D_METHOD("unbind_var", "var_name"), &Blackboard::unbind_var);
ClassDB::bind_method(D_METHOD("link_var", "var_name", "target_blackboard", "target_var"), &Blackboard::link_var);
ClassDB::bind_method(D_METHOD("link_var", "var_name", "target_blackboard", "target_var", "create"), &Blackboard::link_var, DEFVAL(false));
}

View File

@ -51,12 +51,12 @@ public:
bool has_var(const StringName &p_name) const;
void erase_var(const StringName &p_name);
void bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property);
void bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create = false);
void unbind_var(const StringName &p_name);
void assign_var(const StringName &p_name, const BBVariable &p_var);
void link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var);
void link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create = false);
// TODO: Add serialization API.
};

View File

@ -18,3 +18,8 @@ PackedStringArray BTDecorator::get_configuration_warnings() {
}
return warnings;
}
BT::Status BTDecorator::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator doesn't have a child.");
return get_child(0)->execute(p_delta);
}

View File

@ -17,6 +17,9 @@
class BTDecorator : public BTTask {
GDCLASS(BTDecorator, BTTask)
protected:
virtual Status _tick(double p_delta) override;
public:
virtual PackedStringArray get_configuration_warnings() override;
};

View File

@ -33,27 +33,27 @@ Methods
.. table::
:widths: auto
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`bind_var_to_property<class_Blackboard_method_bind_var_to_property>` **(** StringName var_name, Object object, StringName property **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`bind_var_to_property<class_Blackboard_method_bind_var_to_property>` **(** StringName var_name, Object object, StringName property, bool create **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`erase_var<class_Blackboard_method_erase_var>` **(** StringName var_name **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`get_parent<class_Blackboard_method_get_parent>` **(** **)** |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variant | :ref:`get_var<class_Blackboard_method_get_var>` **(** StringName var_name, Variant default=null, bool complain=true **)** |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| bool | :ref:`has_var<class_Blackboard_method_has_var>` **(** StringName var_name **)** |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`link_var<class_Blackboard_method_link_var>` **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`link_var<class_Blackboard_method_link_var>` **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`set_parent<class_Blackboard_method_set_parent>` **(** :ref:`Blackboard<class_Blackboard>` blackboard **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`set_var<class_Blackboard_method_set_var>` **(** StringName var_name, Variant value **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`top<class_Blackboard_method_top>` **(** **)** |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`unbind_var<class_Blackboard_method_unbind_var>` **(** StringName var_name **)** |
+-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator
@ -68,9 +68,9 @@ Method Descriptions
.. rst-class:: classref-method
void **bind_var_to_property** **(** StringName var_name, Object object, StringName property **)**
void **bind_var_to_property** **(** StringName var_name, Object object, StringName property, bool create **)**
Establish a binding between a variable and the object's property specified by ``property`` and ``object``. Changes to the variable update the property, and vice versa.
Establish a binding between a variable and the object's property specified by ``property`` and ``object``. Changes to the variable update the property, and vice versa. If ``create`` is ``true``, the variable will be created if it doesn't exist.
.. rst-class:: classref-item-separator
@ -128,13 +128,11 @@ Returns ``true`` if the Blackboard contains the ``var_name`` variable, including
.. rst-class:: classref-method
void **link_var** **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var **)**
void **link_var** **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create **)**
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance.
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If ``create`` is ``true``, the variable will be created if it doesn't exist.
A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables.
You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance. A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables.
.. rst-class:: classref-item-separator

View File

@ -6,19 +6,19 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'LimboAI'
copyright = '2021-present Serhii Snitsaruk and the LimboAI contributors'
author = 'Serhii Snitsaruk and the LimboAI contributors'
release = '1.0'
project = "LimboAI"
copyright = "2021-present Serhii Snitsaruk and the LimboAI contributors"
author = "Serhii Snitsaruk and the LimboAI contributors"
release = "1.0"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = ['sphinx_rtd_dark_mode', 'sphinx_copybutton']
extensions = ["sphinx_rtd_dark_mode", "sphinx_copybutton"]
master_doc = 'index'
templates_path = ['_templates']
exclude_patterns = ['_build']
master_doc = "index"
templates_path = ["_templates"]
exclude_patterns = ["_build"]
# -- Markdown configuration (sphinx_markdown_builder).
# markdown_anchor_sections = True
@ -33,12 +33,11 @@ default_dark_mode = False
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
html_theme = "sphinx_rtd_theme"
html_static_path = ["_static"]
html_logo = "logo.png"
html_theme_options = {
'logo_only': True,
'display_version': True,
"logo_only": True,
"display_version": True,
"collapse_navigation": True,
}

View File

@ -16,8 +16,9 @@
<param index="0" name="var_name" type="StringName" />
<param index="1" name="object" type="Object" />
<param index="2" name="property" type="StringName" />
<param index="3" name="create" type="bool" />
<description>
Establish a binding between a variable and the object's property specified by [param property] and [param object]. Changes to the variable update the property, and vice versa.
Establish a binding between a variable and the object's property specified by [param property] and [param object]. Changes to the variable update the property, and vice versa. If [param create] is [code]true[/code], the variable will be created if it doesn't exist.
</description>
</method>
<method name="erase_var">
@ -54,10 +55,10 @@
<param index="0" name="var_name" type="StringName" />
<param index="1" name="target_blackboard" type="Blackboard" />
<param index="2" name="target_var" type="StringName" />
<param index="3" name="create" type="bool" />
<description>
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance.
A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables.
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If [param create] is [code]true[/code], the variable will be created if it doesn't exist.
You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance. A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables.
</description>
</method>
<method name="set_parent">

View File

@ -14,22 +14,22 @@ env = SConscript("godot-cpp/SConstruct")
# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["limboai/"])
env.Append(CPPDEFINES = ['LIMBOAI_GDEXTENSION'])
env.Append(CPPDEFINES=["LIMBOAI_GDEXTENSION"])
sources = Glob("limboai/*.cpp")
sources += (Glob("limboai/blackboard/*.cpp"))
sources += (Glob("limboai/blackboard/bb_param/*.cpp"))
sources += (Glob("limboai/bt/*.cpp"))
sources += (Glob("limboai/bt/tasks/*.cpp"))
sources += (Glob("limboai/bt/tasks/blackboard/*.cpp"))
sources += (Glob("limboai/bt/tasks/composites/*.cpp"))
sources += (Glob("limboai/bt/tasks/decorators/*.cpp"))
sources += (Glob("limboai/bt/tasks/scene/*.cpp"))
sources += (Glob("limboai/bt/tasks/utility/*.cpp"))
sources += (Glob("limboai/gdextension/*.cpp"))
sources += (Glob("limboai/editor/debugger/*.cpp"))
sources += (Glob("limboai/editor/*.cpp"))
sources += (Glob("limboai/hsm/*.cpp"))
sources += (Glob("limboai/util/*.cpp"))
sources += Glob("limboai/blackboard/*.cpp")
sources += Glob("limboai/blackboard/bb_param/*.cpp")
sources += Glob("limboai/bt/*.cpp")
sources += Glob("limboai/bt/tasks/*.cpp")
sources += Glob("limboai/bt/tasks/blackboard/*.cpp")
sources += Glob("limboai/bt/tasks/composites/*.cpp")
sources += Glob("limboai/bt/tasks/decorators/*.cpp")
sources += Glob("limboai/bt/tasks/scene/*.cpp")
sources += Glob("limboai/bt/tasks/utility/*.cpp")
sources += Glob("limboai/gdextension/*.cpp")
sources += Glob("limboai/editor/debugger/*.cpp")
sources += Glob("limboai/editor/*.cpp")
sources += Glob("limboai/hsm/*.cpp")
sources += Glob("limboai/util/*.cpp")
if env["platform"] == "macos":

View File

@ -31,18 +31,23 @@ def get_script_dir():
def main():
silent = False
try:
opts, args = getopt.getopt(sys.argv[1:],
"s", ["silent"])
opts, args = getopt.getopt(sys.argv[1:], "s", ["silent"])
except getopt.GetoptError as e:
print('%s: %s!\n' % (os.path.basename(__file__), e.msg,))
print(
"%s: %s!\n"
% (
os.path.basename(__file__),
e.msg,
)
)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ('-s','--silent'):
elif opt in ("-s", "--silent"):
silent = True
config_dir = get_script_dir()
@ -66,7 +71,7 @@ def main():
icon_files.sort()
for icon_file in icon_files:
content += os.path.splitext(icon_file)[0] + " = \"res://addons/limboai/icons/" + icon_file + "\"\n"
content += os.path.splitext(icon_file)[0] + ' = "res://addons/limboai/icons/' + icon_file + '"\n'
f = open(config_path, "w")
f.write(content)

View File

@ -17,8 +17,14 @@
#include "core/object/ref_counted.h"
#include "core/string/node_path.h"
#include "core/variant/variant.h"
#include "modules/limboai/blackboard/bb_param/bb_bool.h"
#include "modules/limboai/blackboard/bb_param/bb_float.h"
#include "modules/limboai/blackboard/bb_param/bb_int.h"
#include "modules/limboai/blackboard/bb_param/bb_node.h"
#include "modules/limboai/blackboard/bb_param/bb_param.h"
#include "modules/limboai/blackboard/bb_param/bb_string.h"
#include "modules/limboai/blackboard/bb_param/bb_variant.h"
#include "modules/limboai/blackboard/bb_param/bb_vector2.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "modules/limboai/bt/tasks/bt_task.h"
#include "tests/test_macros.h"
@ -122,6 +128,68 @@ TEST_CASE("[Modules][LimboAI] BBNode") {
memdelete(dummy);
}
TEST_CASE("[Modules][LimboAI] BBParam default values") {
Node *dummy = memnew(Node);
Ref<Blackboard> bb = memnew(Blackboard);
SUBCASE("Test default value for BBBool") {
Ref<BBBool> param = memnew(BBBool);
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant(false));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
SUBCASE("Test default value for BBInt") {
Ref<BBInt> param = memnew(BBInt);
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant(0));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
SUBCASE("Test default value for BBFloat") {
Ref<BBFloat> param = memnew(BBFloat);
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant(0.0));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
SUBCASE("Test default value for BBString") {
Ref<BBString> param = memnew(BBString);
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant(""));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
SUBCASE("Test default value for BBVector2") {
Ref<BBVector2> param = memnew(BBVector2);
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant(Vector2()));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
SUBCASE("Test default value for BBVariant") {
Ref<BBVariant> param = memnew(BBVariant);
CHECK_EQ(param->get_value(dummy, bb), Variant());
param->set_value_source(BBParam::SAVED_VALUE);
CHECK_EQ(param->get_value(dummy, bb), Variant());
param->set_type(Variant::BOOL);
CHECK_EQ(param->get_value(dummy, bb), Variant(false));
CHECK_NE(param->get_value(dummy, bb), Variant());
param->set_type(Variant::INT);
CHECK_EQ(param->get_value(dummy, bb), Variant(0));
CHECK_NE(param->get_value(dummy, bb), Variant());
param->set_type(Variant::FLOAT);
CHECK_EQ(param->get_value(dummy, bb), Variant(0.0));
CHECK_NE(param->get_value(dummy, bb), Variant());
param->set_type(Variant::STRING);
CHECK_EQ(param->get_value(dummy, bb), Variant(""));
CHECK_NE(param->get_value(dummy, bb), Variant());
param->set_type(Variant::VECTOR2);
CHECK_EQ(param->get_value(dummy, bb), Variant(Vector2()));
CHECK_NE(param->get_value(dummy, bb), Variant());
param->set_type(Variant::NODE_PATH);
CHECK_EQ(param->get_value(dummy, bb), Variant(NodePath()));
CHECK_NE(param->get_value(dummy, bb), Variant());
}
memdelete(dummy);
}
} //namespace TestBBParam
#endif // TEST_BB_PARAM_H

View File

@ -24,6 +24,12 @@
namespace TestHSM {
inline void wire_callbacks(LimboState *p_state, Ref<CallbackCounter> p_entries_counter, Ref<CallbackCounter> p_updates_counter, Ref<CallbackCounter> p_exits_counter) {
p_state->call_on_enter(callable_mp(p_entries_counter.ptr(), &CallbackCounter::callback));
p_state->call_on_update(callable_mp(p_updates_counter.ptr(), &CallbackCounter::callback_delta));
p_state->call_on_exit(callable_mp(p_exits_counter.ptr(), &CallbackCounter::callback));
}
class TestGuard : public RefCounted {
GDCLASS(TestGuard, RefCounted);
@ -42,22 +48,38 @@ TEST_CASE("[Modules][LimboAI] HSM") {
Ref<CallbackCounter> beta_entries = memnew(CallbackCounter);
Ref<CallbackCounter> beta_exits = memnew(CallbackCounter);
Ref<CallbackCounter> beta_updates = memnew(CallbackCounter);
Ref<CallbackCounter> nested_entries = memnew(CallbackCounter);
Ref<CallbackCounter> nested_exits = memnew(CallbackCounter);
Ref<CallbackCounter> nested_updates = memnew(CallbackCounter);
Ref<CallbackCounter> gamma_entries = memnew(CallbackCounter);
Ref<CallbackCounter> gamma_exits = memnew(CallbackCounter);
Ref<CallbackCounter> gamma_updates = memnew(CallbackCounter);
Ref<CallbackCounter> delta_entries = memnew(CallbackCounter);
Ref<CallbackCounter> delta_exits = memnew(CallbackCounter);
Ref<CallbackCounter> delta_updates = memnew(CallbackCounter);
LimboState *state_alpha = memnew(LimboState);
state_alpha->call_on_enter(callable_mp(alpha_entries.ptr(), &CallbackCounter::callback));
state_alpha->call_on_update(callable_mp(alpha_updates.ptr(), &CallbackCounter::callback_delta));
state_alpha->call_on_exit(callable_mp(alpha_exits.ptr(), &CallbackCounter::callback));
wire_callbacks(state_alpha, alpha_entries, alpha_updates, alpha_exits);
LimboState *state_beta = memnew(LimboState);
state_beta->call_on_enter(callable_mp(beta_entries.ptr(), &CallbackCounter::callback));
state_beta->call_on_update(callable_mp(beta_updates.ptr(), &CallbackCounter::callback_delta));
state_beta->call_on_exit(callable_mp(beta_exits.ptr(), &CallbackCounter::callback));
wire_callbacks(state_beta, beta_entries, beta_updates, beta_exits);
LimboHSM *nested_hsm = memnew(LimboHSM);
wire_callbacks(nested_hsm, nested_entries, nested_updates, nested_exits);
LimboState *state_gamma = memnew(LimboState);
wire_callbacks(state_gamma, gamma_entries, gamma_updates, gamma_exits);
LimboState *state_delta = memnew(LimboState);
wire_callbacks(state_delta, delta_entries, delta_updates, delta_exits);
hsm->add_child(state_alpha);
hsm->add_child(state_beta);
hsm->add_child(nested_hsm);
nested_hsm->add_child(state_gamma);
nested_hsm->add_child(state_delta);
hsm->add_transition(state_alpha, state_beta, "event_one");
hsm->add_transition(state_beta, state_alpha, "event_two");
hsm->add_transition(hsm->anystate(), nested_hsm, "goto_nested");
nested_hsm->add_transition(state_gamma, state_delta, "goto_delta");
nested_hsm->add_transition(state_delta, state_gamma, "goto_gamma");
hsm->set_initial_state(state_alpha);
Ref<Blackboard> parent_scope = memnew(Blackboard);
@ -179,6 +201,57 @@ TEST_CASE("[Modules][LimboAI] HSM") {
CHECK(state_beta->get_blackboard()->get_parent() == parent_scope);
CHECK(state_alpha->get_blackboard()->get_var("parent_var", Variant()) == Variant(100));
}
SUBCASE("Test flow with a nested HSM, and test dispatch() from nested states") {
state_gamma->dispatch("goto_nested");
CHECK(hsm->get_leaf_state() == state_gamma);
CHECK(nested_entries->num_callbacks == 1);
CHECK(nested_updates->num_callbacks == 0);
CHECK(nested_exits->num_callbacks == 0);
CHECK(gamma_entries->num_callbacks == 1);
CHECK(gamma_updates->num_callbacks == 0);
CHECK(gamma_exits->num_callbacks == 0);
hsm->update(0.01666);
CHECK(nested_entries->num_callbacks == 1);
CHECK(nested_updates->num_callbacks == 1);
CHECK(nested_exits->num_callbacks == 0);
CHECK(gamma_entries->num_callbacks == 1);
CHECK(gamma_updates->num_callbacks == 1);
CHECK(gamma_exits->num_callbacks == 0);
state_gamma->dispatch("goto_delta");
CHECK(hsm->get_leaf_state() == state_delta);
CHECK(nested_entries->num_callbacks == 1);
CHECK(nested_updates->num_callbacks == 1);
CHECK(nested_exits->num_callbacks == 0);
CHECK(gamma_entries->num_callbacks == 1);
CHECK(gamma_updates->num_callbacks == 1);
CHECK(gamma_exits->num_callbacks == 1);
CHECK(delta_entries->num_callbacks == 1);
CHECK(delta_updates->num_callbacks == 0);
CHECK(delta_exits->num_callbacks == 0);
state_delta->dispatch(hsm->event_finished());
CHECK(nested_entries->num_callbacks == 1);
CHECK(nested_updates->num_callbacks == 1);
CHECK(nested_exits->num_callbacks == 1);
CHECK(gamma_entries->num_callbacks == 1);
CHECK(gamma_updates->num_callbacks == 1);
CHECK(gamma_exits->num_callbacks == 1);
CHECK(delta_entries->num_callbacks == 1);
CHECK(delta_updates->num_callbacks == 0);
CHECK(delta_exits->num_callbacks == 1);
CHECK(hsm->is_active() == false);
CHECK(hsm->get_leaf_state() == hsm);
}
SUBCASE("Test get_root()") {
CHECK(hsm->get_root() == hsm);
CHECK(state_alpha->get_root() == hsm);
CHECK(state_beta->get_root() == hsm);
CHECK(nested_hsm->get_root() == hsm);
CHECK(state_delta->get_root() == hsm);
CHECK(state_gamma->get_root() == hsm);
}
memdelete(agent);
memdelete(hsm);

View File

@ -515,6 +515,7 @@ PackedInt32Array LimboUtility::get_property_hints_allowed_for_type(Variant::Type
case Variant::Type::PACKED_STRING_ARRAY:
case Variant::Type::PACKED_VECTOR2_ARRAY:
case Variant::Type::PACKED_VECTOR3_ARRAY:
case Variant::Type::PACKED_VECTOR4_ARRAY:
case Variant::Type::PACKED_COLOR_ARRAY:
case Variant::Type::VARIANT_MAX: {
} break;