feat(runtime): seal dormant SetPosition evaluations
This commit is contained in:
parent
22651c823d
commit
99f867f053
16 changed files with 2298 additions and 62 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue