diff --git a/limbo_hsm.cpp b/limbo_hsm.cpp index d12e19c..0b302b8 100644 --- a/limbo_hsm.cpp +++ b/limbo_hsm.cpp @@ -168,9 +168,17 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) { return event_consumed; } -void LimboHSM::initialize(Object *p_agent, const Ref &p_blackboard) { +void LimboHSM::initialize(Object *p_agent, const Ref &p_parent_scope) { ERR_FAIL_COND(p_agent == nullptr); - ERR_FAIL_COND(!p_blackboard.is_valid()); + if (!p_parent_scope.is_null()) { + blackboard->set_parent_scope(p_parent_scope); + } + _initialize(p_agent, nullptr); +} + +void LimboHSM::_initialize(Object *p_agent, const Ref &p_blackboard) { + ERR_FAIL_COND(p_agent == nullptr); + ERR_FAIL_COND_MSG(agent != nullptr, "LimboAI: HSM already initialized."); ERR_FAIL_COND_MSG(get_child_count() == 0, "Cannot initialize LimboHSM: no candidate for initial substate."); if (initial_state == nullptr) { @@ -178,14 +186,23 @@ void LimboHSM::initialize(Object *p_agent, const Ref &p_blackboard) ERR_FAIL_COND_MSG(initial_state == nullptr, "LimboHSM: Child at index 0 is not a LimboState."); } - LimboState::initialize(p_agent, p_blackboard); + Ref bb = blackboard; + if (!blackboard->get_data().empty()) { + if (!p_blackboard.is_null()) { + bb->set_parent_scope(p_blackboard); + } + } else if (!p_blackboard.is_null()) { + bb = p_blackboard; + } + + LimboState::_initialize(p_agent, bb); for (int i = 0; i < get_child_count(); i++) { LimboState *c = Object::cast_to(get_child(i)); if (unlikely(c == nullptr)) { ERR_PRINT(vformat("LimboHSM: Child at index %d is not a LimboState.", i)); } else { - c->initialize(p_agent, p_blackboard); + c->_initialize(p_agent, bb); } } } @@ -218,6 +235,9 @@ void LimboHSM::_bind_methods() { ClassDB::bind_method(D_METHOD("set_initial_state", "p_state"), &LimboHSM::set_initial_state); ClassDB::bind_method(D_METHOD("get_initial_state"), &LimboHSM::get_initial_state); + ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &LimboHSM::_set_blackboard_data); + ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &LimboHSM::_get_blackboard_data); + ClassDB::bind_method(D_METHOD("get_active_state"), &LimboHSM::get_active_state); ClassDB::bind_method(D_METHOD("get_leaf_state"), &LimboHSM::get_leaf_state); ClassDB::bind_method(D_METHOD("set_active", "p_active"), &LimboHSM::set_active); @@ -225,6 +245,8 @@ void LimboHSM::_bind_methods() { ClassDB::bind_method(D_METHOD("add_transition", "p_from_state", "p_to_state", "p_event"), &LimboHSM::add_transition); ClassDB::bind_method(D_METHOD("anystate"), &LimboHSM::anystate); + ClassDB::bind_method(D_METHOD("initialize", "p_agent", "p_parent_scope"), &LimboHSM::initialize, Variant()); + BIND_ENUM_CONSTANT(IDLE); BIND_ENUM_CONSTANT(PHYSICS); BIND_ENUM_CONSTANT(MANUAL); @@ -232,6 +254,7 @@ void LimboHSM::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle, Physics, Manual"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ANYSTATE", PROPERTY_HINT_NONE, "", 0), "", "anystate"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "initial_state", PROPERTY_HINT_RESOURCE_TYPE, "LimboState", 0), "set_initial_state", "get_initial_state"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data"), "_set_blackboard_data", "_get_blackboard_data"); ADD_SIGNAL(MethodInfo("state_changed", PropertyInfo(Variant::OBJECT, "p_state", PROPERTY_HINT_NONE, "", 0, "LimboState"))); } @@ -240,4 +263,5 @@ LimboHSM::LimboHSM() { update_mode = UpdateMode::IDLE; active_state = nullptr; initial_state = nullptr; + blackboard = Ref(memnew(Blackboard)); } diff --git a/limbo_hsm.h b/limbo_hsm.h index a6bc25a..388417f 100644 --- a/limbo_hsm.h +++ b/limbo_hsm.h @@ -34,6 +34,10 @@ protected: void _notification(int p_what); + void _set_blackboard_data(Dictionary p_value) { blackboard->set_data(p_value.duplicate()); } + Dictionary _get_blackboard_data() const { return blackboard->get_data(); } + + virtual void _initialize(Object *p_agent, const Ref &p_blackboard); virtual void _enter(); virtual void _exit(); virtual void _update(float p_delta); @@ -51,7 +55,7 @@ public: void set_initial_state(Node *p_state); LimboState *get_initial_state() const { return initial_state; } - virtual void initialize(Object *p_agent, const Ref &p_blackboard); + virtual void initialize(Object *p_agent, const Ref &p_parent_scope = nullptr); virtual bool dispatch(const String &p_event, const Variant &p_cargo); void update(float p_delta) { _update(p_delta); } diff --git a/limbo_state.cpp b/limbo_state.cpp index f19f349..8db9694 100644 --- a/limbo_state.cpp +++ b/limbo_state.cpp @@ -61,7 +61,7 @@ void LimboState::_update(float p_delta) { emit_signal(LimboStringNames::get_singleton()->updated, p_delta); }; -void LimboState::initialize(Object *p_agent, const Ref &p_blackboard) { +void LimboState::_initialize(Object *p_agent, const Ref &p_blackboard) { ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_COND(!p_blackboard.is_valid()); agent = p_agent; @@ -144,7 +144,7 @@ void LimboState::_bind_methods() { ClassDB::bind_method(D_METHOD("_enter"), &LimboState::_enter); ClassDB::bind_method(D_METHOD("_exit"), &LimboState::_exit); ClassDB::bind_method(D_METHOD("_update", "p_delta"), &LimboState::_update); - ClassDB::bind_method(D_METHOD("initialize", "p_agent", "p_blackboard"), &LimboState::initialize); + ClassDB::bind_method(D_METHOD("_initialize", "p_agent", "p_blackboard"), &LimboState::_initialize); ClassDB::bind_method(D_METHOD("dispatch", "p_event", "p_cargo"), &LimboState::dispatch, Variant()); ClassDB::bind_method(D_METHOD("named", "p_name"), &LimboState::named); ClassDB::bind_method(D_METHOD("add_event_handler", "p_event", "p_method"), &LimboState::add_event_handler); diff --git a/limbo_state.h b/limbo_state.h index 70fd6ed..04bd3af 100644 --- a/limbo_state.h +++ b/limbo_state.h @@ -36,6 +36,7 @@ protected: void _notification(int p_what); + virtual void _initialize(Object *p_agent, const Ref &p_blackboard); virtual void _setup(); virtual void _enter(); virtual void _exit(); @@ -51,7 +52,6 @@ public: Object *get_agent() const { return agent; } void set_agent(Object *p_agent) { agent = p_agent; } - virtual void initialize(Object *p_agent, const Ref &p_blackboard); virtual bool dispatch(const String &p_event, const Variant &p_cargo); LimboState *named(String p_name);