From 3be6c6282c39639914a4da8f0a8c608b47cb61e2 Mon Sep 17 00:00:00 2001
From: Relintai <relintai@protonmail.com>
Date: Sat, 14 Jan 2023 13:36:30 +0100
Subject: [PATCH] Also cleaned up agents and added them to the build.

---
 modules/steering_ai/SCsub                     |   6 +
 .../agents/gsai_kinematic_body_2d_agent.cpp   | 258 ++++++++---------
 .../agents/gsai_kinematic_body_2d_agent.h     |  54 ++--
 .../agents/gsai_kinematic_body_3d_agent.cpp   | 260 +++++++-----------
 .../agents/gsai_kinematic_body_3d_agent.h     |  54 ++--
 .../agents/gsai_rigid_body_2d_agent.cpp       | 165 +++++------
 .../agents/gsai_rigid_body_2d_agent.h         |  25 +-
 .../agents/gsai_rigid_body_3d_agent.cpp       | 162 +++++------
 .../agents/gsai_rigid_body_3d_agent.h         |  25 +-
 .../agents/gsai_specialized_agent.cpp         |  48 +---
 .../agents/gsai_specialized_agent.h           |  24 +-
 modules/steering_ai/config.py                 |   6 +
 modules/steering_ai/register_types.cpp        |  12 +
 13 files changed, 489 insertions(+), 610 deletions(-)

diff --git a/modules/steering_ai/SCsub b/modules/steering_ai/SCsub
index aeed6ae26..8dae0788f 100644
--- a/modules/steering_ai/SCsub
+++ b/modules/steering_ai/SCsub
@@ -34,6 +34,12 @@ sources = [
     "behaviors/gsai_pursue.cpp",
     "behaviors/gsai_seek.cpp",
     "behaviors/gsai_separation.cpp",
+
+    "agents/gsai_kinematic_body_2d_agent.cpp",
+    "agents/gsai_kinematic_body_3d_agent.cpp",
+    "agents/gsai_rigid_body_2d_agent.cpp",
+    "agents/gsai_rigid_body_3d_agent.cpp",
+    "agents/gsai_specialized_agent.cpp",
 ]
 
 
diff --git a/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.cpp b/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.cpp
index da563bd20..1a1dee1e3 100644
--- a/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.cpp
+++ b/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.cpp
@@ -1,12 +1,39 @@
 
 #include "gsai_kinematic_body_2d_agent.h"
 
-KinematicBody2D GSAIKinematicBody2DAgent::get_ *body() {
-	return *body;
+#include "core/math/math_funcs.h"
+#include "scene/2d/physics_body_2d.h"
+#include "scene/main/scene_tree.h"
+
+#include "../gsai_target_acceleration.h"
+#include "../gsai_utils.h"
+
+KinematicBody2D *GSAIKinematicBody2DAgent::get_body() {
+	return Object::cast_to<KinematicBody2D>(ObjectDB::get_instance(_body_ref));
 }
 
-void GSAIKinematicBody2DAgent::set_ *body(const KinematicBody2D &val) {
-	*body = val;
+void GSAIKinematicBody2DAgent::set_body(KinematicBody2D *value) {
+	if (!value) {
+		_body_ref = 0;
+		_physics_process_disconnect();
+		return;
+	}
+
+	_body_ref = value->get_instance_id();
+	_last_position = value->get_global_position();
+	last_orientation = value->get_rotation();
+	position = GSAIUtils::to_vector3(_last_position);
+	orientation = last_orientation;
+
+	if (!value->is_inside_tree()) {
+		value->connect("ready", this, "_physics_process_connect", varray(), CONNECT_ONESHOT);
+	} else {
+		_physics_process_connect();
+	}
+}
+
+void GSAIKinematicBody2DAgent::set_body_bind(Node *p_body) {
+	set_body(Object::cast_to<KinematicBody2D>(p_body));
 }
 
 int GSAIKinematicBody2DAgent::get_movement_type() const {
@@ -17,184 +44,134 @@ void GSAIKinematicBody2DAgent::set_movement_type(const int val) {
 	movement_type = val;
 }
 
-Vector2 GSAIKinematicBody2DAgent::get__last_position() {
-	return _last_position;
-}
-
-void GSAIKinematicBody2DAgent::set__last_position(const Vector2 &val) {
-	_last_position = val;
-}
-
-Ref<WeakRef> GSAIKinematicBody2DAgent::get__body_ref() {
-	return _body_ref;
-}
-
-void GSAIKinematicBody2DAgent::set__body_ref(const Ref<WeakRef> &val) {
-	_body_ref = val;
-}
-
-// A specialized steering agent that updates itself every frame so the user does;
-// not have to using a KinematicBody2D;
-// @category - Specialized agents;
-// SLIDE uses `move_and_slide`;
-// COLLIDE uses `move_and_collide`;
-// POSITION changes the `global_position` directly;
-}
-;
-// The KinematicBody2D to keep track of;
-// setget _set_body;
-KinematicBody2D *body;
-// The type of movement the body executes;
-int movement_type = MovementType.SLIDE;
-Vector2 _last_position = ;
-Ref<WeakRef> _body_ref;
-
-void GSAIKinematicBody2DAgent::_body_ready() {
-	// warning-ignore:return_value_discarded;
-	body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame");
-}
-
-// Moves the agent's `body` by target `acceleration`.;
-// @tags - virtual;
-
-void GSAIKinematicBody2DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float delta) {
+void GSAIKinematicBody2DAgent::_apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta) {
 	applied_steering = true;
 
-	if (movement_type == MovementType.COLLIDE) {
-		_apply_collide_steering(acceleration.linear, delta);
+	KinematicBody2D *body = get_body();
+
+	if (!body || !body->is_inside_tree()) {
+		return;
 	}
 
-	else if (movement_type == MovementType.SLIDE) {
-		_apply_sliding_steering(acceleration.linear, delta);
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st && st->is_paused()) {
+		return;
 	}
 
-	else {
-		_apply_position_steering(acceleration.linear, delta);
+	if (movement_type == COLLIDE) {
+		_apply_collide_steering(body, acceleration->get_linear(), delta);
+	} else if (movement_type == SLIDE) {
+		_apply_sliding_steering(body, acceleration->get_linear(), delta);
+	} else {
+		_apply_position_steering(body, acceleration->get_linear(), delta);
 	}
 
-	_apply_orientation_steering(acceleration.angular, delta);
+	_apply_orientation_steering(body, acceleration->get_angular(), delta);
 }
 
-void GSAIKinematicBody2DAgent::_apply_sliding_steering(const Vector3 &accel, const float delta) {
-	KinematicBody2D *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	if (!_body.is_inside_tree() || _body.get_tree().paused) {
-		return;
-	}
-
-	Vector2 velocity = GSAIUtils.to_vector2(linear_velocity + accel * delta).limit_length(linear_speed_max);
+void GSAIKinematicBody2DAgent::_apply_sliding_steering(KinematicBody2D *body, const Vector3 &accel, const float delta) {
+	Vector2 velocity = GSAIUtils::to_vector2(linear_velocity + accel * delta).limit_length(linear_speed_max);
 
 	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag_percentage);
+		velocity = velocity.linear_interpolate(Vector2(), linear_drag_percentage);
 	}
 
-	velocity = _body.move_and_slide(velocity);
+	velocity = body->move_and_slide(velocity);
 
 	if (calculate_velocities) {
-		linear_velocity = GSAIUtils.to_vector3(velocity);
+		linear_velocity = GSAIUtils::to_vector3(velocity);
 	}
 }
 
-void GSAIKinematicBody2DAgent::_apply_collide_steering(const Vector3 &accel, const float delta) {
-	KinematicBody2D *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
+void GSAIKinematicBody2DAgent::_apply_collide_steering(KinematicBody2D *body, const Vector3 &accel, const float delta) {
+	Vector3 velocity = GSAIUtils::clampedv3(linear_velocity + accel * delta, linear_speed_max);
 
 	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+		velocity = velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 	}
 
-	// warning-ignore:return_value_discarded;
-	_body.move_and_collide(GSAIUtils.to_vector2(velocity) * delta);
+	KinematicBody2D::Collision col;
+	body->move_and_collide(GSAIUtils::to_vector2(velocity) * delta, true, col);
 
 	if (calculate_velocities) {
 		linear_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody2DAgent::_apply_position_steering(const Vector3 &accel, const float delta) {
-	KinematicBody2D *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
+void GSAIKinematicBody2DAgent::_apply_position_steering(KinematicBody2D *body, const Vector3 &accel, const float delta) {
+	Vector3 velocity = GSAIUtils::clampedv3(linear_velocity + accel * delta, linear_speed_max);
 
 	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+		velocity = velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 	}
 
-	_body.global_position += GSAIUtils.to_vector2(velocity) * delta;
+	Vector2 global_position = body->get_global_position();
+
+	global_position += GSAIUtils::to_vector2(velocity) * delta;
+
+	body->set_global_position(global_position);
 
 	if (calculate_velocities) {
 		linear_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody2DAgent::_apply_orientation_steering(const float angular_acceleration, const float delta) {
-	KinematicBody2D *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Variant = clamp(angular_velocity + angular_acceleration * delta, -angular_speed_max, angular_speed_max);
+void GSAIKinematicBody2DAgent::_apply_orientation_steering(KinematicBody2D *body, const float angular_acceleration, const float delta) {
+	float velocity = CLAMP(angular_velocity + angular_acceleration * delta, -angular_speed_max, angular_speed_max);
 
 	if (apply_angular_drag) {
-		velocity = lerp(velocity, 0, angular_drag_percentage);
+		velocity = Math::lerp(velocity, 0, angular_drag_percentage);
 	}
 
-	_body.rotation += velocity * delta;
+	body->set_rotation(body->get_rotation() + velocity * delta);
 
 	if (calculate_velocities) {
 		angular_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody2DAgent::_set_body(const KinematicBody2D &value) {
-	bool had_body = false;
+void GSAIKinematicBody2DAgent::_physics_process_connect() {
+	SceneTree *st = SceneTree::get_singleton();
 
-	if (body) {
-		had_body = true;
-	}
-
-	body = value;
-	_body_ref = weakref(body);
-	_last_position = value.global_position;
-	last_orientation = value.rotation;
-	position = GSAIUtils.to_vector3(_last_position);
-	orientation = last_orientation;
-
-	if (!had_body) {
-		if (!body.is_inside_tree()) {
-			body.connect("ready", self, "_body_ready");
+	if (st) {
+		if (!st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->connect("physics_frame", this, "_on_SceneTree_physics_frame");
 		}
+	}
+}
 
-		else {
-			_body_ready();
+void GSAIKinematicBody2DAgent::_physics_process_disconnect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->disconnect("physics_frame", this, "_on_SceneTree_physics_frame");
 		}
 	}
 }
 
 void GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame() {
-	KinematicBody2D *_body = _body_ref.get_ref();
+	KinematicBody2D *body = get_body();
 
-	if (!_body) {
+	if (!body) {
+		call_deferred("_physics_process_disconnect");
 		return;
 	}
 
-	Vector2 current_position = _body.global_position;
-	float current_orientation = _body.rotation;
-	position = GSAIUtils.to_vector3(current_position);
+	if (!body->is_inside_tree()) {
+		return;
+	}
+
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st && st->is_paused()) {
+		return;
+	}
+
+	Vector2 current_position = body->get_global_position();
+	float current_orientation = body->get_rotation();
+	position = GSAIUtils::to_vector3(current_position);
 	orientation = current_orientation;
 
 	if (calculate_velocities) {
@@ -203,16 +180,16 @@ void GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame() {
 		}
 
 		else {
-			linear_velocity = GSAIUtils.clampedv3(GSAIUtils.to_vector3(current_position - _last_position), linear_speed_max);
+			linear_velocity = GSAIUtils::clampedv3(GSAIUtils::to_vector3(current_position - _last_position), linear_speed_max);
 
 			if (apply_linear_drag) {
-				linear_velocity = linear_velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+				linear_velocity = linear_velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 			}
 
-			angular_velocity = clamp(last_orientation - current_orientation, -angular_speed_max, angular_speed_max);
+			angular_velocity = CLAMP(last_orientation - current_orientation, -angular_speed_max, angular_speed_max);
 
 			if (apply_angular_drag) {
-				angular_velocity = lerp(angular_velocity, 0, angular_drag_percentage);
+				angular_velocity = Math::lerp(angular_velocity, 0, angular_drag_percentage);
 			}
 
 			_last_position = current_position;
@@ -220,41 +197,26 @@ void GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame() {
 		}
 	}
 }
-}
 
 GSAIKinematicBody2DAgent::GSAIKinematicBody2DAgent() {
-	*body;
-	movement_type = MovementType.SLIDE;
-	_last_position = ;
-	_body_ref;
+	movement_type = SLIDE;
+	_body_ref = 0;
 }
 
 GSAIKinematicBody2DAgent::~GSAIKinematicBody2DAgent() {
 }
 
-static void GSAIKinematicBody2DAgent::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_*body"), &GSAIKinematicBody2DAgent::get_ * body);
-	ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIKinematicBody2DAgent::set_ * body);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody2D"), "set_*body", "get_*body");
+void GSAIKinematicBody2DAgent::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_body"), &GSAIKinematicBody2DAgent::get_body);
+	ClassDB::bind_method(D_METHOD("set_body", "value"), &GSAIKinematicBody2DAgent::set_body_bind);
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody2D"), "set_body", "get_body");
 
 	ClassDB::bind_method(D_METHOD("get_movement_type"), &GSAIKinematicBody2DAgent::get_movement_type);
 	ClassDB::bind_method(D_METHOD("set_movement_type", "value"), &GSAIKinematicBody2DAgent::set_movement_type);
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "movement_type"), "set_movement_type", "get_movement_type");
 
-	ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIKinematicBody2DAgent::get__last_position);
-	ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIKinematicBody2DAgent::set__last_position);
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "_last_position"), "set__last_position", "get__last_position");
+	ClassDB::bind_method(D_METHOD("_physics_process_connect"), &GSAIKinematicBody2DAgent::_physics_process_connect);
+	ClassDB::bind_method(D_METHOD("_physics_process_disconnect"), &GSAIKinematicBody2DAgent::_physics_process_disconnect);
 
-	ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIKinematicBody2DAgent::get__body_ref);
-	ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIKinematicBody2DAgent::set__body_ref);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
-
-	ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIKinematicBody2DAgent::_body_ready);
-	ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "delta"), &GSAIKinematicBody2DAgent::_apply_steering);
-	ClassDB::bind_method(D_METHOD("_apply_sliding_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_sliding_steering);
-	ClassDB::bind_method(D_METHOD("_apply_collide_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_collide_steering);
-	ClassDB::bind_method(D_METHOD("_apply_position_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_position_steering);
-	ClassDB::bind_method(D_METHOD("_apply_orientation_steering", "angular_acceleration", "delta"), &GSAIKinematicBody2DAgent::_apply_orientation_steering);
-	ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIKinematicBody2DAgent::_set_body);
 	ClassDB::bind_method(D_METHOD("_on_SceneTree_physics_frame"), &GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame);
 }
diff --git a/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.h b/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.h
index 0fd76a562..3dcb297c7 100644
--- a/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.h
+++ b/modules/steering_ai/agents/gsai_kinematic_body_2d_agent.h
@@ -1,36 +1,38 @@
 #ifndef GSAI_KINEMATIC_BODY_2D_AGENT_H
 #define GSAI_KINEMATIC_BODY_2D_AGENT_H
 
+#include "gsai_specialized_agent.h"
+
+class KinematicBody2D;
+class GSAITargetAcceleration;
+
 class GSAIKinematicBody2DAgent : public GSAISpecializedAgent {
 	GDCLASS(GSAIKinematicBody2DAgent, GSAISpecializedAgent);
 
 public:
-	KinematicBody2D get_ *body();
-	void set_ *body(const KinematicBody2D &val);
+	KinematicBody2D *get_body();
+	void set_body(KinematicBody2D *p_body);
+	void set_body_bind(Node *p_body);
 
 	int get_movement_type() const;
 	void set_movement_type(const int val);
 
-	Vector2 get__last_position();
-	void set__last_position(const Vector2 &val);
-
-	Ref<WeakRef> get__body_ref();
-	void set__body_ref(const Ref<WeakRef> &val);
-
 	enum MovementType {
-
 		SLIDE,
 		COLLIDE,
 		POSITION
 	};
 
-	void _body_ready();
-	void _apply_steering(const GSAITargetAcceleration &acceleration, const float delta);
-	void _apply_sliding_steering(const Vector3 &accel, const float delta);
-	void _apply_collide_steering(const Vector3 &accel, const float delta);
-	void _apply_position_steering(const Vector3 &accel, const float delta);
-	void _apply_orientation_steering(const float angular_acceleration, const float delta);
-	void _set_body(const KinematicBody2D &value);
+	void _physics_process_connect();
+	void _physics_process_disconnect();
+	
+	void _apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta);
+
+	void _apply_sliding_steering(KinematicBody2D *body, const Vector3 &accel, const float delta);
+	void _apply_collide_steering(KinematicBody2D *body, const Vector3 &accel, const float delta);
+	void _apply_position_steering(KinematicBody2D *body, const Vector3 &accel, const float delta);
+	void _apply_orientation_steering(KinematicBody2D *body, const float angular_acceleration, const float delta);
+
 	void _on_SceneTree_physics_frame();
 
 	GSAIKinematicBody2DAgent();
@@ -45,17 +47,15 @@ protected:
 	// SLIDE uses `move_and_slide`
 	// COLLIDE uses `move_and_collide`
 	// POSITION changes the `global_position` directly
+
+	// The KinematicBody2D to keep track of
+	// setget _set_body
+	// The type of movement the body executes
+	int movement_type;
+	Vector2 _last_position;
+	ObjectID _body_ref;
+	// Moves the agent's `body` by target `acceleration`.
+	// @tags - virtual
 };
-// The KinematicBody2D to keep track of
-// setget _set_body
-KinematicBody2D *body;
-// The type of movement the body executes
-int movement_type = MovementType.SLIDE;
-Vector2 _last_position = ;
-Ref<WeakRef> _body_ref;
-// Moves the agent's `body` by target `acceleration`.
-// @tags - virtual
-}
-;
 
 #endif
diff --git a/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.cpp b/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.cpp
index ccf0ae734..625d34518 100644
--- a/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.cpp
+++ b/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.cpp
@@ -1,12 +1,37 @@
 
 #include "gsai_kinematic_body_3d_agent.h"
 
-KinematicBody GSAIKinematicBody3DAgent::get_ *body() {
-	return *body;
+#include "scene/3d/physics_body.h"
+
+#include "../gsai_target_acceleration.h"
+#include "../gsai_utils.h"
+
+KinematicBody *GSAIKinematicBody3DAgent::get_body() {
+	return Object::cast_to<KinematicBody>(ObjectDB::get_instance(_body_ref));
 }
 
-void GSAIKinematicBody3DAgent::set_ *body(const KinematicBody &val) {
-	*body = val;
+void GSAIKinematicBody3DAgent::set_body(KinematicBody *value) {
+	if (!value) {
+		_body_ref = 0;
+		_physics_process_disconnect();
+		return;
+	}
+
+	_body_ref = value->get_instance_id();
+	_last_position = value->get_transform().origin;
+	last_orientation = value->get_rotation().y;
+	position = _last_position;
+	orientation = last_orientation;
+
+	if (!value->is_inside_tree()) {
+		value->connect("ready", this, "_physics_process_connect", varray(), CONNECT_ONESHOT);
+	} else {
+		_physics_process_connect();
+	}
+}
+
+void GSAIKinematicBody3DAgent::set_body_bind(Node *p_body) {
+	set_body(Object::cast_to<KinematicBody>(p_body));
 }
 
 int GSAIKinematicBody3DAgent::get_movement_type() const {
@@ -17,202 +42,144 @@ void GSAIKinematicBody3DAgent::set_movement_type(const int val) {
 	movement_type = val;
 }
 
-Vector3 GSAIKinematicBody3DAgent::get__last_position() {
-	return _last_position;
+void GSAIKinematicBody3DAgent::_physics_process_connect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (!st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->connect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-void GSAIKinematicBody3DAgent::set__last_position(const Vector3 &val) {
-	_last_position = val;
+void GSAIKinematicBody3DAgent::_physics_process_disconnect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->disconnect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-Ref<WeakRef> GSAIKinematicBody3DAgent::get__body_ref() {
-	return _body_ref;
-}
-
-void GSAIKinematicBody3DAgent::set__body_ref(const Ref<WeakRef> &val) {
-	_body_ref = val;
-}
-
-// A specialized steering agent that updates itself every frame so the user does;
-// not have to using a KinematicBody;
-// @category - Specialized agents;
-// SLIDE uses `move_and_slide`;
-// COLLIDE uses `move_and_collide`;
-// POSITION changes the global_position directly;
-}
-;
-// The KinematicBody to keep track of;
-// setget _set_body;
-KinematicBody *body;
-// The type of movement the body executes;
-int movement_type = 0;
-Vector3 _last_position = ;
-Ref<WeakRef> _body_ref;
-
-void GSAIKinematicBody3DAgent::_body_ready() {
-	// warning-ignore:return_value_discarded;
-	body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame");
-}
-
-// Moves the agent's `body` by target `acceleration`.;
-// @tags - virtual;
-
-void GSAIKinematicBody3DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float delta) {
+void GSAIKinematicBody3DAgent::_apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta) {
 	applied_steering = true;
 
-	if (movement_type == MovementType.COLLIDE) {
-		_apply_collide_steering(acceleration.linear, delta);
-	}
+	KinematicBody *body = get_body();
 
-	else if (movement_type == MovementType.SLIDE) {
-		_apply_sliding_steering(acceleration.linear, delta);
-	}
-
-	else {
-		_apply_position_steering(acceleration.linear, delta);
-	}
-
-	_apply_orientation_steering(acceleration.angular, delta);
-}
-
-void GSAIKinematicBody3DAgent::_apply_sliding_steering(const Vector3 &accel, const float delta) {
-	KinematicBody *_body = _body_ref.get_ref();
-
-	if (!_body) {
+	if (!body) {
 		return;
 	}
 
-	Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
-
-	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+	if (movement_type == COLLIDE) {
+		_apply_collide_steering(body, acceleration->get_linear(), delta);
+	} else if (movement_type == SLIDE) {
+		_apply_sliding_steering(body, acceleration->get_linear(), delta);
+	} else {
+		_apply_position_steering(body, acceleration->get_linear(), delta);
 	}
 
-	velocity = _body.move_and_slide(velocity);
+	_apply_orientation_steering(body, acceleration->get_angular(), delta);
+}
+
+void GSAIKinematicBody3DAgent::_apply_sliding_steering(KinematicBody *body, const Vector3 &accel, const float delta) {
+	Vector3 velocity = GSAIUtils::clampedv3(linear_velocity + accel * delta, linear_speed_max);
+
+	if (apply_linear_drag) {
+		velocity = velocity.linear_interpolate(Vector3(), linear_drag_percentage);
+	}
+
+	velocity = body->move_and_slide(velocity);
 
 	if (calculate_velocities) {
 		linear_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody3DAgent::_apply_collide_steering(const Vector3 &accel, const float delta) {
-	KinematicBody *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
+void GSAIKinematicBody3DAgent::_apply_collide_steering(KinematicBody *body, const Vector3 &accel, const float delta) {
+	Vector3 velocity = GSAIUtils::clampedv3(linear_velocity + accel * delta, linear_speed_max);
 
 	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+		velocity = velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 	}
 
-	// warning-ignore:return_value_discarded;
-	_body.move_and_collide(velocity * delta);
+	KinematicBody::Collision coll;
+	body->move_and_collide(velocity * delta, true, coll);
 
 	if (calculate_velocities) {
 		linear_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody3DAgent::_apply_position_steering(const Vector3 &accel, const float delta) {
-	KinematicBody *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
+void GSAIKinematicBody3DAgent::_apply_position_steering(KinematicBody *body, const Vector3 &accel, const float delta) {
+	Vector3 velocity = GSAIUtils::clampedv3(linear_velocity + accel * delta, linear_speed_max);
 
 	if (apply_linear_drag) {
-		velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+		velocity = velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 	}
 
-	_body.global_transform.origin += velocity * delta;
+	body->get_global_transform().origin += velocity * delta;
 
 	if (calculate_velocities) {
 		linear_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody3DAgent::_apply_orientation_steering(const float angular_acceleration, const float delta) {
-	KinematicBody *_body = _body_ref.get_ref();
-
-	if (!_body) {
-		return;
-	}
-
-	Variant = clamp(angular_velocity + angular_acceleration * delta, -angular_speed_max, angular_speed_max);
+void GSAIKinematicBody3DAgent::_apply_orientation_steering(KinematicBody *body, const float angular_acceleration, const float delta) {
+	float velocity = CLAMP(angular_velocity + angular_acceleration * delta, -angular_speed_max, angular_speed_max);
 
 	if (apply_angular_drag) {
-		velocity = lerp(velocity, 0, angular_drag_percentage);
+		velocity = Math::lerp(velocity, 0, angular_drag_percentage);
 	}
 
-	_body.rotation.y += velocity * delta;
+	Vector3 rotation = body->get_rotation();
+
+	rotation.y += velocity * delta;
+
+	body->set_rotation(rotation);
 
 	if (calculate_velocities) {
 		angular_velocity = velocity;
 	}
 }
 
-void GSAIKinematicBody3DAgent::_set_body(const KinematicBody &value) {
-	bool had_body = false;
-
-	if (body) {
-		had_body = true;
-	}
-
-	body = value;
-	_body_ref = weakref(value);
-	_last_position = value.transform.origin;
-	last_orientation = value.rotation.y;
-	position = _last_position;
-	orientation = last_orientation;
-
-	if (!had_body) {
-		if (!body.is_inside_tree()) {
-			body.connect("ready", self, "_body_ready");
-		}
-
-		else {
-			_body_ready();
-		}
-	}
-}
-
 void GSAIKinematicBody3DAgent::_on_SceneTree_physics_frame() {
-	KinematicBody *_body = _body_ref.get_ref();
+	KinematicBody *body = get_body();
 
-	if (!_body) {
+	if (!body) {
+		call_deferred("_physics_process_disconnect");
 		return;
 	}
 
-	if (!_body.is_inside_tree() || _body.get_tree().paused) {
+	if (!body->is_inside_tree()) {
 		return;
 	}
 
-	Vector3 current_position = _body.transform.origin;
-	float current_orientation = _body.rotation.y;
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st && st->is_paused()) {
+		return;
+	}
+
+	Vector3 current_position = body->get_transform().origin;
+	float current_orientation = body->get_rotation().y;
 	position = current_position;
 	orientation = current_orientation;
 
 	if (calculate_velocities) {
 		if (applied_steering) {
 			applied_steering = false;
-		}
-
-		else {
-			linear_velocity = GSAIUtils.clampedv3(current_position - _last_position, linear_speed_max);
+		} else {
+			linear_velocity = GSAIUtils::clampedv3(current_position - _last_position, linear_speed_max);
 
 			if (apply_linear_drag) {
-				linear_velocity = linear_velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
+				linear_velocity = linear_velocity.linear_interpolate(Vector3(), linear_drag_percentage);
 			}
 
-			angular_velocity = clamp(last_orientation - current_orientation, -angular_speed_max, angular_speed_max);
+			angular_velocity = CLAMP(last_orientation - current_orientation, -angular_speed_max, angular_speed_max);
 
 			if (apply_angular_drag) {
-				angular_velocity = lerp(angular_velocity, 0, angular_drag_percentage);
+				angular_velocity = Math::lerp(angular_velocity, 0, angular_drag_percentage);
 			}
 
 			_last_position = current_position;
@@ -220,41 +187,26 @@ void GSAIKinematicBody3DAgent::_on_SceneTree_physics_frame() {
 		}
 	}
 }
-}
 
 GSAIKinematicBody3DAgent::GSAIKinematicBody3DAgent() {
-	*body;
 	movement_type = 0;
-	_last_position = ;
-	_body_ref;
+	_body_ref = 0;
 }
 
 GSAIKinematicBody3DAgent::~GSAIKinematicBody3DAgent() {
 }
 
-static void GSAIKinematicBody3DAgent::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_*body"), &GSAIKinematicBody3DAgent::get_ * body);
-	ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIKinematicBody3DAgent::set_ * body);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody"), "set_*body", "get_*body");
+void GSAIKinematicBody3DAgent::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_body"), &GSAIKinematicBody3DAgent::get_body);
+	ClassDB::bind_method(D_METHOD("set_body", "value"), &GSAIKinematicBody3DAgent::set_body_bind);
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody"), "set_body", "get_body");
 
 	ClassDB::bind_method(D_METHOD("get_movement_type"), &GSAIKinematicBody3DAgent::get_movement_type);
 	ClassDB::bind_method(D_METHOD("set_movement_type", "value"), &GSAIKinematicBody3DAgent::set_movement_type);
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "movement_type"), "set_movement_type", "get_movement_type");
 
-	ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIKinematicBody3DAgent::get__last_position);
-	ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIKinematicBody3DAgent::set__last_position);
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_last_position"), "set__last_position", "get__last_position");
+	ClassDB::bind_method(D_METHOD("_physics_process_connect"), &GSAIKinematicBody3DAgent::_physics_process_connect);
+	ClassDB::bind_method(D_METHOD("_physics_process_disconnect"), &GSAIKinematicBody3DAgent::_physics_process_disconnect);
 
-	ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIKinematicBody3DAgent::get__body_ref);
-	ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIKinematicBody3DAgent::set__body_ref);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
-
-	ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIKinematicBody3DAgent::_body_ready);
-	ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "delta"), &GSAIKinematicBody3DAgent::_apply_steering);
-	ClassDB::bind_method(D_METHOD("_apply_sliding_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_sliding_steering);
-	ClassDB::bind_method(D_METHOD("_apply_collide_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_collide_steering);
-	ClassDB::bind_method(D_METHOD("_apply_position_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_position_steering);
-	ClassDB::bind_method(D_METHOD("_apply_orientation_steering", "angular_acceleration", "delta"), &GSAIKinematicBody3DAgent::_apply_orientation_steering);
-	ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIKinematicBody3DAgent::_set_body);
 	ClassDB::bind_method(D_METHOD("_on_SceneTree_physics_frame"), &GSAIKinematicBody3DAgent::_on_SceneTree_physics_frame);
 }
diff --git a/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.h b/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.h
index 899b86a22..20f41eef8 100644
--- a/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.h
+++ b/modules/steering_ai/agents/gsai_kinematic_body_3d_agent.h
@@ -1,36 +1,38 @@
 #ifndef GSAI_KINEMATIC_BODY_3D_AGENT_H
 #define GSAI_KINEMATIC_BODY_3D_AGENT_H
 
+#include "gsai_specialized_agent.h"
+
+class KinematicBody;
+class GSAITargetAcceleration;
+
 class GSAIKinematicBody3DAgent : public GSAISpecializedAgent {
 	GDCLASS(GSAIKinematicBody3DAgent, GSAISpecializedAgent);
 
 public:
-	KinematicBody get_ *body();
-	void set_ *body(const KinematicBody &val);
+	KinematicBody *get_body();
+	void set_body(KinematicBody *p_body);
+	void set_body_bind(Node *p_body);
 
 	int get_movement_type() const;
 	void set_movement_type(const int val);
 
-	Vector3 get__last_position();
-	void set__last_position(const Vector3 &val);
-
-	Ref<WeakRef> get__body_ref();
-	void set__body_ref(const Ref<WeakRef> &val);
-
 	enum MovementType {
-
 		SLIDE,
 		COLLIDE,
 		POSITION
 	};
 
-	void _body_ready();
-	void _apply_steering(const GSAITargetAcceleration &acceleration, const float delta);
-	void _apply_sliding_steering(const Vector3 &accel, const float delta);
-	void _apply_collide_steering(const Vector3 &accel, const float delta);
-	void _apply_position_steering(const Vector3 &accel, const float delta);
-	void _apply_orientation_steering(const float angular_acceleration, const float delta);
-	void _set_body(const KinematicBody &value);
+	void _physics_process_connect();
+	void _physics_process_disconnect();
+
+	void _apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta);
+
+	void _apply_sliding_steering(KinematicBody *body, const Vector3 &accel, const float delta);
+	void _apply_collide_steering(KinematicBody *body, const Vector3 &accel, const float delta);
+	void _apply_position_steering(KinematicBody *body, const Vector3 &accel, const float delta);
+	void _apply_orientation_steering(KinematicBody *body, const float angular_acceleration, const float delta);
+
 	void _on_SceneTree_physics_frame();
 
 	GSAIKinematicBody3DAgent();
@@ -45,17 +47,15 @@ protected:
 	// SLIDE uses `move_and_slide`
 	// COLLIDE uses `move_and_collide`
 	// POSITION changes the global_position directly
+
+	// The KinematicBody to keep track of
+	// setget _set_body
+	// The type of movement the body executes
+	int movement_type;
+	Vector3 _last_position;
+	ObjectID _body_ref;
+	// Moves the agent's `body` by target `acceleration`.
+	// @tags - virtual
 };
-// The KinematicBody to keep track of
-// setget _set_body
-KinematicBody *body;
-// The type of movement the body executes
-int movement_type = 0;
-Vector3 _last_position = ;
-Ref<WeakRef> _body_ref;
-// Moves the agent's `body` by target `acceleration`.
-// @tags - virtual
-}
-;
 
 #endif
diff --git a/modules/steering_ai/agents/gsai_rigid_body_2d_agent.cpp b/modules/steering_ai/agents/gsai_rigid_body_2d_agent.cpp
index d5179d1f3..288207b3f 100644
--- a/modules/steering_ai/agents/gsai_rigid_body_2d_agent.cpp
+++ b/modules/steering_ai/agents/gsai_rigid_body_2d_agent.cpp
@@ -1,142 +1,123 @@
 
 #include "gsai_rigid_body_2d_agent.h"
 
-RigidBody2D GSAIRigidBody2DAgent::get_ *body() {
-	return *body;
+#include "scene/2d/physics_body_2d.h"
+
+#include "../gsai_target_acceleration.h"
+#include "../gsai_utils.h"
+
+RigidBody2D *GSAIRigidBody2DAgent::get_body() {
+	return Object::cast_to<RigidBody2D>(ObjectDB::get_instance(_body_ref));
 }
 
-void GSAIRigidBody2DAgent::set_ *body(const RigidBody2D &val) {
-	*body = val;
+void GSAIRigidBody2DAgent::set_body(RigidBody2D *value) {
+	if (!value) {
+		_body_ref = 0;
+		_physics_process_disconnect();
+		return;
+	}
+
+	_body_ref = value->get_instance_id();
+	_last_position = value->get_global_position();
+	last_orientation = value->get_rotation();
+	position = GSAIUtils::to_vector3(_last_position);
+	orientation = last_orientation;
+
+	if (!value->is_inside_tree()) {
+		value->connect("ready", this, "_physics_process_connect", varray(), CONNECT_ONESHOT);
+	} else {
+		_physics_process_connect();
+	}
 }
 
-Vector2 GSAIRigidBody2DAgent::get__last_position() {
-	return _last_position;
+void GSAIRigidBody2DAgent::set_body_bind(Node *p_body) {
+	set_body(Object::cast_to<RigidBody2D>(p_body));
 }
 
-void GSAIRigidBody2DAgent::set__last_position(const Vector2 &val) {
-	_last_position = val;
+void GSAIRigidBody2DAgent::_physics_process_connect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (!st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->connect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-Ref<WeakRef> GSAIRigidBody2DAgent::get__body_ref() {
-	return _body_ref;
+void GSAIRigidBody2DAgent::_physics_process_disconnect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->disconnect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-void GSAIRigidBody2DAgent::set__body_ref(const Ref<WeakRef> &val) {
-	_body_ref = val;
-}
+void GSAIRigidBody2DAgent::_apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta) {
+	RigidBody2D *body = get_body();
 
-// A specialized steering agent that updates itself every frame so the user does;
-// not have to using a RigidBody2D;
-// @category - Specialized agents;
-// The RigidBody2D to keep track of;
-// setget _set_body;
-RigidBody2D *body;
-Vector2 _last_position = ;
-Ref<WeakRef> _body_ref;
-
-void GSAIRigidBody2DAgent::_body_ready() {
-	// warning-ignore:return_value_discarded;
-	body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame");
-}
-
-// Moves the agent's `body` by target `acceleration`.;
-// @tags - virtual;
-
-void GSAIRigidBody2DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float _delta) {
-	RigidBody2D *_body = _body_ref.get_ref();
-
-	if (not _body) {
+	if (!body) {
 		return;
 	}
 
 	applied_steering = true;
-	_body.apply_central_impulse(GSAIUtils.to_vector2(acceleration.linear));
-	_body.apply_torque_impulse(acceleration.angular);
+	body->apply_central_impulse(GSAIUtils::to_vector2(acceleration->get_linear()));
+	body->apply_torque_impulse(acceleration->get_angular());
 
 	if (calculate_velocities) {
-		linear_velocity = GSAIUtils.to_vector3(_body.linear_velocity);
-		angular_velocity = _body.angular_velocity;
-	}
-}
-
-void GSAIRigidBody2DAgent::_set_body(const RigidBody2D &value) {
-	bool had_body = false;
-
-	if (body) {
-		had_body = true;
-	}
-
-	body = value;
-	_body_ref = weakref(value);
-	_last_position = value.global_position;
-	last_orientation = value.rotation;
-	position = GSAIUtils.to_vector3(_last_position);
-	orientation = last_orientation;
-
-	if (!had_body) {
-		if (!body.is_inside_tree()) {
-			body.connect("ready", self, "_body_ready");
-		}
-
-		else {
-			_body_ready();
-		}
+		linear_velocity = GSAIUtils::to_vector3(body->get_linear_velocity());
+		angular_velocity = body->get_angular_velocity();
 	}
 }
 
 void GSAIRigidBody2DAgent::_on_SceneTree_frame() {
-	RigidBody2D *_body = _body_ref.get_ref();
+	RigidBody2D *body = get_body();
 
-	if (!_body) {
+	if (!body) {
+		call_deferred("_physics_process_disconnect");
 		return;
 	}
 
-	if (!_body.is_inside_tree() || _body.get_tree().paused) {
+	if (!body->is_inside_tree()) {
 		return;
 	}
 
-	Vector2 current_position = _body.global_position;
-	float current_orientation = _body.rotation;
-	position = GSAIUtils.to_vector3(current_position);
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st && st->is_paused()) {
+		return;
+	}
+
+	Vector2 current_position = body->get_global_position();
+	float current_orientation = body->get_rotation();
+	position = GSAIUtils::to_vector3(current_position);
 	orientation = current_orientation;
 
 	if (calculate_velocities) {
 		if (applied_steering) {
 			applied_steering = false;
-		}
-
-		else {
-			linear_velocity = GSAIUtils.to_vector3(_body.linear_velocity);
-			angular_velocity = _body.angular_velocity;
+		} else {
+			linear_velocity = GSAIUtils::to_vector3(body->get_linear_velocity());
+			angular_velocity = body->get_angular_velocity();
 		}
 	}
 }
-}
 
 GSAIRigidBody2DAgent::GSAIRigidBody2DAgent() {
-	*body;
-	_last_position = ;
-	_body_ref;
+	_body_ref = 0;
 }
 
 GSAIRigidBody2DAgent::~GSAIRigidBody2DAgent() {
 }
 
-static void GSAIRigidBody2DAgent::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_*body"), &GSAIRigidBody2DAgent::get_ * body);
-	ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIRigidBody2DAgent::set_ * body);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody2D"), "set_*body", "get_*body");
+void GSAIRigidBody2DAgent::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_body"), &GSAIRigidBody2DAgent::get_body);
+	ClassDB::bind_method(D_METHOD("set_body", "value"), &GSAIRigidBody2DAgent::set_body_bind);
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody2D"), "set_body", "get_body");
 
-	ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIRigidBody2DAgent::get__last_position);
-	ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIRigidBody2DAgent::set__last_position);
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "_last_position"), "set__last_position", "get__last_position");
+	ClassDB::bind_method(D_METHOD("_physics_process_connect"), &GSAIRigidBody2DAgent::_physics_process_connect);
+	ClassDB::bind_method(D_METHOD("_physics_process_disconnect"), &GSAIRigidBody2DAgent::_physics_process_disconnect);
 
-	ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIRigidBody2DAgent::get__body_ref);
-	ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIRigidBody2DAgent::set__body_ref);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
-
-	ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIRigidBody2DAgent::_body_ready);
-	ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "_delta"), &GSAIRigidBody2DAgent::_apply_steering);
-	ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIRigidBody2DAgent::_set_body);
 	ClassDB::bind_method(D_METHOD("_on_SceneTree_frame"), &GSAIRigidBody2DAgent::_on_SceneTree_frame);
 }
diff --git a/modules/steering_ai/agents/gsai_rigid_body_2d_agent.h b/modules/steering_ai/agents/gsai_rigid_body_2d_agent.h
index 11969a32e..2517032e0 100644
--- a/modules/steering_ai/agents/gsai_rigid_body_2d_agent.h
+++ b/modules/steering_ai/agents/gsai_rigid_body_2d_agent.h
@@ -1,22 +1,24 @@
 #ifndef GSAI_RIGID_BODY_2D_AGENT_H
 #define GSAI_RIGID_BODY_2D_AGENT_H
 
+#include "gsai_specialized_agent.h"
+
+class RigidBody2D;
+class GSAITargetAcceleration;
+
 class GSAIRigidBody2DAgent : public GSAISpecializedAgent {
 	GDCLASS(GSAIRigidBody2DAgent, GSAISpecializedAgent);
 
 public:
-	RigidBody2D get_ *body();
-	void set_ *body(const RigidBody2D &val);
+	RigidBody2D *get_body();
+	void set_body(RigidBody2D *p_body);
+	void set_body_bind(Node *p_body);
 
-	Vector2 get__last_position();
-	void set__last_position(const Vector2 &val);
+	void _physics_process_connect();
+	void _physics_process_disconnect();
 
-	Ref<WeakRef> get__body_ref();
-	void set__body_ref(const Ref<WeakRef> &val);
+	void _apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta);
 
-	void _body_ready();
-	void _apply_steering(const GSAITargetAcceleration &acceleration, const float _delta);
-	void _set_body(const RigidBody2D &value);
 	void _on_SceneTree_frame();
 
 	GSAIRigidBody2DAgent();
@@ -30,9 +32,8 @@ protected:
 	// @category - Specialized agents
 	// The RigidBody2D to keep track of
 	// setget _set_body
-	RigidBody2D *body;
-	Vector2 _last_position = ;
-	Ref<WeakRef> _body_ref;
+	Vector2 _last_position;
+	ObjectID _body_ref;
 	// Moves the agent's `body` by target `acceleration`.
 	// @tags - virtual
 };
diff --git a/modules/steering_ai/agents/gsai_rigid_body_3d_agent.cpp b/modules/steering_ai/agents/gsai_rigid_body_3d_agent.cpp
index 59b28a9de..e2dfae918 100644
--- a/modules/steering_ai/agents/gsai_rigid_body_3d_agent.cpp
+++ b/modules/steering_ai/agents/gsai_rigid_body_3d_agent.cpp
@@ -1,142 +1,122 @@
 
 #include "gsai_rigid_body_3d_agent.h"
 
-RigidBody GSAIRigidBody3DAgent::get_ *body() {
-	return *body;
+#include "scene/3d/physics_body.h"
+
+#include "../gsai_target_acceleration.h"
+
+RigidBody *GSAIRigidBody3DAgent::get_body() {
+	return Object::cast_to<RigidBody>(ObjectDB::get_instance(_body_ref));
 }
 
-void GSAIRigidBody3DAgent::set_ *body(const RigidBody &val) {
-	*body = val;
+void GSAIRigidBody3DAgent::set_body(RigidBody *value) {
+	if (!value) {
+		_body_ref = 0;
+		_physics_process_disconnect();
+		return;
+	}
+
+	_body_ref = value->get_instance_id();
+	_last_position = value->get_transform().origin;
+	last_orientation = value->get_rotation().y;
+	position = _last_position;
+	orientation = last_orientation;
+
+	if (!value->is_inside_tree()) {
+		value->connect("ready", this, "_physics_process_connect", varray(), CONNECT_ONESHOT);
+	} else {
+		_physics_process_connect();
+	}
 }
 
-Vector3 GSAIRigidBody3DAgent::get__last_position() {
-	return _last_position;
+void GSAIRigidBody3DAgent::set_body_bind(Node *p_body) {
+	set_body(Object::cast_to<RigidBody>(p_body));
 }
 
-void GSAIRigidBody3DAgent::set__last_position(const Vector3 &val) {
-	_last_position = val;
+void GSAIRigidBody3DAgent::_physics_process_connect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (!st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->connect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-Ref<WeakRef> GSAIRigidBody3DAgent::get__body_ref() {
-	return _body_ref;
+void GSAIRigidBody3DAgent::_physics_process_disconnect() {
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st) {
+		if (st->is_connected("physics_frame", this, "_on_SceneTree_physics_frame")) {
+			st->disconnect("physics_frame", this, "_on_SceneTree_physics_frame");
+		}
+	}
 }
 
-void GSAIRigidBody3DAgent::set__body_ref(const Ref<WeakRef> &val) {
-	_body_ref = val;
-}
+void GSAIRigidBody3DAgent::_apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta) {
+	RigidBody *body = get_body();
 
-// A specialized steering agent that updates itself every frame so the user does;
-// not have to using a RigidBody;
-// @category - Specialized agents;
-// The RigidBody to keep track of;
-// setget _set_body;
-RigidBody *body;
-Vector3 _last_position = ;
-Ref<WeakRef> _body_ref;
-
-void GSAIRigidBody3DAgent::_body_ready() {
-	// warning-ignore:return_value_discarded;
-	body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame");
-}
-
-// Moves the agent's `body` by target `acceleration`.;
-// @tags - virtual;
-
-void GSAIRigidBody3DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float _delta) {
-	RigidBody *_body = _body_ref.get_ref();
-
-	if (!_body) {
+	if (!body || !body->is_inside_tree()) {
 		return;
 	}
 
 	applied_steering = true;
-	_body.apply_central_impulse(acceleration.linear);
-	_body.apply_torque_impulse(Vector3.UP * acceleration.angular);
+	body->apply_central_impulse(acceleration->get_linear());
+	body->apply_torque_impulse(Vector3(0, 1, 0) * acceleration->get_angular());
 
 	if (calculate_velocities) {
-		linear_velocity = _body.linear_velocity;
-		angular_velocity = _body.angular_velocity.y;
-	}
-}
-
-void GSAIRigidBody3DAgent::_set_body(const RigidBody &value) {
-	bool had_body = false;
-
-	if (body) {
-		had_body = true;
-	}
-
-	body = value;
-	_body_ref = weakref(value);
-	_last_position = value.transform.origin;
-	last_orientation = value.rotation.y;
-	position = _last_position;
-	orientation = last_orientation;
-
-	if (!had_body) {
-		if (!body.is_inside_tree()) {
-			body.connect("ready", self, "_body_ready");
-		}
-
-		else {
-			_body_ready();
-		}
+		linear_velocity = body->get_linear_velocity();
+		angular_velocity = body->get_angular_velocity().y;
 	}
 }
 
 void GSAIRigidBody3DAgent::_on_SceneTree_frame() {
-	RigidBody *_body = _body_ref.get_ref();
+	RigidBody *body = get_body();
 
-	if (not _body) {
+	if (!body) {
+		call_deferred("_physics_process_disconnect");
 		return;
 	}
 
-	if (not _body.is_inside_tree() || _body.get_tree().paused) {
+	if (!body->is_inside_tree()) {
 		return;
 	}
 
-	Vector3 current_position = _body.transform.origin;
-	float current_orientation = _body.rotation.y;
+	SceneTree *st = SceneTree::get_singleton();
+
+	if (st && st->is_paused()) {
+		return;
+	}
+
+	Vector3 current_position = body->get_transform().origin;
+	float current_orientation = body->get_rotation().y;
 	position = current_position;
 	orientation = current_orientation;
 
 	if (calculate_velocities) {
 		if (applied_steering) {
 			applied_steering = false;
-		}
-
-		else {
-			linear_velocity = _body.linear_velocity;
-			angular_velocity = _body.angular_velocity.y;
+		} else {
+			linear_velocity = body->get_linear_velocity();
+			angular_velocity = body->get_angular_velocity().y;
 		}
 	}
 }
-}
 
 GSAIRigidBody3DAgent::GSAIRigidBody3DAgent() {
-	*body;
-	_last_position = ;
-	_body_ref;
+	_body_ref = 0;
 }
 
 GSAIRigidBody3DAgent::~GSAIRigidBody3DAgent() {
 }
 
-static void GSAIRigidBody3DAgent::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_*body"), &GSAIRigidBody3DAgent::get_ * body);
-	ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIRigidBody3DAgent::set_ * body);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody"), "set_*body", "get_*body");
+void GSAIRigidBody3DAgent::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_body"), &GSAIRigidBody3DAgent::get_body);
+	ClassDB::bind_method(D_METHOD("set_body", "value"), &GSAIRigidBody3DAgent::set_body_bind);
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody"), "set_body", "get_body");
 
-	ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIRigidBody3DAgent::get__last_position);
-	ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIRigidBody3DAgent::set__last_position);
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_last_position"), "set__last_position", "get__last_position");
+	ClassDB::bind_method(D_METHOD("_physics_process_connect"), &GSAIRigidBody3DAgent::_physics_process_connect);
+	ClassDB::bind_method(D_METHOD("_physics_process_disconnect"), &GSAIRigidBody3DAgent::_physics_process_disconnect);
 
-	ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIRigidBody3DAgent::get__body_ref);
-	ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIRigidBody3DAgent::set__body_ref);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
-
-	ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIRigidBody3DAgent::_body_ready);
-	ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "_delta"), &GSAIRigidBody3DAgent::_apply_steering);
-	ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIRigidBody3DAgent::_set_body);
 	ClassDB::bind_method(D_METHOD("_on_SceneTree_frame"), &GSAIRigidBody3DAgent::_on_SceneTree_frame);
 }
