feat(runtime): commit dormant SetPosition activation

This commit is contained in:
Erik 2026-08-01 14:25:02 +02:00
parent 99f867f053
commit 5785a07b3e
13 changed files with 4674 additions and 111 deletions

View file

@ -707,6 +707,57 @@ public sealed class PlayerMovementController
internal bool IsRuntimeOwnedDormant => _publicationLifecycle
is PlayerMovementControllerPublicationLifecycle.RuntimeOwnedDormant;
internal bool IsRuntimePublished => _publicationLifecycle
is PlayerMovementControllerPublicationLifecycle.RuntimePublished;
private bool _dormantSetPositionGroundPhase;
internal void BeginDormantSetPositionGroundPhase()
{
if (!IsRuntimeOwnedDormant || _dormantSetPositionGroundPhase)
throw new InvalidOperationException(
"Dormant SetPosition ground phase requires one dormant Runtime owner.");
_dormantSetPositionGroundPhase = true;
}
internal void EndDormantSetPositionGroundPhase()
{
if (!_dormantSetPositionGroundPhase)
throw new InvalidOperationException(
"Dormant SetPosition ground phase is not active.");
_body.TransientState &= ~TransientStateFlags.Active;
_dormantSetPositionGroundPhase = false;
}
internal bool IsDormantSetPositionGroundPhaseActive =>
_dormantSetPositionGroundPhase;
internal void RefreshDormantRuntimePhysicsState(
PhysicsStateFlags state,
bool recalculateAcceleration)
{
if (!IsRuntimeOwnedDormant || _dormantSetPositionGroundPhase)
throw new InvalidOperationException(
"Only an idle dormant Runtime owner can refresh physics state.");
_body.State = state;
if (recalculateAcceleration)
_body.calc_acceleration();
}
internal void RefreshDormantRuntimeVector(
Vector3? velocity,
Vector3? omega)
{
if (!IsRuntimeOwnedDormant || _dormantSetPositionGroundPhase)
throw new InvalidOperationException(
"Only an idle dormant Runtime owner can refresh vector state.");
if (velocity is { } liveVelocity)
_body.set_velocity(liveVelocity);
if (omega is { } liveOmega)
_body.Omega = liveOmega;
_body.TransientState &= ~TransientStateFlags.Active;
}
internal void SealPublicationCandidate()
{
if (_publicationLifecycle
@ -738,7 +789,8 @@ public sealed class PlayerMovementController
{
if (_publicationLifecycle
is not PlayerMovementControllerPublicationLifecycle
.RuntimeOwnedDormant)
.RuntimeOwnedDormant
|| _dormantSetPositionGroundPhase)
{
throw new InvalidOperationException(
"Only a dormant Runtime-owned movement controller can be activated.");
@ -747,6 +799,30 @@ public sealed class PlayerMovementController
.RuntimePublished;
}
/// <summary>
/// Installs the already-committed Runtime SetPosition frame into the
/// controller's interpolation/cell sidecar without invoking the public
/// teleport path. The canonical body is written by Runtime first; this
/// method only makes the controller's private frame agree while it is
/// still dormant. It deliberately does not touch CellGraph, movement,
/// PositionManager, the object clock, or callbacks.
/// </summary>
internal void CommitRuntimeActivationFrame()
{
if (_publicationLifecycle
is not PlayerMovementControllerPublicationLifecycle
.RuntimeOwnedDormant
|| _dormantSetPositionGroundPhase)
{
throw new InvalidOperationException(
"Only a dormant Runtime-owned movement controller can accept its activation frame.");
}
_prevPhysicsPos = _body.Position;
_currPhysicsPos = _body.Position;
CellId = _body.CellPosition.ObjCellId;
}
internal void DiscardRuntimeCandidate()
{
if (_publicationLifecycle
@ -775,7 +851,8 @@ public sealed class PlayerMovementController
is PlayerMovementControllerPublicationLifecycle.StandalonePublished
or PlayerMovementControllerPublicationLifecycle
.CandidatePreparing
or PlayerMovementControllerPublicationLifecycle.RuntimePublished)
or PlayerMovementControllerPublicationLifecycle.RuntimePublished
|| IsRuntimeOwnedDormant && _dormantSetPositionGroundPhase)
{
return;
}
@ -807,6 +884,9 @@ public sealed class PlayerMovementController
if ((_body.State & PhysicsStateFlags.Static) != 0)
return;
if (IsRuntimeOwnedDormant && _dormantSetPositionGroundPhase)
return;
_objectClock.Activate();
_body.TransientState |= TransientStateFlags.Active;
}

View file

@ -1,5 +1,6 @@
using System.Numerics;
using AcDream.Core.Physics;
using AcDream.Core.Physics.Motion;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Physics;
@ -23,6 +24,26 @@ internal enum RuntimeLocalPlayerPhysicsActivationStatus
RejectedToken,
}
internal enum RuntimeLocalPlayerShadowDisposition : byte
{
RegisteredAuthoredPayload,
ProvenShapeless,
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationPreparation(
float Radius,
float Height,
RuntimeLocalPlayerShadowDisposition ShadowDisposition)
{
internal bool IsValid => float.IsFinite(Radius)
&& Radius >= 0f
&& float.IsFinite(Height)
&& Height >= 0f
&& ShadowDisposition is RuntimeLocalPlayerShadowDisposition
.RegisteredAuthoredPayload
or RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
}
internal readonly record struct RuntimeLocalPlayerPhysicsPublicationToken(
RuntimeEntityKey Entity,
RuntimeEntityPlacementToken Placement,
@ -111,6 +132,12 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
{ get; init; }
internal required PlayerMovementController Controller { get; init; }
internal required PhysicsBody Body { get; init; }
internal required EntityPhysicsHost PhysicsHost { get; init; }
internal required MovementManager Movement { get; init; }
internal required MotionInterpreter Motion { get; init; }
internal required RuntimeLocalPlayerPhysicsActivationPreparation
ActivationPreparation { get; init; }
internal required Activation PreparedActivation { get; init; }
}
private sealed class Activation
@ -122,8 +149,15 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
{ get; init; }
internal required PlayerMovementController Controller { get; init; }
internal required PhysicsBody Body { get; init; }
internal required EntityPhysicsHost PhysicsHost { get; init; }
internal required MovementManager Movement { get; init; }
internal required MotionInterpreter Motion { get; init; }
internal required RuntimeLocalPlayerPhysicsActivationPreparation
ActivationPreparation { get; init; }
internal RuntimeLocalPlayerPhysicsActivationReceipt Receipt
{ get; set; }
internal RuntimeDormantSetPositionCommitReceipt PendingFinalCommit
{ get; set; }
}
private readonly RuntimeEntityDirectory _entities;
@ -135,6 +169,7 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
private ulong _nextPublicationId;
private ulong _nextActivationId;
private ulong _nextEvaluationId;
private long _activationDispatchFailureCount;
private bool _disposed;
internal RuntimeLocalPlayerPhysicsPublicationState(
@ -154,14 +189,25 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
in RuntimeEntityPlacementToken placement,
in RuntimeSetPositionCommand command,
PlayerMovementConstructionOptions options,
in RuntimeLocalPlayerPhysicsActivationPreparation activationPreparation,
out RuntimeLocalPlayerPhysicsPublicationToken token)
{
ObjectDisposedException.ThrowIf(_disposed, this);
ArgumentNullException.ThrowIfNull(record);
token = default;
if (!CanPrepare(record, placement, command))
if (!activationPreparation.IsValid
|| !CanPrepare(record, placement, command))
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedAuthority;
// Exhaustion is checked before allocating or replacing a private
// candidate. A checked overflow must not strand an unowned controller
// or discard an already-prepared exact receipt.
ulong publicationId = checked(_nextPublicationId + 1UL);
ulong activationId = checked(_nextActivationId + 1UL);
RuntimeLocalPlayerPhysicsActivationPreparation preparedActivation =
activationPreparation;
var controller = PlayerMovementController.CreatePublicationCandidate(
_physics.Engine,
options);
@ -177,6 +223,69 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
controller.SetBodyOrientation(command.Physics.Orientation);
controller.ApplyPhysicsState(record.FinalPhysicsState);
PhysicsBody body = controller.PhysicsBody;
var physics = record.Snapshot.Physics;
body.Friction = NormalizeFriction(
physics?.Friction ?? record.Snapshot.Friction);
body.Elasticity = NormalizeElasticity(
physics?.Elasticity
?? record.Snapshot.Elasticity
?? body.Elasticity);
if (physics?.Velocity is { } initialVelocity)
body.set_velocity(initialVelocity);
if (physics?.AngularVelocity is { } initialOmega)
body.Omega = initialOmega;
MovementManager movement = controller.Movement;
MotionInterpreter motion = controller.Motion;
EntityPhysicsHost physicsHost = null!;
movement.MoveToFactory = () =>
{
var moveTo = new MoveToManager(
motion,
stopCompletely: () =>
_ = controller.StopCompletelyAtPhysicsObjectBoundary(),
getPosition: () => body.CellPosition,
getHeading: () => MoveToMath.GetHeading(body.Orientation),
setHeading: (heading, _) => body.Orientation =
MoveToMath.SetHeading(body.Orientation, heading),
getOwnRadius: () => preparedActivation.Radius,
getOwnHeight: () => preparedActivation.Height,
contact: () => body.InContact,
isInterpolating: static () => false,
getVelocity: () => body.Velocity,
getSelfId: () => record.ServerGuid,
setTarget: (context, target, radius, quantum) =>
physicsHost.SetTarget(context, target, radius, quantum),
clearTarget: () => physicsHost.ClearTarget(),
getTargetQuantum: () =>
physicsHost.TargetManager.GetTargetQuantum(),
setTargetQuantum: quantum =>
physicsHost.TargetManager.SetTargetQuantum(quantum),
curTime: () => controller.SimTimeSeconds);
moveTo.StickTo = (target, radius, height) =>
physicsHost.PositionManager.StickTo(target, radius, height);
moveTo.Unstick = physicsHost.PositionManager.UnStick;
return moveTo;
};
physicsHost = new EntityPhysicsHost(
record.ServerGuid,
getPosition: () => body.CellPosition,
getVelocity: () => body.Velocity,
getRadius: () => preparedActivation.Radius,
inContact: () => body.InContact,
minterpMaxSpeed: () => motion.GetAdjustedMaxSpeed(),
curTime: () => controller.SimTimeSeconds,
physicsTimerTime: () => controller.SimTimeSeconds,
getObjectA: id => _physics.TryGetPhysicsHost(id, out var host)
? host
: null,
handleUpdateTarget: movement.HandleUpdateTarget,
interruptCurrentMovement: () =>
movement.CancelMoveTo(WeenieError.ActionCancelled));
movement.MakeMoveToManager();
motion.UnstickFromObject = physicsHost.PositionManager.UnStick;
motion.InterruptCurrentMovement = () =>
movement.CancelMoveTo(WeenieError.ActionCancelled);
controller.PositionManager = physicsHost.PositionManager;
// This checkpoint publishes ownership only. The subsequent canonical
// SetPosition transaction is the sole authority which may enter the
// body into world simulation and activate its ordinary workset.
@ -194,16 +303,41 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
}
DiscardCurrent();
_nextPublicationId = publicationId;
_nextActivationId = activationId;
token = new RuntimeLocalPlayerPhysicsPublicationToken(
record.Key.Value,
placement,
checked(++_nextPublicationId),
publicationId,
_identity.ServerGuid,
_identity.Revision,
record.PhysicsOwnershipEpoch,
record.ObjectClockEpoch,
_movement.ControllerOwnershipEpoch,
_entities.SessionLifetimeVersion);
ulong expectedControllerEpoch = checked(
_movement.ControllerOwnershipEpoch + 1UL);
var activationEnvelope = new Activation
{
Token = new RuntimeLocalPlayerPhysicsActivationToken(
token.Entity,
token.Placement,
activationId,
token.LocalPlayerServerGuid,
token.LocalPlayerIdentityRevision,
checked(token.PhysicsOwnershipEpoch + 1UL),
token.ObjectClockEpoch,
expectedControllerEpoch,
token.SessionGenerationAuthority),
Record = record,
PlacementCommand = command,
Controller = controller,
Body = body,
PhysicsHost = physicsHost,
Movement = movement,
Motion = motion,
ActivationPreparation = preparedActivation,
};
_candidate = new Candidate
{
Token = token,
@ -211,10 +345,27 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
PlacementCommand = command,
Controller = controller,
Body = body,
PhysicsHost = physicsHost,
Movement = movement,
Motion = motion,
ActivationPreparation = preparedActivation,
PreparedActivation = activationEnvelope,
};
return RuntimeLocalPlayerPhysicsPublicationStatus.Prepared;
}
private static float NormalizeFriction(float? value) =>
value is >= 0f and <= 1f && float.IsFinite(value.Value)
? value.Value
: PhysicsBody.DefaultFriction;
private static float NormalizeElasticity(float value)
{
if (float.IsNaN(value) || value <= 0f)
return 0f;
return MathF.Min(value, 0.1f);
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Commit(
in RuntimeLocalPlayerPhysicsPublicationToken token) =>
Commit(token, out _);
@ -245,24 +396,8 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
candidate.Record.ObjectClock);
candidate.Record.SetPhysicsBody(candidate.Body);
_movement.CommitRuntimeOwnedController(candidate.Controller);
activationToken = new RuntimeLocalPlayerPhysicsActivationToken(
candidate.Token.Entity,
candidate.Token.Placement,
checked(++_nextActivationId),
candidate.Token.LocalPlayerServerGuid,
candidate.Token.LocalPlayerIdentityRevision,
candidate.Record.PhysicsOwnershipEpoch,
candidate.Record.ObjectClockEpoch,
_movement.ControllerOwnershipEpoch,
_entities.SessionLifetimeVersion);
_activation = new Activation
{
Token = activationToken,
Record = candidate.Record,
PlacementCommand = candidate.PlacementCommand,
Controller = candidate.Controller,
Body = candidate.Body,
};
activationToken = candidate.PreparedActivation.Token;
_activation = candidate.PreparedActivation;
_candidate = null;
return RuntimeLocalPlayerPhysicsPublicationStatus.Committed;
}
@ -291,6 +426,16 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
activation.PlacementCommand,
out RuntimeDormantSetPositionEvaluation placement))
{
if (ReferenceEquals(_activation, activation)
&& IsActivationCurrent(activation)
&& _physics.SetPosition.IsDormantLocalActivationAwaitingCell(
activation.Record,
activation.Body,
token.Placement,
activation.PlacementCommand))
{
return RuntimeLocalPlayerPhysicsActivationStatus.DeferredCell;
}
if (ReferenceEquals(_activation, activation)
&& !IsActivationCurrent(activation))
{
@ -329,6 +474,304 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
receipt.Placement);
}
internal RuntimeDormantSetPositionCommitStatus CommitActivation(
in RuntimeLocalPlayerPhysicsActivationReceipt receipt,
out RuntimePlacementProjectionToken projection)
{
ObjectDisposedException.ThrowIf(_disposed, this);
projection = default;
if (!receipt.IsValid
|| _activation is not { } activation
|| activation.Token != receipt.Token
|| activation.Receipt != receipt)
{
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (activation.PendingFinalCommit.Status
is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation)
{
return FinalizeActivation(
activation,
activation.PendingFinalCommit,
out projection);
}
if (!IsActivationCurrent(activation)
|| !_physics.SetPosition.IsDormantLocalEvaluationCurrent(
activation.Record,
activation.Body,
receipt.Placement))
{
activation.Receipt = default;
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
bool provenShapeless = activation.ActivationPreparation
.ShadowDisposition
is RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
if (!_physics.SetPosition.TryPrepareDormantLocalActivationCommit(
activation.Record,
activation.Body,
receipt.Placement,
provenShapeless,
out PreparedDormantSetPositionCommit? prepared)
|| prepared is null
|| !IsActivationCurrent(activation))
{
activation.Receipt = default;
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryApplyDormantLocalActivationCommit(
activation.Record,
activation.Body,
activation.Controller,
activation.PhysicsHost,
prepared,
out RuntimeDormantSetPositionCommitReceipt committed))
{
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus.DeferredCell)
{
activation.Receipt = default;
_physics.SetPosition.DispatchDormantLocalActivationShadow(committed);
return committed.Status;
}
// Named retail SetPosition: contact prefix, ground edge, second
// acceleration/sliding, collision callbacks, physical response, then
// shadow/live publication.
try
{
activation.Controller.BeginDormantSetPositionGroundPhase();
if (committed.HitGround)
activation.Movement.HitGround();
else if (committed.LeaveGround)
activation.Motion.LeaveGround();
}
catch
{
_activationDispatchFailureCount++;
}
finally
{
activation.Controller.EndDormantSetPositionGroundPhase();
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& (!IsActivationPrephaseEnvelopeCurrent(activation, committed)
|| !RefreshDormantVector(activation, committed)
|| !RefreshDormantState(activation)
|| !_physics.SetPosition.CommitDormantLocalActivationPostGround(
activation.Record,
activation.Body,
committed)))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: false);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
try
{
SetPositionCollisionBatchDispatchResult collisionDispatch =
_physics.SetPosition.DispatchDormantLocalActivationCollision(
committed);
if (collisionDispatch.Status
is not SetPositionCollisionBatchDispatchStatus.Completed)
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
}
catch
{
_activationDispatchFailureCount++;
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!IsActivationResponseEnvelopeCurrent(activation, committed))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
_ = RefreshDormantVector(activation, committed);
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& !IsActivationPrephaseEnvelopeCurrent(activation, committed)
|| !_physics.SetPosition.CommitDormantLocalActivationPostCollision(
activation.Record,
activation.Body,
committed))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.RejectedPlacement)
{
activation.Receipt = default;
activation.PendingFinalCommit = committed;
return committed.Status;
}
activation.PendingFinalCommit = committed;
return FinalizeActivation(activation, committed, out projection);
}
private RuntimeDormantSetPositionCommitStatus FinalizeActivation(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt prephase,
out RuntimePlacementProjectionToken projection)
{
projection = default;
if (!IsActivationPrephaseEnvelopeCurrent(activation, prephase))
{
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
bool provenShapeless = activation.ActivationPreparation
.ShadowDisposition is RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
if (!_physics.SetPosition.TryPrepareDormantLocalActivationFinalCommit(
activation.Record,
activation.Body,
prephase,
provenShapeless,
out PreparedDormantActivationFinalCommit? prepared)
|| prepared is null)
{
if (IsActivationPrephaseEnvelopeCurrent(activation, prephase))
return prephase.Status;
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!IsActivationPrephaseEnvelopeCurrent(activation, prephase))
{
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryApplyDormantLocalActivationFinalCommit(
activation.Record,
activation.Body,
activation.Controller,
activation.PhysicsHost,
prephase,
prepared,
out RuntimeDormantSetPositionCommitReceipt committed))
{
return prephase.Status;
}
activation.Receipt = default;
activation.PendingFinalCommit = default;
_activation = null;
_physics.SetPosition.DispatchDormantLocalActivationShadow(committed);
if (!IsCommittedActivationSuffixCurrent(activation, committed))
return committed.Status;
_physics.SetPosition.DispatchDormantLocalActivationPlacement(committed);
projection = committed.Projection.Token;
return committed.Status;
}
private bool IsActivationPrephaseEnvelopeCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt) =>
IsActivationOwnershipEnvelopeCurrent(activation)
&& _physics.IsCollisionEvaluationFatalAuthorityCurrent(
receipt.CollisionAuthority)
&& _physics.SetPosition.IsDormantLocalActivationPrephaseCurrent(
activation.Record,
activation.Body,
receipt);
private bool IsActivationResponseEnvelopeCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt) =>
IsActivationOwnershipEnvelopeCurrent(activation)
&& _physics.IsCollisionEvaluationFatalAuthorityCurrent(
receipt.CollisionAuthority)
&& _physics.SetPosition.IsDormantLocalActivationResponseCurrent(
activation.Record,
activation.Body,
receipt);
private bool IsActivationOwnershipEnvelopeCurrent(
Activation activation) =>
activation.Controller.IsRuntimeOwnedDormant
&& !activation.Controller.IsDormantSetPositionGroundPhaseActive
&& activation.Controller.OwnsPhysicsBody(activation.Body)
&& _entities.SessionLifetimeVersion
== activation.Token.SessionGenerationAuthority
&& _entities.IsCurrent(activation.Record)
&& activation.Record.Key == activation.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == activation.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == activation.Record.ServerGuid
&& _identity.Revision == activation.Token.LocalPlayerIdentityRevision
&& activation.Record.PhysicsOwnershipEpoch
== activation.Token.PhysicsOwnershipEpoch
&& activation.Record.ObjectClockEpoch
== activation.Token.ObjectClockEpoch
&& _movement.CanCommitRuntimeOwnedController(
activation.Token.ControllerOwnershipEpoch,
activation.Controller)
&& ReferenceEquals(activation.Record.PhysicsBody, activation.Body)
&& activation.Record.PhysicsHost is null
&& activation.Record.RemoteMotion is null
&& activation.Record.Projectile is null
&& !activation.Record.PhysicsBodyAcquisitionInProgress
&& !activation.Record.RemoteMotionBindingInProgress
&& !activation.Record.ProjectileBindingInProgress
&& !activation.Record.RequiresRemotePlacementRuntime
&& !activation.Record.DeleteAcceptedForTeardown;
private static bool RefreshDormantState(Activation activation)
{
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
return true;
}
private static bool RefreshDormantVector(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (activation.Record.VectorAuthorityVersion
== receipt.SourceVectorAuthorityVersion)
return true;
var physics = activation.Record.Snapshot.Physics;
activation.Controller.RefreshDormantRuntimeVector(
physics?.Velocity,
physics?.AngularVelocity);
return true;
}
private void AbortActivation(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt,
bool collisionAlreadyDispatched)
{
_physics.SetPosition.RetireDormantLocalActivation(
receipt,
collisionAlreadyDispatched);
activation.Receipt = default;
activation.PendingFinalCommit = default;
if (ReferenceEquals(_activation, activation))
DiscardActivation();
}
internal bool DiscardActivation(
in RuntimeLocalPlayerPhysicsActivationToken token)
{
@ -389,6 +832,9 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
_activation is null ? 0 : 1,
_nextPublicationId);
internal long ActivationDispatchFailureCount =>
_activationDispatchFailureCount;
internal void ResetSession()
{
ObjectDisposedException.ThrowIf(_disposed, this);
@ -501,15 +947,67 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
&& !activation.Record.ProjectileBindingInProgress
&& !activation.Record.RequiresRemotePlacementRuntime
&& !activation.Record.DeleteAcceptedForTeardown
&& _physics.SetPosition.IsExactPreparedPlacementCurrent(
&& _physics.SetPosition.IsDormantLocalActivationLeaseCurrent(
activation.Record,
activation.Body,
activation.Token.Placement,
activation.PlacementCommand);
private bool IsCommittedActivationSuffixCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
return activation.Token.ObjectClockEpoch != ulong.MaxValue
&& _entities.SessionLifetimeVersion
== activation.Token.SessionGenerationAuthority
&& _entities.IsCurrent(activation.Record)
&& activation.Record.Key == activation.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == activation.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == activation.Record.ServerGuid
&& _identity.Revision
== activation.Token.LocalPlayerIdentityRevision
&& activation.Record.PhysicsOwnershipEpoch
== activation.Token.PhysicsOwnershipEpoch
&& activation.Record.ObjectClockEpoch
== activation.Token.ObjectClockEpoch + 1UL
&& _movement.ControllerOwnershipEpoch
== activation.Token.ControllerOwnershipEpoch
&& ReferenceEquals(_movement.Controller, activation.Controller)
&& activation.Controller.IsRuntimePublished
&& activation.Controller.OwnsPhysicsBody(activation.Body)
&& ReferenceEquals(
activation.Record.PhysicsBody,
activation.Body)
&& ReferenceEquals(
activation.Record.PhysicsHost,
activation.PhysicsHost)
&& activation.Record.RemoteMotion is null
&& activation.Record.Projectile is null
&& !activation.Record.DeleteAcceptedForTeardown
&& _physics.SetPosition.IsDormantLocalActivationCommitCurrent(
activation.Record,
activation.Body,
receipt);
}
private void DiscardActivation()
{
Activation? activation = _activation;
_activation = null;
if (activation is not null)
{
if (activation.PendingFinalCommit.Status
is not RuntimeDormantSetPositionCommitStatus.None)
{
_physics.SetPosition.RetireDormantLocalActivation(
activation.PendingFinalCommit,
collisionAlreadyDispatched: true);
}
_physics.SetPosition.RetireDormantLocalActivationToken(
activation.Record,
activation.Token.Placement);
}
if (activation is not null
&& _entities.IsCurrent(activation.Record)
&& ReferenceEquals(