feat(runtime): seal dormant SetPosition evaluations

This commit is contained in:
Erik 2026-08-01 11:31:58 +02:00
parent 22651c823d
commit 99f867f053
16 changed files with 2298 additions and 62 deletions

View file

@ -704,6 +704,9 @@ public sealed class PlayerMovementController
internal bool IsSealedPublicationCandidate => _publicationLifecycle
is PlayerMovementControllerPublicationLifecycle.CandidateSealed;
internal bool IsRuntimeOwnedDormant => _publicationLifecycle
is PlayerMovementControllerPublicationLifecycle.RuntimeOwnedDormant;
internal void SealPublicationCandidate()
{
if (_publicationLifecycle

View file

@ -14,6 +14,15 @@ internal enum RuntimeLocalPlayerPhysicsPublicationStatus
Discarded,
}
internal enum RuntimeLocalPlayerPhysicsActivationStatus
{
Evaluated,
DeferredCell,
RejectedPlacement,
RejectedAuthority,
RejectedToken,
}
internal readonly record struct RuntimeLocalPlayerPhysicsPublicationToken(
RuntimeEntityKey Entity,
RuntimeEntityPlacementToken Placement,
@ -31,6 +40,33 @@ internal readonly record struct RuntimeLocalPlayerPhysicsPublicationToken(
&& Entity == Placement.Entity;
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationToken(
RuntimeEntityKey Entity,
RuntimeEntityPlacementToken Placement,
ulong ActivationId,
uint LocalPlayerServerGuid,
long LocalPlayerIdentityRevision,
ulong PhysicsOwnershipEpoch,
ulong ObjectClockEpoch,
ulong ControllerOwnershipEpoch,
ulong SessionGenerationAuthority)
{
internal bool IsValid => ActivationId != 0UL
&& LocalPlayerServerGuid != 0u
&& Placement.IsValid
&& Entity == Placement.Entity;
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationReceipt(
RuntimeLocalPlayerPhysicsActivationToken Token,
ulong EvaluationId,
RuntimeDormantSetPositionEvaluation Placement)
{
internal bool IsValid => Token.IsValid
&& EvaluationId != 0UL
&& Placement.Placement == Token.Placement;
}
internal readonly record struct RuntimeLocalPlayerPhysicsCandidateSnapshot(
Vector3 Position,
Quaternion Orientation,
@ -45,10 +81,13 @@ public readonly record struct
bool IsBound,
bool IsDisposed,
int CandidateCount,
int PendingActivationCount,
ulong LastPublicationId)
{
internal bool IsConverged => !IsBound
|| (IsDisposed && CandidateCount == 0);
|| (IsDisposed
&& CandidateCount == 0
&& PendingActivationCount == 0);
}
/// <summary>
@ -74,12 +113,28 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
internal required PhysicsBody Body { get; init; }
}
private sealed class Activation
{
internal required RuntimeLocalPlayerPhysicsActivationToken Token
{ get; init; }
internal required RuntimeEntityRecord Record { get; init; }
internal required RuntimeSetPositionCommand PlacementCommand
{ get; init; }
internal required PlayerMovementController Controller { get; init; }
internal required PhysicsBody Body { get; init; }
internal RuntimeLocalPlayerPhysicsActivationReceipt Receipt
{ get; set; }
}
private readonly RuntimeEntityDirectory _entities;
private readonly RuntimePhysicsState _physics;
private readonly RuntimeLocalPlayerMovementState _movement;
private readonly RuntimeLocalPlayerIdentityState _identity;
private Candidate? _candidate;
private Activation? _activation;
private ulong _nextPublicationId;
private ulong _nextActivationId;
private ulong _nextEvaluationId;
private bool _disposed;
internal RuntimeLocalPlayerPhysicsPublicationState(
@ -161,9 +216,15 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Commit(
in RuntimeLocalPlayerPhysicsPublicationToken token)
in RuntimeLocalPlayerPhysicsPublicationToken token) =>
Commit(token, out _);
internal RuntimeLocalPlayerPhysicsPublicationStatus Commit(
in RuntimeLocalPlayerPhysicsPublicationToken token,
out RuntimeLocalPlayerPhysicsActivationToken activationToken)
{
ObjectDisposedException.ThrowIf(_disposed, this);
activationToken = default;
if (!token.IsValid
|| _candidate is not { } candidate
|| candidate.Token != token)
@ -184,10 +245,104 @@ 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,
};
_candidate = null;
return RuntimeLocalPlayerPhysicsPublicationStatus.Committed;
}
internal RuntimeLocalPlayerPhysicsActivationStatus EvaluateActivation(
in RuntimeLocalPlayerPhysicsActivationToken token,
out RuntimeLocalPlayerPhysicsActivationReceipt receipt)
{
ObjectDisposedException.ThrowIf(_disposed, this);
receipt = default;
if (!token.IsValid
|| _activation is not { } activation
|| activation.Token != token)
{
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedToken;
}
if (!IsActivationCurrent(activation))
{
DiscardActivation();
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryEvaluateDormantLocalActivation(
activation.Record,
activation.Body,
token.Placement,
activation.PlacementCommand,
out RuntimeDormantSetPositionEvaluation placement))
{
if (ReferenceEquals(_activation, activation)
&& !IsActivationCurrent(activation))
{
DiscardActivation();
}
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedAuthority;
}
receipt = new RuntimeLocalPlayerPhysicsActivationReceipt(
token,
checked(++_nextEvaluationId),
placement);
activation.Receipt = receipt;
if (placement.Result.IsDeferred)
return RuntimeLocalPlayerPhysicsActivationStatus.DeferredCell;
return placement.Result.IsCommitted
? RuntimeLocalPlayerPhysicsActivationStatus.Evaluated
: RuntimeLocalPlayerPhysicsActivationStatus.RejectedPlacement;
}
internal bool IsEvaluationCurrent(
in RuntimeLocalPlayerPhysicsActivationReceipt receipt)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!receipt.IsValid
|| _activation is not { } activation
|| activation.Token != receipt.Token
|| activation.Receipt != receipt)
{
return false;
}
return IsActivationCurrent(activation)
&& _physics.SetPosition.IsDormantLocalEvaluationCurrent(
activation.Record,
activation.Body,
receipt.Placement);
}
internal bool DiscardActivation(
in RuntimeLocalPlayerPhysicsActivationToken token)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!token.IsValid
|| _activation is not { } activation
|| activation.Token != token)
{
return false;
}
DiscardActivation();
return true;
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Discard(
in RuntimeLocalPlayerPhysicsPublicationToken token)
{
@ -231,12 +386,14 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
IsBound: true,
_disposed,
_candidate is null ? 0 : 1,
_activation is null ? 0 : 1,
_nextPublicationId);
internal void ResetSession()
{
ObjectDisposedException.ThrowIf(_disposed, this);
DiscardCurrent();
DiscardActivation();
}
public void Dispose()
@ -244,6 +401,7 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
if (_disposed)
return;
DiscardCurrent();
DiscardActivation();
_disposed = true;
}
@ -251,7 +409,8 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken placement,
in RuntimeSetPositionCommand command) =>
record.Key is { } key
_activation is null
&& record.Key is { } key
&& key == placement.Entity
&& _entities.IsCurrent(record)
&& !record.DeleteAcceptedForTeardown
@ -276,7 +435,8 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
command);
private bool IsCurrent(Candidate candidate) =>
candidate.Controller.IsSealedPublicationCandidate
_activation is null
&& candidate.Controller.IsSealedPublicationCandidate
&& candidate.Controller.OwnsPhysicsBody(candidate.Body)
&& _entities.SessionLifetimeVersion
== candidate.Token.SessionGenerationAuthority
@ -313,4 +473,55 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
_candidate = null;
candidate?.Controller.DiscardRuntimeCandidate();
}
private bool IsActivationCurrent(Activation activation) =>
activation.Controller.IsRuntimeOwnedDormant
&& 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
&& _physics.SetPosition.IsExactPreparedPlacementCurrent(
activation.Record,
activation.Token.Placement,
activation.PlacementCommand);
private void DiscardActivation()
{
Activation? activation = _activation;
_activation = null;
if (activation is not null
&& _entities.IsCurrent(activation.Record)
&& ReferenceEquals(
activation.Record.PhysicsBody,
activation.Body))
{
_entities.SetPhysicsBody(activation.Record, null);
}
if (activation is not null
&& ReferenceEquals(_movement.Controller, activation.Controller))
{
_movement.Controller = null;
}
}
}