diff --git a/modules/steering_ai/agents/gsai_rigid_body_3d_agent.h b/modules/steering_ai/agents/gsai_rigid_body_3d_agent.h
index ce2988515..207a374d8 100644
--- a/modules/steering_ai/agents/gsai_rigid_body_3d_agent.h
+++ b/modules/steering_ai/agents/gsai_rigid_body_3d_agent.h
@@ -1,22 +1,24 @@
 #ifndef GSAI_RIGID_BODY_3D_AGENT_H
 #define GSAI_RIGID_BODY_3D_AGENT_H
 
+#include "gsai_specialized_agent.h"
+
+class RigidBody;
+class GSAITargetAcceleration;
+
 class GSAIRigidBody3DAgent : public GSAISpecializedAgent {
 	GDCLASS(GSAIRigidBody3DAgent, GSAISpecializedAgent);
 
 public:
-	RigidBody get_ *body();
-	void set_ *body(const RigidBody &val);
+	RigidBody *get_body();
+	void set_body(RigidBody *p_body);
+	void set_body_bind(Node *p_body);
 
-	Vector3 get__last_position();
-	void set__last_position(const Vector3 &val);
+	void _physics_process_connect();
+	void _physics_process_disconnect();
 
-	Ref<WeakRef> get__body_ref();
-	void set__body_ref(const Ref<WeakRef> &val);
+	void _apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta);
 
