From 22f9ef19e1accd5d5e36ce30589ba3edd5c3d0d0 Mon Sep 17 00:00:00 2001 From: Josh Jones Date: Fri, 27 Jan 2023 20:15:10 -0800 Subject: [PATCH] Use Callable for Navigation Agent callbacks --- doc/classes/NavigationServer2D.xml | 8 ++-- doc/classes/NavigationServer3D.xml | 8 ++-- .../navigation/godot_navigation_server.cpp | 41 +++---------------- modules/navigation/godot_navigation_server.h | 7 +--- modules/navigation/rvo_agent.cpp | 32 +++++---------- modules/navigation/rvo_agent.h | 13 +----- scene/2d/navigation_agent_2d.cpp | 8 ++-- scene/3d/navigation_agent_3d.cpp | 8 ++-- servers/navigation_server_2d.cpp | 39 +++--------------- servers/navigation_server_2d.h | 2 +- servers/navigation_server_3d.cpp | 2 +- servers/navigation_server_3d.h | 2 +- 12 files changed, 44 insertions(+), 126 deletions(-) diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 95e3fded36b2..16f6de523800 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -41,12 +41,10 @@ - - - + - Sets the callback [param object_id] and [param method] that gets called after each avoidance processing step for the [param agent]. The calculated [code]safe_velocity[/code] will be dispatched with a signal to the object just before the physics calculations. - [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]0[/code] ObjectID as the [param object_id]. + Sets the callback that gets called after each avoidance processing step for the [param agent]. The calculated [code]safe_velocity[/code] will be passed as the first parameter just before the physics calculations. + [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with an empty [Callable]. diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index fd20f780b304..340821d41e8d 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -41,12 +41,10 @@ - - - + - Sets the callback [param object_id] and [param method] that gets called after each avoidance processing step for the [param agent]. The calculated [code]safe_velocity[/code] will be dispatched with a signal to the object just before the physics calculations. - [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]0[/code] ObjectID as the [param object_id]. + Sets the callback that gets called after each avoidance processing step for the [param agent]. The calculated [code]safe_velocity[/code] will be passed as the first parameter just before the physics calculations. + [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with an empty [Callable]. diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 5baf6db2e884..d546c5d3bac2 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -81,36 +81,6 @@ using namespace NavigationUtilities; } \ void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) -#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - T_1 d_1; \ - T_2 d_2; \ - T_3 d_3; \ - MERGE(F_NAME, _command) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1, \ - T_2 p_d_2, \ - T_3 p_d_3) : \ - d_0(p_d_0), \ - d_1(p_d_1), \ - d_2(p_d_2), \ - d_3(p_d_3) {} \ - virtual void exec(GodotNavigationServer *server) override { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ - } \ - }; \ - void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0, \ - D_1, \ - D_2, \ - D_3)); \ - add_command(cmd); \ - } \ - void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) - GodotNavigationServer::GodotNavigationServer() {} GodotNavigationServer::~GodotNavigationServer() { @@ -711,17 +681,17 @@ bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const { return agent->is_map_changed(); } -COMMAND_4(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata) { +COMMAND_2(agent_set_callback, RID, p_agent, Callable, p_callback) { RvoAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); - agent->set_callback(p_object_id, p_method, p_udata); + agent->set_callback(p_callback); if (agent->get_map()) { - if (p_object_id == ObjectID()) { - agent->get_map()->remove_agent_as_controlled(agent); - } else { + if (p_callback.is_valid()) { agent->get_map()->set_agent_as_controlled(agent); + } else { + agent->get_map()->remove_agent_as_controlled(agent); } } } @@ -946,4 +916,3 @@ int GodotNavigationServer::get_process_info(ProcessInfo p_info) const { #undef COMMAND_1 #undef COMMAND_2 -#undef COMMAND_4 diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index efefa60de8d7..eea5713c4025 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -54,10 +54,6 @@ virtual void F_NAME(T_0 D_0, T_1 D_1) override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) -#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \ - virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) override; \ - void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) - class GodotNavigationServer; struct SetCommand { @@ -182,7 +178,7 @@ public: COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position); COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore); virtual bool agent_is_map_changed(RID p_agent) const override; - COMMAND_4_DEF(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata, Variant()); + COMMAND_2(agent_set_callback, RID, p_agent, Callable, p_callback); COMMAND_1(free, RID, p_object); @@ -198,6 +194,5 @@ public: #undef COMMAND_1 #undef COMMAND_2 -#undef COMMAND_4_DEF #endif // GODOT_NAVIGATION_SERVER_H diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp index 979ef0d91718..40f1e925bef5 100644 --- a/modules/navigation/rvo_agent.cpp +++ b/modules/navigation/rvo_agent.cpp @@ -32,10 +32,6 @@ #include "nav_map.h" -RvoAgent::RvoAgent() { - callback.id = ObjectID(); -} - void RvoAgent::set_map(NavMap *p_map) { map = p_map; } @@ -50,31 +46,25 @@ bool RvoAgent::is_map_changed() { } } -void RvoAgent::set_callback(ObjectID p_id, const StringName p_method, const Variant p_udata) { - callback.id = p_id; - callback.method = p_method; - callback.udata = p_udata; +void RvoAgent::set_callback(Callable p_callback) { + callback = p_callback; } bool RvoAgent::has_callback() const { - return callback.id.is_valid(); + return callback.is_valid(); } void RvoAgent::dispatch_callback() { - if (callback.id.is_null()) { - return; - } - Object *obj = ObjectDB::get_instance(callback.id); - if (!obj) { - callback.id = ObjectID(); + if (!callback.is_valid()) { return; } - Callable::CallError responseCallError; + Vector3 new_velocity = Vector3(agent.newVelocity_.x(), agent.newVelocity_.y(), agent.newVelocity_.z()); - callback.new_velocity = Vector3(agent.newVelocity_.x(), agent.newVelocity_.y(), agent.newVelocity_.z()); - - const Variant *vp[2] = { &callback.new_velocity, &callback.udata }; - int argc = (callback.udata.get_type() == Variant::NIL) ? 1 : 2; - obj->callp(callback.method, vp, argc, responseCallError); + // Invoke the callback with the new velocity. + Variant args[] = { new_velocity }; + const Variant *args_p[] = { &args[0] }; + Variant return_value; + Callable::CallError call_error; + callback.callp(args_p, 1, return_value, call_error); } diff --git a/modules/navigation/rvo_agent.h b/modules/navigation/rvo_agent.h index 7b19907b2bac..5f377b60791b 100644 --- a/modules/navigation/rvo_agent.h +++ b/modules/navigation/rvo_agent.h @@ -39,21 +39,12 @@ class NavMap; class RvoAgent : public NavRid { - struct AvoidanceComputedCallback { - ObjectID id; - StringName method; - Variant udata; - Variant new_velocity; - }; - NavMap *map = nullptr; RVO::Agent agent; - AvoidanceComputedCallback callback; + Callable callback = Callable(); uint32_t map_update_id = 0; public: - RvoAgent(); - void set_map(NavMap *p_map); NavMap *get_map() { return map; @@ -65,7 +56,7 @@ public: bool is_map_changed(); - void set_callback(ObjectID p_id, const StringName p_method, const Variant p_udata = Variant()); + void set_callback(Callable p_callback); bool has_callback() const; void dispatch_callback(); diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 907fb7e6a9b3..e73b6e7e23a2 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -205,9 +205,9 @@ NavigationAgent2D::~NavigationAgent2D() { void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) { avoidance_enabled = p_enabled; if (avoidance_enabled) { - NavigationServer2D::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done"); + NavigationServer2D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done)); } else { - NavigationServer2D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done"); + NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable()); } } @@ -217,7 +217,8 @@ bool NavigationAgent2D::get_avoidance_enabled() const { void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map - NavigationServer2D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done"); + NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable()); + if (Object::cast_to(p_agent_parent) != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later agent_parent = Object::cast_to(p_agent_parent); @@ -226,6 +227,7 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { } else { NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); } + // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); } else { diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index fe7ddcb06efd..4aa6e61ec547 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -212,9 +212,9 @@ NavigationAgent3D::~NavigationAgent3D() { void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) { avoidance_enabled = p_enabled; if (avoidance_enabled) { - NavigationServer3D::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done"); + NavigationServer3D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done)); } else { - NavigationServer3D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done"); + NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable()); } } @@ -224,7 +224,8 @@ bool NavigationAgent3D::get_avoidance_enabled() const { void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) { // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map - NavigationServer3D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done"); + NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable()); + if (Object::cast_to(p_agent_parent) != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later agent_parent = Object::cast_to(p_agent_parent); @@ -233,6 +234,7 @@ void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) { } else { NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map()); } + // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); } else { diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 88178d5c7d75..2e4087c1de51 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -81,35 +81,12 @@ NavigationServer2D *NavigationServer2D::singleton = nullptr; return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \ } -#define FORWARD_4(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \ - NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) { \ - return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \ - } - -#define FORWARD_4_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \ - NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \ - const { \ - return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3))); \ - } - -#define FORWARD_4_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \ - NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \ - const { \ - return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \ - } - #define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \ const { \ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \ } -#define FORWARD_5_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \ - NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \ - const { \ - return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4)); \ - } - static RID rid_to_rid(const RID d) { return d; } @@ -155,18 +132,14 @@ static Transform3D trf2_to_trf3(const Transform2D &d) { return Transform3D(b, o); } -static StringName sn_to_sn(const StringName &d) { - return d; -} - -static Variant var_to_var(const Variant &d) { - return d; -} - static ObjectID id_to_id(const ObjectID &id) { return id; } +static Callable callable_to_callable(const Callable &c) { + return c; +} + static Ref poly_to_mesh(Ref d) { if (d.is_valid()) { return d->get_navigation_mesh(); @@ -308,7 +281,7 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer2D::agent_set_target_velocity); ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer2D::agent_set_position); ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer2D::agent_is_map_changed); - ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "object_id", "method", "userdata"), &NavigationServer2D::agent_set_callback, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "callback"), &NavigationServer2D::agent_set_callback); ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer2D::free); @@ -420,7 +393,7 @@ void FORWARD_2(agent_set_target_velocity, RID, p_agent, Vector2, p_velocity, rid void FORWARD_2(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3); void FORWARD_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore, rid_to_rid, bool_to_bool); bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid); -void FORWARD_4(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata, rid_to_rid, id_to_id, sn_to_sn, var_to_var); +void FORWARD_2(agent_set_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable); void FORWARD_1(free, RID, p_object, rid_to_rid); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index b50808cddf3c..cd18476182f9 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -223,7 +223,7 @@ public: virtual bool agent_is_map_changed(RID p_agent) const; /// Callback called at the end of the RVO process - virtual void agent_set_callback(RID p_agent, ObjectID p_object_id, StringName p_method, Variant p_udata = Variant()); + virtual void agent_set_callback(RID p_agent, Callable p_callback); virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 07256badefdb..5b95317a38ff 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -113,7 +113,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer3D::agent_set_target_velocity); ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer3D::agent_set_position); ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer3D::agent_is_map_changed); - ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "object_id", "method", "userdata"), &NavigationServer3D::agent_set_callback, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "callback"), &NavigationServer3D::agent_set_callback); ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer3D::free); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 4d81726fc352..9c468d1b10e1 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -238,7 +238,7 @@ public: virtual bool agent_is_map_changed(RID p_agent) const = 0; /// Callback called at the end of the RVO process - virtual void agent_set_callback(RID p_agent, ObjectID p_object_id, StringName p_method, Variant p_udata = Variant()) = 0; + virtual void agent_set_callback(RID p_agent, Callable p_callback) = 0; /// Destroy the `RID` virtual void free(RID p_object) = 0;