Browse Source

Use Callable for Navigation Agent callbacks

Josh Jones 2 years ago
parent
commit
22f9ef19e1

+ 3 - 5
doc/classes/NavigationServer2D.xml

@@ -41,12 +41,10 @@
 		<method name="agent_set_callback">
 			<return type="void" />
 			<param index="0" name="agent" type="RID" />
-			<param index="1" name="object_id" type="int" />
-			<param index="2" name="method" type="StringName" />
-			<param index="3" name="userdata" type="Variant" default="null" />
+			<param index="1" name="callback" type="Callable" />
 			<description>
-				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].
 			</description>
 		</method>
 		<method name="agent_set_map">

+ 3 - 5
doc/classes/NavigationServer3D.xml

@@ -41,12 +41,10 @@
 		<method name="agent_set_callback">
 			<return type="void" />
 			<param index="0" name="agent" type="RID" />
-			<param index="1" name="object_id" type="int" />
-			<param index="2" name="method" type="StringName" />
-			<param index="3" name="userdata" type="Variant" default="null" />
+			<param index="1" name="callback" type="Callable" />
 			<description>
-				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].
 			</description>
 		</method>
 		<method name="agent_set_map">

+ 5 - 36
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

+ 1 - 6
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

+ 11 - 21
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()) {
+	if (!callback.is_valid()) {
 		return;
 	}
-	Object *obj = ObjectDB::get_instance(callback.id);
-	if (!obj) {
-		callback.id = ObjectID();
-		return;
-	}
-
-	Callable::CallError responseCallError;
 
-	callback.new_velocity = Vector3(agent.newVelocity_.x(), agent.newVelocity_.y(), agent.newVelocity_.z());
+	Vector3 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);
 }

+ 2 - 11
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();

+ 5 - 3
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<Node2D>(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<Node2D>(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 {

+ 5 - 3
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<Node3D>(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<Node3D>(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 {

+ 6 - 33
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<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> 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);
 

+ 1 - 1
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<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result) const;
 

+ 1 - 1
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);
 

+ 1 - 1
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;