-	void _body_ready();
-	void _apply_steering(const GSAITargetAcceleration &acceleration, const float _delta);
-	void _set_body(const RigidBody &value);
 	void _on_SceneTree_frame();
 
 	GSAIRigidBody3DAgent();
@@ -30,9 +32,8 @@ protected:
 	// @category - Specialized agents
 	// The RigidBody to keep track of
 	// setget _set_body
-	RigidBody *body;
-	Vector3 _last_position = ;
-	Ref<WeakRef> _body_ref;
+	Vector3 _last_position;
+	ObjectID _body_ref;
 	// Moves the agent's `body` by target `acceleration`.
 	// @tags - virtual
 };
diff --git a/modules/steering_ai/agents/gsai_specialized_agent.cpp b/modules/steering_ai/agents/gsai_specialized_agent.cpp
index dbd97603c..37092be1a 100644
--- a/modules/steering_ai/agents/gsai_specialized_agent.cpp
+++ b/modules/steering_ai/agents/gsai_specialized_agent.cpp
@@ -1,5 +1,7 @@
 
-#include "gsai_specialize_dagent.h"
+#include "gsai_specialized_agent.h"
+
+#include "../gsai_target_acceleration.h"
 
 bool GSAISpecializedAgent::get_calculate_velocities() const {
 	return calculate_velocities;
@@ -57,42 +59,11 @@ void GSAISpecializedAgent::set_applied_steering(const bool val) {
 	applied_steering = val;
 }
 
-// A base class for a specialized steering agent that updates itself every frame;
-// so the user does not have to. All other specialized agents derive from this.;
-// @category - Specialized agents;
-// @tags - abstract;
-// If `true`, calculates linear and angular velocities based on the previous;
-// frame. When `false`, the user must keep those values updated.;
-bool calculate_velocities = true;
-// If `true`, interpolates the current linear velocity towards 0 by the;
-// `linear_drag_percentage` value.;
-// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
-bool apply_linear_drag = true;
-// If `true`, interpolates the current angular velocity towards 0 by the;
-// `angular_drag_percentage` value.;
-// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
-bool apply_angular_drag = true;
-// The percentage between the current linear velocity and 0 to interpolate by if;
-// `apply_linear_drag` is true.;
-// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
-float linear_drag_percentage = 0.0;
-// The percentage between the current angular velocity and 0 to interpolate by if;
-// `apply_angular_drag` is true.;
-// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
-float angular_drag_percentage = 0.0;
-float last_orientation = 0.0;
-bool applied_steering = false;
-
-void GSAISpecializedAgent::apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta) {
-	call("_apply_steering", _acceleration, _delta);
+void GSAISpecializedAgent::apply_steering(const Ref<GSAITargetAcceleration> &acceleration, const float delta) {
+	call("_apply_steering", acceleration, delta);
 }
 
-// Moves the agent's body by target `acceleration`.;
-// @tags - virtual;
-
-void GSAISpecializedAgent::_apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta) {
-	pass;
-}
+void GSAISpecializedAgent::_apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta) {
 }
 
 GSAISpecializedAgent::GSAISpecializedAgent() {
@@ -108,7 +79,7 @@ GSAISpecializedAgent::GSAISpecializedAgent() {
 GSAISpecializedAgent::~GSAISpecializedAgent() {
 }
 
-static void GSAISpecializedAgent::_bind_methods() {
+void GSAISpecializedAgent::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_calculate_velocities"), &GSAISpecializedAgent::get_calculate_velocities);
 	ClassDB::bind_method(D_METHOD("set_calculate_velocities", "value"), &GSAISpecializedAgent::set_calculate_velocities);
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_velocities"), "set_calculate_velocities", "get_calculate_velocities");
@@ -137,6 +108,7 @@ static void GSAISpecializedAgent::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_applied_steering", "value"), &GSAISpecializedAgent::set_applied_steering);
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "applied_steering"), "set_applied_steering", "get_applied_steering");
 
-	ClassDB::bind_method(D_METHOD("apply_steering", "_acceleration", "_delta"), &GSAISpecializedAgent::apply_steering);
-	ClassDB::bind_method(D_METHOD("_apply_steering", "_acceleration", "_delta"), &GSAISpecializedAgent::_apply_steering);
+	BIND_VMETHOD(MethodInfo("_apply_steering", PropertyInfo(Variant::OBJECT, "acceleration", PROPERTY_HINT_RESOURCE_TYPE, "GSAITargetAcceleration"), PropertyInfo(Variant::REAL, "delta")));
+	ClassDB::bind_method(D_METHOD("apply_steering", "acceleration", "delta"), &GSAISpecializedAgent::apply_steering);
+	ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "delta"), &GSAISpecializedAgent::_apply_steering);
 }
