Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Authors: Lokilife
using System.Numerics;
using Content.Shared.Exodus.Tailed;
using Robust.Shared.Map;
using Robust.Shared.Physics.Components;

namespace Content.Shared.Movement.Systems;
Expand Down Expand Up @@ -60,6 +61,10 @@ private void ApplySegmentVelocities(
if (!TryComp<PhysicsComponent>(segment, out var physics))
continue;

var xform = Transform(segment);
if (!xform.ParentUid.IsValid())
continue;

var currentPos = _transform.GetWorldPosition(segment);
Vector2 desiredVelocity;

Expand Down Expand Up @@ -129,6 +134,9 @@ private void UpdateSegmentRotation(
{
var segment = tail.TailSegments[i];
var segmentPos = _transform.GetWorldPosition(segment);
var segmentXform = Transform(segment);
if (!segmentXform.ParentUid.IsValid())
continue;
Comment on lines 136 to +139
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

GetWorldPosition is called before the parent validity check.

_transform.GetWorldPosition(segment) on line 136 runs before the ParentUid.IsValid() guard on line 138. If the segment has no valid parent, this call may produce a garbage position or throw. Move the guard above the position lookup, consistent with how ApplySegmentVelocities handles it (lines 64–68).

Proposed fix
         var segment = tail.TailSegments[i];
+        var segmentXform = Transform(segment);
+        if (!segmentXform.ParentUid.IsValid())
+            continue;
+
         var segmentPos = _transform.GetWorldPosition(segment);
-        var segmentXform = Transform(segment);
-        if (!segmentXform.ParentUid.IsValid())
-            continue;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var segmentPos = _transform.GetWorldPosition(segment);
var segmentXform = Transform(segment);
if (!segmentXform.ParentUid.IsValid())
continue;
var segmentXform = Transform(segment);
if (!segmentXform.ParentUid.IsValid())
continue;
var segmentPos = _transform.GetWorldPosition(segment);
🤖 Prompt for AI Agents
In `@Content.Shared/Movement/Systems/SharedMoverController.Tailed.cs` around lines
136 - 139, The GetWorldPosition call on the segment is happening before the
parent validity check, which could produce incorrect results if the parent is
invalid. Move the guard that checks if segmentXform.ParentUid.IsValid() to occur
before calling _transform.GetWorldPosition(segment), so invalid parent segments
are skipped before attempting the position lookup. Follow the same pattern used
in the ApplySegmentVelocities method where the parent validity check happens
first, then the transform operations proceed only for valid parents.


var direction = prevPos - segmentPos;

Expand Down
17 changes: 14 additions & 3 deletions Content.Shared/_Exodus/Tailed/TailedEntitySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ private void OnComponentStartup(EntityUid uid, TailedEntityComponent component,

private void OnComponentShutdown(EntityUid uid, TailedEntityComponent component, ComponentShutdown args)
{
// CRITICAL: Remove joints before deleting entities
// This prevents physics from trying to update positions of entities being deleted
var prev = uid;
foreach (var segment in component.TailSegments)
{
// Remove the joint between prev and this segment
_joint.RemoveJoint(prev, $"TailJoint_{prev}_{segment}");
prev = segment;
}

// Now safe to queue deletion
foreach (var segment in component.TailSegments)
QueueDel(segment);

Expand All @@ -59,8 +70,8 @@ private void InitializeTailSegments(Entity<TailedEntityComponent, TransformCompo
{
var (uid, comp, xform) = ent;

var mapUid = xform.MapUid;
if (mapUid == null)
var parentUid = xform.ParentUid;
if (!parentUid.IsValid())
return;

// Ensure the head entity has physics for joints
Expand All @@ -77,7 +88,7 @@ private void InitializeTailSegments(Entity<TailedEntityComponent, TransformCompo
var offset = headRot.ToWorldVec() * comp.Spacing * (i + 1);
var spawnPos = headPos - offset;

var segment = PredictedSpawnAtPosition(comp.Prototype, new EntityCoordinates(mapUid.Value, spawnPos));
var segment = PredictedSpawnAtPosition(comp.Prototype, new EntityCoordinates(parentUid, spawnPos));

_transform.SetWorldRotation(segment, headRot);

Expand Down
Loading