From fbb92e3593fcddbdc7cd4d3c07310adaa26c4263 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 20 Feb 2020 10:58:00 -0500 Subject: [PATCH] Replace body with WeakRef of body to fix crashes When a physics body was freed by queue_free or free, it was possible for the physics update to still happen on the specialized agent. The Null body then caused a crash. --- CHANGELOG.md | 11 +++++ .../src/Agents/GSAIKinematicBody2DAgent.gd | 43 ++++++++++++++----- .../src/Agents/GSAIKinematicBody3DAgent.gd | 43 ++++++++++++++----- project/src/Agents/GSAIRigidBody2DAgent.gd | 33 ++++++++------ project/src/Agents/GSAIRigidBody3DAgent.gd | 42 +++++++++--------- project/src/Agents/GSAISpecializedAgent.gd | 1 - 6 files changed, 116 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4124ad6..e5474f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ This document lists new features, improvements, changes, and bug fixes in every release of the add-on. +## Godot Steering AI Framework 2.1.1 ## + +### Changes ### + +- Unused and undocumented variable `_body_type` has been removed from `SpecializedAgent` + +### Bug fixes ### + +- The specialized agents now use WeakRef internally to prevent crashes when their `body` is freed. +- `RigidBody2DAgent` now properly connects to physics updates. + ## Godot Steering AI Framework 2.1.0 ## ### Features ### diff --git a/project/src/Agents/GSAIKinematicBody2DAgent.gd b/project/src/Agents/GSAIKinematicBody2DAgent.gd index 006fb8e..ff360f5 100644 --- a/project/src/Agents/GSAIKinematicBody2DAgent.gd +++ b/project/src/Agents/GSAIKinematicBody2DAgent.gd @@ -15,17 +15,18 @@ var body: KinematicBody2D setget _set_body var movement_type: int var _last_position: Vector2 +var _body_ref: WeakRef func _init(_body: KinematicBody2D, _movement_type: int = MovementType.SLIDE) -> void: if not _body.is_inside_tree(): yield(_body, "ready") - self.body = _body + _body_ref = weakref(_body) self.movement_type = _movement_type # warning-ignore:return_value_discarded - body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") + _body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") # Moves the agent's `body` by target `acceleration`. @@ -44,55 +45,75 @@ func _apply_steering(acceleration: GSAITargetAcceleration, delta: float) -> void func _apply_sliding_steering(accel: Vector3) -> void: + var _body: KinematicBody2D = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.to_vector2(linear_velocity + accel).clamped(linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag_percentage) - velocity = body.move_and_slide(velocity) + velocity = _body.move_and_slide(velocity) if calculate_velocities: linear_velocity = GSAIUtils.to_vector3(velocity) func _apply_collide_steering(accel: Vector3, delta: float) -> void: + var _body: KinematicBody2D = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) # warning-ignore:return_value_discarded - body.move_and_collide(GSAIUtils.to_vector2(velocity) * delta) + _body.move_and_collide(GSAIUtils.to_vector2(velocity) * delta) if calculate_velocities: linear_velocity = velocity func _apply_position_steering(accel: Vector3, delta: float) -> void: + var _body: KinematicBody2D = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) - body.global_position += GSAIUtils.to_vector2(velocity) * delta + _body.global_position += GSAIUtils.to_vector2(velocity) * delta if calculate_velocities: linear_velocity = velocity func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + var _body: KinematicBody2D = _body_ref.get_ref() + if not _body: + return + var velocity = angular_velocity + angular_acceleration if apply_angular_drag: velocity = lerp(velocity, 0, angular_drag_percentage) - body.rotation += velocity * delta + _body.rotation += velocity * delta if calculate_velocities: angular_velocity = velocity func _set_body(value: KinematicBody2D) -> void: - body = value + _body_ref = weakref(body) - _last_position = body.global_position - _last_orientation = body.rotation + _last_position = value.global_position + _last_orientation = value.rotation position = GSAIUtils.to_vector3(_last_position) orientation = _last_orientation func _on_SceneTree_physics_frame() -> void: - var current_position := body.global_position - var current_orientation := body.rotation + var _body: KinematicBody2D = _body_ref.get_ref() + if not _body: + return + + var current_position := _body.global_position + var current_orientation := _body.rotation position = GSAIUtils.to_vector3(current_position) orientation = current_orientation diff --git a/project/src/Agents/GSAIKinematicBody3DAgent.gd b/project/src/Agents/GSAIKinematicBody3DAgent.gd index d12f9e8..6742089 100644 --- a/project/src/Agents/GSAIKinematicBody3DAgent.gd +++ b/project/src/Agents/GSAIKinematicBody3DAgent.gd @@ -15,17 +15,18 @@ var body: KinematicBody setget _set_body var movement_type: int var _last_position: Vector3 +var _body_ref: WeakRef func _init(_body: KinematicBody, _movement_type: int = MovementType.SLIDE) -> void: if not _body.is_inside_tree(): yield(_body, "ready") - self.body = _body + self._body_ref = weakref(_body) self.movement_type = _movement_type # warning-ignore:return_value_discarded - self.body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") + _body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") # Moves the agent's `body` by target `acceleration`. @@ -44,55 +45,75 @@ func _apply_steering(acceleration: GSAITargetAcceleration, delta: float) -> void func _apply_sliding_steering(accel: Vector3) -> void: + var _body: KinematicBody = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) - velocity = body.move_and_slide(velocity) + velocity = _body.move_and_slide(velocity) if calculate_velocities: linear_velocity = velocity func _apply_collide_steering(accel: Vector3, delta: float) -> void: + var _body: KinematicBody = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) # warning-ignore:return_value_discarded - body.move_and_collide(velocity * delta) + _body.move_and_collide(velocity * delta) if calculate_velocities: linear_velocity = velocity func _apply_position_steering(accel: Vector3, delta: float) -> void: + var _body: KinematicBody = _body_ref.get_ref() + if not _body: + return + var velocity := GSAIUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) - body.global_position += velocity * delta + _body.global_position += velocity * delta if calculate_velocities: linear_velocity = velocity func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + var _body: KinematicBody = _body_ref.get_ref() + if not _body: + return + var velocity = angular_velocity + angular_acceleration if apply_angular_drag: velocity = lerp(velocity, 0, angular_drag_percentage) - body.rotation.y += velocity * delta + _body.rotation.y += velocity * delta if calculate_velocities: angular_velocity = velocity func _set_body(value: KinematicBody) -> void: - body = value + _body_ref = weakref(value) - _last_position = body.transform.origin - _last_orientation = body.rotation.y + _last_position = value.transform.origin + _last_orientation = value.rotation.y position = _last_position orientation = _last_orientation func _on_SceneTree_physics_frame() -> void: - var current_position := body.transform.origin - var current_orientation := body.rotation.y + var _body: KinematicBody = _body_ref.get_ref() + if not _body: + return + + var current_position := _body.transform.origin + var current_orientation := _body.rotation.y position = current_position orientation = current_orientation diff --git a/project/src/Agents/GSAIRigidBody2DAgent.gd b/project/src/Agents/GSAIRigidBody2DAgent.gd index f8d814f..d2ad3a2 100644 --- a/project/src/Agents/GSAIRigidBody2DAgent.gd +++ b/project/src/Agents/GSAIRigidBody2DAgent.gd @@ -7,43 +7,48 @@ class_name GSAIRigidBody2DAgent var body: RigidBody2D setget _set_body var _last_position: Vector2 +var _body_ref: WeakRef func _init(_body: RigidBody2D) -> void: if not _body.is_inside_tree(): yield(_body, "ready") - self.body = _body + _body_ref = weakref(_body) + # 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 func _apply_steering(acceleration: GSAITargetAcceleration, _delta: float) -> void: + var _body: RigidBody2D = _body_ref.get_ref() + if not _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.linear)) + _body.apply_torque_impulse(acceleration.angular) if calculate_velocities: - linear_velocity = GSAIUtils.to_vector3(body.linear_velocity) - angular_velocity = body.angular_velocity + linear_velocity = GSAIUtils.to_vector3(_body.linear_velocity) + angular_velocity = _body.angular_velocity func _set_body(value: RigidBody2D) -> void: - body = value + _body_ref = weakref(value) - _last_position = body.global_position - _last_orientation = body.rotation + _last_position = value.global_position + _last_orientation = value.rotation position = GSAIUtils.to_vector3(_last_position) orientation = _last_orientation -func _on_body_ready() -> void: - # warning-ignore:return_value_discarded - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - _set_body(body) - - func _on_SceneTree_frame() -> void: + var _body: RigidBody2D = _body_ref.get_ref() + if not _body: + return + var current_position := body.global_position var current_orientation := body.rotation diff --git a/project/src/Agents/GSAIRigidBody3DAgent.gd b/project/src/Agents/GSAIRigidBody3DAgent.gd index 78bc462..a98e4d5 100644 --- a/project/src/Agents/GSAIRigidBody3DAgent.gd +++ b/project/src/Agents/GSAIRigidBody3DAgent.gd @@ -7,47 +7,49 @@ class_name GSAIRigidBody3DAgent var body: RigidBody setget _set_body var _last_position: Vector3 - +var _body_ref: WeakRef func _init(_body: RigidBody) -> void: if not _body.is_inside_tree(): yield(_body, "ready") - self.body = _body + _body_ref = weakref(_body) # warning-ignore:return_value_discarded - self.body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + _body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") # Moves the agent's `body` by target `acceleration`. # tags: virtual func _apply_steering(acceleration: GSAITargetAcceleration, _delta: float) -> void: + var _body: RigidBody = _body_ref.get_ref() + if not _body: + return + _applied_steering = true - body.apply_central_impulse(acceleration.linear) - body.apply_torque_impulse(Vector3.UP * acceleration.angular) + _body.apply_central_impulse(acceleration.linear) + _body.apply_torque_impulse(Vector3.UP * acceleration.angular) if calculate_velocities: - linear_velocity = body.linear_velocity - angular_velocity = body.angular_velocity.y + linear_velocity = _body.linear_velocity + angular_velocity = _body.angular_velocity.y func _set_body(value: RigidBody) -> void: - body = value + _body_ref = weakref(value) - _last_position = body.transform.origin - _last_orientation = body.rotation.y + _last_position = value.transform.origin + _last_orientation = value.rotation.y position = _last_position orientation = _last_orientation -func _on_body_ready() -> void: - # warning-ignore:return_value_discarded - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - _set_body(body) - - func _on_SceneTree_frame() -> void: - var current_position := body.transform.origin - var current_orientation := body.rotation.y + var _body: RigidBody = _body_ref.get_ref() + if not _body: + return + + var current_position := _body.transform.origin + var current_orientation := _body.rotation.y position = current_position orientation = current_orientation @@ -56,5 +58,5 @@ func _on_SceneTree_frame() -> void: if _applied_steering: _applied_steering = false else: - linear_velocity = body.linear_velocity - angular_velocity = body.angular_velocity.y + linear_velocity = _body.linear_velocity + angular_velocity = _body.angular_velocity.y diff --git a/project/src/Agents/GSAISpecializedAgent.gd b/project/src/Agents/GSAISpecializedAgent.gd index 18be399..f6ab9f6 100644 --- a/project/src/Agents/GSAISpecializedAgent.gd +++ b/project/src/Agents/GSAISpecializedAgent.gd @@ -29,7 +29,6 @@ var linear_drag_percentage := 0.0 var angular_drag_percentage := 0.0 var _last_orientation: float -var _body_type: int var _applied_steering := false