diff --git a/modules/steering_ai/agents/gsai_specialized_agent.h b/modules/steering_ai/agents/gsai_specialized_agent.h
index f68cde820..e47b037fd 100644
--- a/modules/steering_ai/agents/gsai_specialized_agent.h
+++ b/modules/steering_ai/agents/gsai_specialized_agent.h
@@ -1,6 +1,12 @@
 #ifndef GSAI_SPECIALIZED_AGENT_H
 #define GSAI_SPECIALIZED_AGENT_H
 
+#include "core/object/reference.h"
+
+#include "../gsai_steering_agent.h"
+
+class GSAITargetAcceleration;
+
 class GSAISpecializedAgent : public GSAISteeringAgent {
 	GDCLASS(GSAISpecializedAgent, GSAISteeringAgent);
 
@@ -26,8 +32,8 @@ public:
 	bool get_applied_steering() const;
 	void set_applied_steering(const bool val);
 
-	void apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta);
-	void _apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta);
+	void apply_steering(const Ref<GSAITargetAcceleration> &acceleration, const float delta);
+	virtual void _apply_steering(Ref<GSAITargetAcceleration> acceleration, float delta);
 
 	GSAISpecializedAgent();
 	~GSAISpecializedAgent();
@@ -41,25 +47,25 @@ protected:
 	// @tags - abstract
 	// If `true`, calculates linear and angular velocities based on the previous
 	// frame. When `false`, the user must keep those values updated.
-	bool calculate_velocities = true;
+	bool calculate_velocities;
 	// If `true`, interpolates the current linear velocity towards 0 by the
 	// `linear_drag_percentage` value.
 	// Does not apply to `RigidBody` and `RigidBody2D` nodes.
-	bool apply_linear_drag = true;
+	bool apply_linear_drag;
 	// If `true`, interpolates the current angular velocity towards 0 by the
 	// `angular_drag_percentage` value.
 	// Does not apply to `RigidBody` and `RigidBody2D` nodes.
-	bool apply_angular_drag = true;
+	bool apply_angular_drag;
 	// The percentage between the current linear velocity and 0 to interpolate by if
 	// `apply_linear_drag` is true.
 	// Does not apply to `RigidBody` and `RigidBody2D` nodes.
-	float linear_drag_percentage = 0.0;
+	float linear_drag_percentage;
 	// The percentage between the current angular velocity and 0 to interpolate by if
 	// `apply_angular_drag` is true.
 	// Does not apply to `RigidBody` and `RigidBody2D` nodes.
-	float angular_drag_percentage = 0.0;
-	float last_orientation = 0.0;
-	bool applied_steering = false;
+	float angular_drag_percentage;
+	float last_orientation;
+	bool applied_steering;
 	// Moves the agent's body by target `acceleration`.
 	// @tags - virtual
 };
diff --git a/modules/steering_ai/config.py b/modules/steering_ai/config.py
index 6481b0b0b..5510ae6a4 100644
--- a/modules/steering_ai/config.py
+++ b/modules/steering_ai/config.py
@@ -33,6 +33,12 @@ def get_doc_classes():
         "GSAIPursue",
         "GSAISeek",
         "GSAISeparation",
+
+        "GSAIKinematicBody2DAgent",
+        "GSAIKinematicBody3DAgent",
+        "GSAIRigidBody2DAgent",
+        "GSAIRigidBody3DAgent",
+        "GSAISpecializedAgent",
     ]
 
 def get_doc_path():
diff --git a/modules/steering_ai/register_types.cpp b/modules/steering_ai/register_types.cpp
index b0d2e36a4..f0b374feb 100644
--- a/modules/steering_ai/register_types.cpp
+++ b/modules/steering_ai/register_types.cpp
@@ -53,6 +53,12 @@ SOFTWARE.
 #include "behaviors/gsai_seek.cpp"
 #include "behaviors/gsai_separation.cpp"
 
+#include "agents/gsai_kinematic_body_2d_agent.cpp"
+#include "agents/gsai_kinematic_body_3d_agent.cpp"
+#include "agents/gsai_rigid_body_2d_agent.cpp"
+#include "agents/gsai_rigid_body_3d_agent.cpp"
+#include "agents/gsai_specialized_agent.cpp"
+
 static GSAIUtils *gs_ai_utils = NULL;
 
 void register_steering_ai_types() {
@@ -85,6 +91,12 @@ void register_steering_ai_types() {
 	ClassDB::register_class<GSAIPursue>();
 	ClassDB::register_class<GSAISeek>();
 	ClassDB::register_class<GSAISeparation>();
+
+	ClassDB::register_class<GSAIKinematicBody2DAgent>();
+	ClassDB::register_class<GSAIKinematicBody3DAgent>();
+	ClassDB::register_class<GSAIRigidBody2DAgent>();
+	ClassDB::register_class<GSAIRigidBody3DAgent>();
+	ClassDB::register_class<GSAISpecializedAgent>();
 }
 
 void unregister_steering_ai_types() {