feat(runtime): own SetPosition collision reports

This commit is contained in:
Erik 2026-08-01 00:15:11 +02:00
parent ec627c13a2
commit 237d1184d2
19 changed files with 3744 additions and 103 deletions

View file

@ -323,6 +323,14 @@ public sealed class RuntimeEntityDirectory
record.FinalPhysicsState = state;
}
internal bool StopMissileAfterCollision(
RuntimeEntityRecord record,
bool requireCurrentMissile)
{
EnsureKnown(record);
return record.StopMissileAfterCollision(requireCurrentMissile);
}
public void SetHasPartArray(RuntimeEntityRecord record, bool value)
{
EnsureKnown(record);

View file

@ -450,6 +450,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
Physics.SetPosition.Forget(
canonical,
releasePreparedMover: true);
Physics.CollisionReports.Forget(canonical);
Physics.RemoveSpatialProjection(canonical);
Entities.SetRemoteMotion(canonical, null);
Entities.SetRemoteMotionBindingInProgress(canonical, false);
@ -540,6 +541,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
Entities.RefreshSnapshot(canonical, accepted);
Entities.AdvancePositionAuthority(canonical);
Physics.CollisionReports.LeaveWorld(canonical);
RuntimePlacementCancellationReceipt cancellation =
Physics.SetPosition.Forget(canonical);
Entities.SuspendObjectClock(canonical);
@ -631,6 +633,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
RuntimePlacementCancellationReceipt cancellation =
Physics.SetPosition.Forget(canonical);
Physics.CollisionReports.LeaveWorld(canonical);
Entities.SuspendObjectClock(canonical);
Entities.SetFullCell(canonical, 0u, 0u);
ulong spatialVersion = canonical.SpatialAuthorityVersion;
@ -730,6 +733,22 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
}
Entities.RefreshSnapshot(canonical, accepted);
RetailPhysicsStateTransition preview =
RetailPhysicsStateTransitions.Apply(
canonical.FinalPhysicsState,
(PhysicsStateFlags)update.PhysicsState);
ulong priorPhysicsMutation = canonical.PhysicsStateMutationVersion;
if (preview.HiddenTransition is RetailHiddenTransition.BecameHidden)
{
Physics.CollisionReports.LeaveWorld(canonical);
if (!Entities.IsCurrent(canonical)
|| canonical.PhysicsStateMutationVersion
!= priorPhysicsMutation)
{
transition = default;
return false;
}
}
transition = Entities.ApplyRawPhysicsState(
canonical,
update.PhysicsState);
@ -878,6 +897,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
if (!Entities.IsCurrent(canonical))
return false;
Physics.CollisionReports.LeaveWorld(canonical);
Entities.SuspendObjectClock(canonical);
Entities.SetFullCell(canonical, 0u, 0u);
ulong spatialVersion = canonical.SpatialAuthorityVersion;
@ -955,6 +975,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
&& active.Incarnation == delete.InstanceSequence
&& Entities.RemoveActive(active))
{
Physics.CollisionReports.Forget(active);
RuntimePlacementCancellationReceipt cancellation =
Physics.SetPosition.Forget(
active,
@ -1030,9 +1051,11 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
return Array.Empty<RuntimeEntityRecord>();
_sessionClearInProgress = true;
Physics.SetPosition.ResetSession();
Entities.BeginSessionClear();
RuntimeEntityRecord[] active = Entities.ActiveRecords.ToArray();
Physics.CollisionReports.LeaveWorldBatch(active);
Physics.SetPosition.ResetSession();
Physics.CollisionReports.ResetSession();
Entities.BeginSessionClear();
foreach (RuntimeEntityRecord canonical in active)
{
Physics.SetPosition.Forget(canonical);
@ -1166,6 +1189,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
Entities.RefreshSnapshot(canonical, accepted);
Entities.AdvancePositionAuthority(canonical);
Physics.CollisionReports.LeaveWorld(canonical);
RuntimePlacementCancellationReceipt cancellation =
Physics.SetPosition.Forget(canonical);
ulong positionVersion = canonical.PositionAuthorityVersion;

View file

@ -164,6 +164,29 @@ public sealed class RuntimeEntityRecord
PhysicsBody.State = FinalPhysicsState;
}
/// <summary>
/// Retail collision reporting clears Missile, AlignPath, and PathClipped
/// directly on the live CPhysicsObj. Keep the canonical record and its
/// borrowed body in the same mutation edge.
/// </summary>
internal bool StopMissileAfterCollision(bool requireCurrentMissile)
{
const PhysicsStateFlags stopped = PhysicsStateFlags.Missile
| PhysicsStateFlags.AlignPath
| PhysicsStateFlags.PathClipped;
if (requireCurrentMissile
&& (FinalPhysicsState & PhysicsStateFlags.Missile) == 0)
return false;
PhysicsStateFlags final = FinalPhysicsState & ~stopped;
if (final == FinalPhysicsState)
return false;
PhysicsStateMutationVersion++;
FinalPhysicsState = final;
if (PhysicsBody is not null)
PhysicsBody.State = FinalPhysicsState;
return true;
}
internal void RefreshDerivedState(bool refreshPosition = true)
{
if (refreshPosition && Snapshot.Position is { } position)