diff --git a/blackboard/bb_param/bb_param.cpp b/blackboard/bb_param/bb_param.cpp index 2d550c2..88ad5e7 100644 --- a/blackboard/bb_param/bb_param.cpp +++ b/blackboard/bb_param/bb_param.cpp @@ -79,6 +79,9 @@ Variant BBParam::get_value(Object *p_agent, const Ref &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(); } diff --git a/tests/test_bb_param.h b/tests/test_bb_param.h index 1618430..8243e6a 100644 --- a/tests/test_bb_param.h +++ b/tests/test_bb_param.h @@ -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 bb = memnew(Blackboard); + + SUBCASE("Test default value for BBBool") { + Ref 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 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 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 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 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 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 diff --git a/tests/test_hsm.h b/tests/test_hsm.h index 184f086..533f279 100644 --- a/tests/test_hsm.h +++ b/tests/test_hsm.h @@ -24,6 +24,12 @@ namespace TestHSM { +inline void wire_callbacks(LimboState *p_state, Ref p_entries_counter, Ref p_updates_counter, Ref 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 beta_entries = memnew(CallbackCounter); Ref beta_exits = memnew(CallbackCounter); Ref beta_updates = memnew(CallbackCounter); + Ref nested_entries = memnew(CallbackCounter); + Ref nested_exits = memnew(CallbackCounter); + Ref nested_updates = memnew(CallbackCounter); + Ref gamma_entries = memnew(CallbackCounter); + Ref gamma_exits = memnew(CallbackCounter); + Ref gamma_updates = memnew(CallbackCounter); + Ref delta_entries = memnew(CallbackCounter); + Ref delta_exits = memnew(CallbackCounter); + Ref 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 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);