Fix infinite call recursion crash due to virtual function workaround

This commit is contained in:
Serhii Snitsaruk 2024-01-12 23:20:39 +01:00
parent 1d3cea6b2e
commit 947e253bf9
4 changed files with 45 additions and 37 deletions

View File

@ -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) {
_enter(); _do_enter();
} else { } else {
_exit(); _do_exit();
} }
} }
@ -60,45 +60,43 @@ 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->_exit(); active_state->_do_exit();
} }
active_state = p_state; active_state = p_state;
active_state->_enter(); active_state->_do_enter();
emit_signal(LimboStringNames::get_singleton()->state_changed, active_state); emit_signal(LimboStringNames::get_singleton()->state_changed, active_state);
} }
void LimboHSM::_enter() { void LimboHSM::_do_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.");
LimboState::_enter(); LimboState::_do_enter();
if (initial_state == nullptr) {
initial_state = Object::cast_to<LimboState>(get_child(0));
}
ERR_FAIL_COND_MSG(initial_state == nullptr, "LimboHSM: Failed to acquire initial state.");
_change_state(initial_state); _change_state(initial_state);
} }
void LimboHSM::_exit() { void LimboHSM::_do_exit() {
ERR_FAIL_COND(active_state == nullptr); ERR_FAIL_COND(active_state == nullptr);
active_state->_exit(); active_state->_do_exit();
active_state = nullptr; active_state = nullptr;
LimboState::_exit(); LimboState::_do_exit();
} }
void LimboHSM::_update(double p_delta) { void LimboHSM::_do_update(double p_delta) {
if (active) { if (active) {
ERR_FAIL_COND(active_state == nullptr); ERR_FAIL_COND(active_state == nullptr);
LimboState::_update(p_delta); LimboState::_do_update(p_delta);
active_state->_update(p_delta); active_state->_do_update(p_delta);
} }
} }
void LimboHSM::update(double p_delta) {
_do_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) {
// ERR_FAIL_COND(p_from_state == nullptr); // ERR_FAIL_COND(p_from_state == nullptr);
ERR_FAIL_COND(p_from_state != nullptr && p_from_state->get_parent() != this); ERR_FAIL_COND(p_from_state != nullptr && p_from_state->get_parent() != this);
@ -186,7 +184,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"))) {
_exit(); _do_exit();
} }
return event_consumed; return event_consumed;
@ -198,6 +196,10 @@ void LimboHSM::initialize(Node *p_agent, const Ref<Blackboard> &p_parent_scope)
blackboard->set_parent_scope(p_parent_scope); blackboard->set_parent_scope(p_parent_scope);
} }
_initialize(p_agent, nullptr); _initialize(p_agent, nullptr);
if (initial_state == nullptr) {
initial_state = Object::cast_to<LimboState>(get_child(0));
}
} }
void LimboHSM::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) { void LimboHSM::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
@ -227,10 +229,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: {
_update(get_process_delta_time()); _do_update(get_process_delta_time());
} break; } break;
case NOTIFICATION_PHYSICS_PROCESS: { case NOTIFICATION_PHYSICS_PROCESS: {
_update(get_physics_process_delta_time()); _do_update(get_physics_process_delta_time());
} break; } break;
} }
} }

View File

@ -43,9 +43,10 @@ protected:
void _notification(int p_what); void _notification(int p_what);
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 _enter() override;
virtual void _exit() override; virtual void _do_enter() override;
virtual void _update(double p_delta) override; virtual void _do_exit() override;
virtual void _do_update(double p_delta) override;
void _change_state(LimboState *p_state); void _change_state(LimboState *p_state);
@ -63,7 +64,7 @@ public:
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_parent_scope = nullptr); virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_parent_scope = nullptr);
virtual bool dispatch(const String &p_event, const Variant &p_cargo = Variant()) override; virtual bool dispatch(const String &p_event, const Variant &p_cargo = Variant()) override;
void update(double p_delta) { _update(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; };

View File

@ -39,18 +39,13 @@ LimboState *LimboState::named(String p_name) {
return this; return this;
}; };
void LimboState::_setup() { void LimboState::_do_enter() {
VCALL(_setup);
emit_signal(LimboStringNames::get_singleton()->setup);
};
void LimboState::_enter() {
active = true; active = true;
VCALL(_enter); VCALL(_enter);
emit_signal(LimboStringNames::get_singleton()->entered); emit_signal(LimboStringNames::get_singleton()->entered);
}; };
void LimboState::_exit() { void LimboState::_do_exit() {
if (!active) { if (!active) {
return; return;
} }
@ -59,14 +54,13 @@ void LimboState::_exit() {
active = false; active = false;
}; };
void LimboState::_update(double p_delta) { void LimboState::_do_update(double p_delta) {
VCALL_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::_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);
agent = p_agent; agent = p_agent;
if (!p_blackboard.is_null()) { if (!p_blackboard.is_null()) {
@ -77,8 +71,14 @@ void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
} }
} }
_setup(); VCALL(_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);

View File

@ -56,6 +56,7 @@ 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();
@ -68,6 +69,10 @@ 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: