feat(runtime): seal dormant SetPosition evaluations
This commit is contained in:
parent
22651c823d
commit
99f867f053
16 changed files with 2298 additions and 62 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
|
@ -82,6 +83,32 @@ internal readonly record struct RuntimeSetPositionCommand(
|
|||
float ShadowWorldOffsetY = 0f,
|
||||
RuntimePortalPlacementAuthority Portal = default);
|
||||
|
||||
internal readonly record struct RuntimeCollisionGenerationAuthority(
|
||||
uint LandblockId,
|
||||
ulong Generation);
|
||||
|
||||
internal readonly record struct RuntimeCollisionEvaluationAuthority(
|
||||
ulong CollisionWorldAuthority,
|
||||
ulong ShadowWorldAuthority,
|
||||
ClientObjectTable? ObjectTable,
|
||||
ulong ObjectTableBindingAuthority,
|
||||
ulong ObjectTableAuthority,
|
||||
ImmutableArray<RuntimeCollisionGenerationAuthority> Generations)
|
||||
{
|
||||
internal bool IsValid => CollisionWorldAuthority != 0UL
|
||||
&& !Generations.IsDefault;
|
||||
}
|
||||
|
||||
internal readonly record struct RuntimeDormantSetPositionEvaluation(
|
||||
RuntimeEntityPlacementToken Placement,
|
||||
RuntimeSetPositionCommand Command,
|
||||
PhysicsSetPositionResult Result,
|
||||
RuntimeCollisionEvaluationAuthority CollisionAuthority)
|
||||
{
|
||||
internal bool IsValid => Placement.IsValid
|
||||
&& CollisionAuthority.IsValid;
|
||||
}
|
||||
|
||||
public readonly record struct RuntimePlacementProjectionToken(
|
||||
ulong Sequence,
|
||||
ulong Revision,
|
||||
|
|
@ -597,6 +624,98 @@ internal sealed class RuntimeSetPositionState : IDisposable
|
|||
&& IsPreparationAuthorityCurrent(operation, authority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the exact authored local-player placement without mutating
|
||||
/// the canonical dormant body or any Runtime ownership index. Core's
|
||||
/// SetPosition transaction is pure; collision reporting is deliberately
|
||||
/// omitted until the later atomic activation commit.
|
||||
/// </summary>
|
||||
internal bool TryEvaluateDormantLocalActivation(
|
||||
RuntimeEntityRecord record,
|
||||
PhysicsBody body,
|
||||
in RuntimeEntityPlacementToken token,
|
||||
in RuntimeSetPositionCommand command,
|
||||
out RuntimeDormantSetPositionEvaluation evaluation)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
ArgumentNullException.ThrowIfNull(body);
|
||||
evaluation = default;
|
||||
if (!IsExactDormantLocalActivationCurrent(
|
||||
record,
|
||||
body,
|
||||
token,
|
||||
command,
|
||||
out Operation? operation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PhysicsSetPositionRequest canonicalRequest = command.Physics with
|
||||
{
|
||||
MoverPhysicsState = record.FinalPhysicsState,
|
||||
MovingEntityId = token.Entity.LocalEntityId,
|
||||
CurrentCellId = null,
|
||||
};
|
||||
if (!IsStructurallyValid(canonicalRequest))
|
||||
return false;
|
||||
|
||||
var canonicalCommand = command with { Physics = canonicalRequest };
|
||||
ulong collisionWorldAuthority = _physics.CollisionWorldAuthority;
|
||||
ulong shadowWorldAuthority = _physics.ShadowWorldAuthority;
|
||||
ClientObjectTable? objectTable = _physics.ObjectTable;
|
||||
ulong objectTableBindingAuthority =
|
||||
_physics.ObjectTableBindingAuthority;
|
||||
ulong objectTableAuthority = objectTable?.MutationRevision ?? 0UL;
|
||||
PhysicsSetPositionResult result = _physics.Engine.SetPosition(
|
||||
canonicalRequest,
|
||||
handleCollisions: null);
|
||||
if (!IsExactDormantLocalActivationCurrent(
|
||||
record,
|
||||
body,
|
||||
token,
|
||||
command,
|
||||
out Operation? current)
|
||||
|| !ReferenceEquals(current, operation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_physics.TrySealCollisionEvaluationAuthority(
|
||||
result,
|
||||
collisionWorldAuthority,
|
||||
shadowWorldAuthority,
|
||||
objectTable,
|
||||
objectTableBindingAuthority,
|
||||
objectTableAuthority,
|
||||
out RuntimeCollisionEvaluationAuthority collisionAuthority))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
evaluation = new RuntimeDormantSetPositionEvaluation(
|
||||
token,
|
||||
canonicalCommand,
|
||||
result,
|
||||
collisionAuthority);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool IsDormantLocalEvaluationCurrent(
|
||||
RuntimeEntityRecord record,
|
||||
PhysicsBody body,
|
||||
in RuntimeDormantSetPositionEvaluation evaluation) =>
|
||||
evaluation.IsValid
|
||||
&& IsExactDormantLocalActivationCurrent(
|
||||
record,
|
||||
body,
|
||||
evaluation.Placement,
|
||||
evaluation.Command,
|
||||
out _,
|
||||
allowCanonicalCommand: true)
|
||||
&& _physics.IsCollisionEvaluationAuthorityCurrent(
|
||||
evaluation.CollisionAuthority);
|
||||
|
||||
internal RuntimeSetPositionOutcome SubmitPreparedPlacement(
|
||||
in RuntimeEntityPlacementToken token,
|
||||
in RuntimeSetPositionCommand command) =>
|
||||
|
|
@ -1881,6 +2000,69 @@ internal sealed class RuntimeSetPositionState : IDisposable
|
|||
&& operation.Record.PlacementCommitVersion
|
||||
== operation.PlacementCommitVersion;
|
||||
|
||||
private bool IsExactDormantLocalActivationCurrent(
|
||||
RuntimeEntityRecord record,
|
||||
PhysicsBody body,
|
||||
in RuntimeEntityPlacementToken token,
|
||||
in RuntimeSetPositionCommand command,
|
||||
out Operation? operation,
|
||||
bool allowCanonicalCommand = false)
|
||||
{
|
||||
operation = null;
|
||||
if (!token.IsValid
|
||||
|| token.Entity != record.Key
|
||||
|| token.PreparationKind
|
||||
is not RuntimeEntityPlacementPreparationKind.AuthoredMover
|
||||
|| command.Kind is not (RuntimeSetPositionOperationKind.InitialLogin
|
||||
or RuntimeSetPositionOperationKind.LocalAuthoritative)
|
||||
|| command.Portal != default
|
||||
&& !command.Portal.IsValid
|
||||
|| !_operations.TryGetValue(token.Entity, out operation)
|
||||
|| operation.Token != token
|
||||
|| operation.Stage
|
||||
is not RuntimeEntityPlacementStage.AwaitingPreparation
|
||||
|| !ReferenceEquals(operation.Record, record)
|
||||
|| !IsCurrent(operation)
|
||||
|| !ReferenceEquals(record.PhysicsBody, body)
|
||||
|| body.InWorld
|
||||
|| (body.TransientState & TransientStateFlags.Active) != 0
|
||||
|| record.PhysicsHost is not null
|
||||
|| record.RemoteMotion is not null
|
||||
|| record.Projectile is not null
|
||||
|| record.PhysicsBodyAcquisitionInProgress
|
||||
|| record.RemoteMotionBindingInProgress
|
||||
|| record.ProjectileBindingInProgress
|
||||
|| record.RequiresRemotePlacementRuntime
|
||||
|| record.DeleteAcceptedForTeardown
|
||||
|| _physics.IsSpatialRoot(record)
|
||||
|| !_moverPreparationAuthorities.TryGetValue(
|
||||
token.Entity,
|
||||
out MoverPreparationAuthority authority)
|
||||
|| authority.OperationId != token.OperationId
|
||||
|| !authority.Prepared
|
||||
|| !IsPreparationAuthorityCurrent(operation, authority))
|
||||
{
|
||||
operation = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (authority.PreparedCommand == command)
|
||||
return true;
|
||||
if (!allowCanonicalCommand)
|
||||
return false;
|
||||
|
||||
RuntimeSetPositionCommand authored = authority.PreparedCommand;
|
||||
return authored with
|
||||
{
|
||||
Physics = authored.Physics with
|
||||
{
|
||||
MoverPhysicsState = record.FinalPhysicsState,
|
||||
MovingEntityId = token.Entity.LocalEntityId,
|
||||
CurrentCellId = null,
|
||||
},
|
||||
} == command;
|
||||
}
|
||||
|
||||
private bool IsVelocityCurrent(Operation operation) =>
|
||||
operation.SourceVelocityAuthorityVersion == 0UL
|
||||
|| operation.Record.VelocityAuthorityVersion
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue