Use the new virtual workaround and rework LimboState and HSM
This commit is contained in:
parent
390d4a9385
commit
a3f8c09766
|
@ -49,9 +49,9 @@ void LimboHSM::set_active(bool p_active) {
|
||||||
set_process_input(p_active);
|
set_process_input(p_active);
|
||||||
|
|
||||||
if (active) {
|
if (active) {
|
||||||
_do_enter();
|
_enter();
|
||||||
} else {
|
} else {
|
||||||
_do_exit();
|
_exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,41 +60,41 @@ void LimboHSM::_change_state(LimboState *p_state) {
|
||||||
ERR_FAIL_COND(p_state->get_parent() != this);
|
ERR_FAIL_COND(p_state->get_parent() != this);
|
||||||
|
|
||||||
if (active_state) {
|
if (active_state) {
|
||||||
active_state->_do_exit();
|
active_state->_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
active_state = p_state;
|
active_state = p_state;
|
||||||
active_state->_do_enter();
|
active_state->_enter();
|
||||||
|
|
||||||
emit_signal(LimboStringNames::get_singleton()->state_changed, active_state);
|
emit_signal(LimboStringNames::get_singleton()->state_changed, active_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboHSM::_do_enter() {
|
void LimboHSM::_enter() {
|
||||||
ERR_FAIL_COND_MSG(get_child_count() == 0, "LimboHSM has no candidate for initial substate.");
|
ERR_FAIL_COND_MSG(get_child_count() == 0, "LimboHSM has no candidate for initial substate.");
|
||||||
ERR_FAIL_COND(active_state != nullptr);
|
ERR_FAIL_COND(active_state != nullptr);
|
||||||
ERR_FAIL_COND_MSG(initial_state == nullptr, "LimboHSM: Initial state is not set.");
|
ERR_FAIL_COND_MSG(initial_state == nullptr, "LimboHSM: Initial state is not set.");
|
||||||
|
|
||||||
LimboState::_do_enter();
|
LimboState::_enter();
|
||||||
_change_state(initial_state);
|
_change_state(initial_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboHSM::_do_exit() {
|
void LimboHSM::_exit() {
|
||||||
ERR_FAIL_COND(active_state == nullptr);
|
ERR_FAIL_COND(active_state == nullptr);
|
||||||
active_state->_do_exit();
|
active_state->_exit();
|
||||||
active_state = nullptr;
|
active_state = nullptr;
|
||||||
LimboState::_do_exit();
|
LimboState::_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboHSM::_do_update(double p_delta) {
|
void LimboHSM::_update(double p_delta) {
|
||||||
if (active) {
|
if (active) {
|
||||||
ERR_FAIL_COND(active_state == nullptr);
|
ERR_FAIL_COND(active_state == nullptr);
|
||||||
LimboState::_do_update(p_delta);
|
LimboState::_update(p_delta);
|
||||||
active_state->_do_update(p_delta);
|
active_state->_update(p_delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboHSM::update(double p_delta) {
|
void LimboHSM::update(double p_delta) {
|
||||||
_do_update(p_delta);
|
_update(p_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboHSM::add_transition(Node *p_from_state, Node *p_to_state, const String &p_event) {
|
void LimboHSM::add_transition(Node *p_from_state, Node *p_to_state, const String &p_event) {
|
||||||
|
@ -181,7 +181,7 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event_consumed && p_event == LW_NAME(EVENT_FINISHED) && !(get_parent() && get_parent()->is_class("LimboState"))) {
|
if (!event_consumed && p_event == LW_NAME(EVENT_FINISHED) && !(get_parent() && get_parent()->is_class("LimboState"))) {
|
||||||
_do_exit();
|
_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return event_consumed;
|
return event_consumed;
|
||||||
|
@ -226,10 +226,10 @@ void LimboHSM::_notification(int p_what) {
|
||||||
case NOTIFICATION_POST_ENTER_TREE: {
|
case NOTIFICATION_POST_ENTER_TREE: {
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_PROCESS: {
|
case NOTIFICATION_PROCESS: {
|
||||||
_do_update(get_process_delta_time());
|
_update(get_process_delta_time());
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_PHYSICS_PROCESS: {
|
case NOTIFICATION_PHYSICS_PROCESS: {
|
||||||
_do_update(get_physics_process_delta_time());
|
_update(get_physics_process_delta_time());
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,9 @@ protected:
|
||||||
|
|
||||||
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 void _do_enter() override;
|
virtual void _enter() override;
|
||||||
virtual void _do_exit() override;
|
virtual void _exit() override;
|
||||||
virtual void _do_update(double p_delta) override;
|
virtual void _update(double p_delta) override;
|
||||||
|
|
||||||
void _change_state(LimboState *p_state);
|
void _change_state(LimboState *p_state);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public:
|
||||||
void set_update_mode(UpdateMode p_mode) { update_mode = p_mode; }
|
void set_update_mode(UpdateMode p_mode) { update_mode = p_mode; }
|
||||||
UpdateMode get_update_mode() const { return update_mode; }
|
UpdateMode get_update_mode() const { return update_mode; }
|
||||||
|
|
||||||
LimboState *get_active_state() const { return active_state; };
|
LimboState *get_active_state() const { return active_state; }
|
||||||
LimboState *get_leaf_state() const;
|
LimboState *get_leaf_state() const;
|
||||||
void set_active(bool p_active);
|
void set_active(bool p_active);
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public:
|
||||||
void update(double p_delta);
|
void update(double p_delta);
|
||||||
void add_transition(Node *p_from_state, Node *p_to_state, const String &p_event);
|
void add_transition(Node *p_from_state, Node *p_to_state, const String &p_event);
|
||||||
// void add_transition_from_any_state(Node *p_to_state, const String &p_event);
|
// void add_transition_from_any_state(Node *p_to_state, const String &p_event);
|
||||||
LimboState *anystate() const { return nullptr; };
|
LimboState *anystate() const { return nullptr; }
|
||||||
|
|
||||||
LimboHSM();
|
LimboHSM();
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,27 +37,32 @@ LimboState *LimboState::get_root() const {
|
||||||
LimboState *LimboState::named(String p_name) {
|
LimboState *LimboState::named(String p_name) {
|
||||||
set_name(p_name);
|
set_name(p_name);
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
void LimboState::_do_enter() {
|
void LimboState::_enter() {
|
||||||
active = true;
|
active = true;
|
||||||
VCALL_OR_NATIVE(_enter);
|
VCALL(_enter);
|
||||||
emit_signal(LimboStringNames::get_singleton()->entered);
|
emit_signal(LimboStringNames::get_singleton()->entered);
|
||||||
};
|
}
|
||||||
|
|
||||||
void LimboState::_do_exit() {
|
void LimboState::_exit() {
|
||||||
if (!active) {
|
if (!active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VCALL_OR_NATIVE(_exit);
|
VCALL(_exit);
|
||||||
emit_signal(LimboStringNames::get_singleton()->exited);
|
emit_signal(LimboStringNames::get_singleton()->exited);
|
||||||
active = false;
|
active = false;
|
||||||
};
|
}
|
||||||
|
|
||||||
void LimboState::_do_update(double p_delta) {
|
void LimboState::_update(double p_delta) {
|
||||||
VCALL_OR_NATIVE_ARGS(_update, p_delta);
|
VCALL_ARGS(_update, p_delta);
|
||||||
emit_signal(LimboStringNames::get_singleton()->updated, p_delta);
|
emit_signal(LimboStringNames::get_singleton()->updated, p_delta);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void LimboState::_setup() {
|
||||||
|
VCALL(_setup);
|
||||||
|
emit_signal(LimboStringNames::get_singleton()->setup);
|
||||||
|
}
|
||||||
|
|
||||||
void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
|
void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
|
||||||
ERR_FAIL_COND(p_agent == nullptr);
|
ERR_FAIL_COND(p_agent == nullptr);
|
||||||
|
@ -71,15 +76,9 @@ void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VCALL_OR_NATIVE(_setup);
|
_setup();
|
||||||
emit_signal(LimboStringNames::get_singleton()->setup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboState::_setup() {}
|
|
||||||
void LimboState::_enter() {}
|
|
||||||
void LimboState::_exit() {}
|
|
||||||
void LimboState::_update(double p_delta) {}
|
|
||||||
|
|
||||||
bool LimboState::dispatch(const String &p_event, const Variant &p_cargo) {
|
bool LimboState::dispatch(const String &p_event, const Variant &p_cargo) {
|
||||||
ERR_FAIL_COND_V(p_event.is_empty(), false);
|
ERR_FAIL_COND_V(p_event.is_empty(), false);
|
||||||
if (handlers.size() > 0 && handlers.has(p_event)) {
|
if (handlers.size() > 0 && handlers.has(p_event)) {
|
||||||
|
@ -189,10 +188,7 @@ void LimboState::_bind_methods() {
|
||||||
GDVIRTUAL_BIND(_exit);
|
GDVIRTUAL_BIND(_exit);
|
||||||
GDVIRTUAL_BIND(_update, "p_delta");
|
GDVIRTUAL_BIND(_update, "p_delta");
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
ClassDB::bind_method(D_METHOD("_setup"), &LimboState::_setup);
|
// TODO: Registering virtual functions is not available in godot-cpp...
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "EVENT_FINISHED", PROPERTY_HINT_NONE, "", 0), "", "event_finished");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "EVENT_FINISHED", PROPERTY_HINT_NONE, "", 0), "", "event_finished");
|
||||||
|
@ -204,7 +200,7 @@ void LimboState::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("entered"));
|
ADD_SIGNAL(MethodInfo("entered"));
|
||||||
ADD_SIGNAL(MethodInfo("exited"));
|
ADD_SIGNAL(MethodInfo("exited"));
|
||||||
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::FLOAT, "p_delta")));
|
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::FLOAT, "p_delta")));
|
||||||
};
|
}
|
||||||
|
|
||||||
LimboState::LimboState() {
|
LimboState::LimboState() {
|
||||||
agent = nullptr;
|
agent = nullptr;
|
||||||
|
|
|
@ -56,7 +56,6 @@ protected:
|
||||||
|
|
||||||
virtual void _initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard);
|
virtual void _initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard);
|
||||||
|
|
||||||
// Implemented in GDScript:
|
|
||||||
virtual void _setup();
|
virtual void _setup();
|
||||||
virtual void _enter();
|
virtual void _enter();
|
||||||
virtual void _exit();
|
virtual void _exit();
|
||||||
|
@ -69,15 +68,9 @@ protected:
|
||||||
GDVIRTUAL1(_update, double);
|
GDVIRTUAL1(_update, double);
|
||||||
#endif // LIMBOAI_MODULE
|
#endif // LIMBOAI_MODULE
|
||||||
|
|
||||||
virtual void _do_enter();
|
|
||||||
virtual void _do_exit();
|
|
||||||
virtual void _do_update(double p_delta);
|
|
||||||
|
|
||||||
void add_event_handler(const String &p_event, const Callable &p_handler);
|
void add_event_handler(const String &p_event, const Callable &p_handler);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static String EVENT_FINISHED() { return LW_NAME(EVENT_FINISHED); }
|
|
||||||
|
|
||||||
Ref<Blackboard> get_blackboard() const { return blackboard; }
|
Ref<Blackboard> get_blackboard() const { return blackboard; }
|
||||||
|
|
||||||
Node *get_agent() const { return agent; }
|
Node *get_agent() const { return agent; }
|
||||||
|
|
|
@ -136,7 +136,7 @@ TEST_CASE("[Modules][LimboAI] HSM") {
|
||||||
CHECK(beta_updates->num_callbacks == 2);
|
CHECK(beta_updates->num_callbacks == 2);
|
||||||
CHECK(beta_exits->num_callbacks == 1);
|
CHECK(beta_exits->num_callbacks == 1);
|
||||||
|
|
||||||
hsm->dispatch(LimboState::EVENT_FINISHED());
|
hsm->dispatch(hsm->event_finished());
|
||||||
CHECK(alpha_entries->num_callbacks == 2);
|
CHECK(alpha_entries->num_callbacks == 2);
|
||||||
CHECK(alpha_updates->num_callbacks == 3);
|
CHECK(alpha_updates->num_callbacks == 3);
|
||||||
CHECK(alpha_exits->num_callbacks == 2); // * exited
|
CHECK(alpha_exits->num_callbacks == 2); // * exited
|
||||||
|
|
|
@ -58,8 +58,9 @@
|
||||||
// * Virtual calls
|
// * Virtual calls
|
||||||
|
|
||||||
#define VCALL(m_name, ...) (GDVIRTUAL_CALL(m_name, __VA_ARGS__))
|
#define VCALL(m_name, ...) (GDVIRTUAL_CALL(m_name, __VA_ARGS__))
|
||||||
#define VCALL_ARGS(method, ...) (call(LW_NAME(method), __VA_ARGS__))
|
#define VCALL_ARGS(m_name, ...) (GDVIRTUAL_CALL(m_name, __VA_ARGS__))
|
||||||
#define VCALL_V(m_name, r_ret) (GDVIRTUAL_CALL(m_name, r_ret))
|
#define VCALL_V(m_name, r_ret) (GDVIRTUAL_CALL(m_name, r_ret))
|
||||||
|
#define VCALL_ARGS_V(m_name, r_ret, ...) (GDVIRTUAL_CALL(m_name, __VA_ARGS__, r_ret))
|
||||||
|
|
||||||
#define VCALL_OR_NATIVE(m_name) \
|
#define VCALL_OR_NATIVE(m_name) \
|
||||||
if (!GDVIRTUAL_CALL(m_name)) { \
|
if (!GDVIRTUAL_CALL(m_name)) { \
|
||||||
|
@ -139,10 +140,29 @@ using namespace godot;
|
||||||
// * Virtual calls:
|
// * Virtual calls:
|
||||||
// * This is a workaround for missing ClassDB::add_virtual_method().
|
// * This is a workaround for missing ClassDB::add_virtual_method().
|
||||||
// ! When using these macros, DON'T BIND the native virtual methods!
|
// ! When using these macros, DON'T BIND the native virtual methods!
|
||||||
|
// -----------------------------
|
||||||
|
// VCALL*: only calls a script version if present.
|
||||||
|
// VCALL_OR_NATIVE*: calls a script version if present; otherwise, calls the native version.
|
||||||
|
|
||||||
#define VCALL(m_name) (call(LW_NAME(m_name)))
|
#define VCALL(m_name) \
|
||||||
#define VCALL_ARGS(m_name, ...) (call(LW_NAME(m_name), __VA_ARGS__))
|
if (has_method(LW_NAME(m_name))) { \
|
||||||
#define VCALL_V(m_name, r_ret) (r_ret = call(LW_NAME(m_name)))
|
call(LW_NAME(m_name)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCALL_ARGS(m_name, ...) \
|
||||||
|
if (has_method(LW_NAME(m_name))) { \
|
||||||
|
call(LW_NAME(m_name), __VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCALL_V(m_name, r_ret) \
|
||||||
|
if (has_method(LW_NAME(m_name))) { \
|
||||||
|
r_ret = call(LW_NAME(m_name)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCALL_ARGS_V(m_name, r_ret, ...) \
|
||||||
|
if (has_method(LW_NAME(m_name))) { \
|
||||||
|
r_ret = call(LW_NAME(m_name, __VA_ARGS__)); \
|
||||||
|
}
|
||||||
|
|
||||||
#define VCALL_OR_NATIVE(m_name) \
|
#define VCALL_OR_NATIVE(m_name) \
|
||||||
if (has_method(LW_NAME(m_name))) { \
|
if (has_method(LW_NAME(m_name))) { \
|
||||||
|
|
Loading…
Reference in New Issue