feat(runtime): own initial create residence transaction
This commit is contained in:
parent
74103f75b5
commit
38fd4b8dc9
10 changed files with 3031 additions and 17 deletions
|
|
@ -0,0 +1,743 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Runtime.Physics;
|
||||
|
||||
namespace AcDream.Runtime.Entities;
|
||||
|
||||
internal readonly record struct RuntimeInitialCreateResidenceToken(
|
||||
RuntimeEntityKey Entity,
|
||||
ulong LeaseId,
|
||||
ulong SessionLifetimeVersion,
|
||||
ulong PositionAuthorityVersion,
|
||||
ulong CreateIntegrationVersion,
|
||||
ulong SourcePlacementCommitVersion)
|
||||
{
|
||||
internal bool IsValid => Entity.LocalEntityId != 0u
|
||||
&& LeaseId != 0UL
|
||||
&& PositionAuthorityVersion != 0UL
|
||||
&& CreateIntegrationVersion != 0UL;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exact, presentation-free initial CreateObject residence authority. The
|
||||
/// accepted wire frame remains on the canonical record while FullCell stays
|
||||
/// zero until the authored Runtime SetPosition operation commits.
|
||||
/// </summary>
|
||||
internal readonly record struct RuntimeInitialCreateResidenceLease(
|
||||
RuntimeInitialCreateResidenceToken Token,
|
||||
RuntimeAuthoritativePositionRoute Route,
|
||||
RuntimeEntityPlacementToken Placement,
|
||||
ImmutableArray<RuntimeInitialCreateResidenceContinuation> Continuations)
|
||||
{
|
||||
internal bool IsValid => Token.IsValid
|
||||
&& Route.Accepted
|
||||
&& Route.Authority.Entity == Token.Entity
|
||||
&& !Continuations.IsDefault
|
||||
&& HasValidContinuationChain()
|
||||
&& (!Route.PerformsSetPosition
|
||||
|| Placement.IsValid
|
||||
&& Placement.Entity == Token.Entity);
|
||||
|
||||
private bool HasValidContinuationChain()
|
||||
{
|
||||
ushort previousTeleport = Route.Authority.AcceptedTeleportSequence;
|
||||
for (int index = 0; index < Continuations.Length; index++)
|
||||
{
|
||||
RuntimeInitialCreateResidenceContinuation continuation =
|
||||
Continuations[index];
|
||||
if (!continuation.IsValid
|
||||
|| continuation.Sequence != (ulong)index + 1UL
|
||||
|| continuation.InstanceSequence != Token.Entity.Incarnation
|
||||
|| continuation.PositionAuthorityVersion
|
||||
!= Token.PositionAuthorityVersion
|
||||
|| continuation.PreviousTeleportSequence
|
||||
!= previousTeleport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
previousTeleport = continuation.AcceptedTeleportSequence;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One accepted Position packet which arrived before the immutable initial
|
||||
/// CreateObject admission completed. These records remain dormant until a
|
||||
/// host adopts the completed batch; accepting them never replaces or mutates
|
||||
/// the initial 0x11 SetPosition operation.
|
||||
/// </summary>
|
||||
internal readonly record struct RuntimeInitialCreateResidenceContinuation(
|
||||
ulong Sequence,
|
||||
RuntimePositionEntityKind EntityKind,
|
||||
ushort InstanceSequence,
|
||||
ushort PositionSequence,
|
||||
ushort PreviousTeleportSequence,
|
||||
ushort TeleportSequence,
|
||||
ushort ForcePositionSequence,
|
||||
ushort AcceptedTeleportSequence,
|
||||
ushort AcceptedForcePositionSequence,
|
||||
PositionTimestampDisposition TimestampDisposition,
|
||||
CreateObject.ServerPosition AcceptedWirePosition,
|
||||
Vector3? PositionPackVelocity,
|
||||
Vector3? AcceptedVelocity,
|
||||
Quaternion? ForcePositionRotation,
|
||||
Vector3? CurrentLocalVelocity,
|
||||
bool ProjectionRequiresTeleportHook,
|
||||
uint PlacementFrame,
|
||||
ulong PositionAuthorityVersion)
|
||||
{
|
||||
internal bool IsValid => Sequence != 0UL
|
||||
&& EntityKind is RuntimePositionEntityKind.LocalPlayer
|
||||
or RuntimePositionEntityKind.Remote
|
||||
or RuntimePositionEntityKind.Projectile
|
||||
&& PositionAuthorityVersion != 0UL
|
||||
&& TimestampDisposition is PositionTimestampDisposition.Apply
|
||||
or PositionTimestampDisposition.ForcePosition;
|
||||
}
|
||||
|
||||
internal readonly record struct RuntimeInitialCreateResidenceAdoptionToken(
|
||||
RuntimeEntityKey Entity,
|
||||
ulong LeaseId,
|
||||
ulong AdoptionId,
|
||||
ulong SessionLifetimeVersion,
|
||||
ulong Revision)
|
||||
{
|
||||
internal bool IsValid => Entity.LocalEntityId != 0u
|
||||
&& LeaseId != 0UL
|
||||
&& AdoptionId != 0UL
|
||||
&& Revision != 0UL;
|
||||
}
|
||||
|
||||
internal enum RuntimeInitialCreateResidenceCompletionStatus : byte
|
||||
{
|
||||
Completed,
|
||||
PendingPlacement,
|
||||
RejectedToken,
|
||||
RejectedAuthority,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exact post-residence receipt. A local graphical or no-window host may run
|
||||
/// the retail after-enter teleport suffix only when this receipt carries
|
||||
/// <see cref="RuntimeTeleportHookPhase.AfterEnterWorld"/>.
|
||||
/// </summary>
|
||||
internal readonly record struct RuntimeInitialCreateResidenceReceipt(
|
||||
RuntimeInitialCreateResidenceToken Token,
|
||||
RuntimeTeleportHookPhase TeleportHookPhase,
|
||||
RuntimePlacementProjectionToken Projection,
|
||||
uint FullCellId,
|
||||
ulong PlacementCommitVersion,
|
||||
RuntimeInitialCreateResidenceAdoptionToken Adoption,
|
||||
ImmutableArray<RuntimeInitialCreateResidenceContinuation> Continuations);
|
||||
|
||||
internal readonly record struct RuntimeInitialCreateResidenceOwnershipSnapshot(
|
||||
int ActiveLeaseCount,
|
||||
int PendingAdoptionCount,
|
||||
ulong LastLeaseId)
|
||||
{
|
||||
internal bool IsConverged => ActiveLeaseCount == 0
|
||||
&& PendingAdoptionCount == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Owns only initial CreateObject residence leases. DAT lookup, body creation,
|
||||
/// and presentation stay outside this owner; their immutable preparation is
|
||||
/// submitted through the lease's canonical Runtime SetPosition token.
|
||||
/// </summary>
|
||||
internal sealed class RuntimeInitialCreateResidenceState
|
||||
{
|
||||
private sealed class Entry
|
||||
{
|
||||
internal required RuntimeEntityRecord Record { get; init; }
|
||||
internal required RuntimeInitialCreateResidenceLease Lease { get; set; }
|
||||
}
|
||||
|
||||
private sealed class CompletedEntry
|
||||
{
|
||||
internal required RuntimeEntityRecord Record { get; init; }
|
||||
internal required RuntimeInitialCreateResidenceLease Lease { get; set; }
|
||||
internal required RuntimeInitialCreateResidenceReceipt Receipt { get; set; }
|
||||
}
|
||||
|
||||
private readonly RuntimeEntityDirectory _entities;
|
||||
private readonly RuntimeSetPositionState _setPosition;
|
||||
private readonly Dictionary<RuntimeEntityKey, Entry> _entries = [];
|
||||
private readonly Dictionary<RuntimeEntityKey, CompletedEntry> _completed = [];
|
||||
private Func<RuntimeGenerationToken>? _generation;
|
||||
private ulong _nextLeaseId;
|
||||
|
||||
internal RuntimeInitialCreateResidenceState(
|
||||
RuntimeEntityDirectory entities,
|
||||
RuntimeSetPositionState setPosition)
|
||||
{
|
||||
_entities = entities ?? throw new ArgumentNullException(nameof(entities));
|
||||
_setPosition = setPosition
|
||||
?? throw new ArgumentNullException(nameof(setPosition));
|
||||
}
|
||||
|
||||
internal void BindGeneration(Func<RuntimeGenerationToken> generation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generation);
|
||||
if (_generation is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The initial Create residence generation source is already bound.");
|
||||
}
|
||||
_generation = generation;
|
||||
}
|
||||
|
||||
internal bool CanAcceptCreate(WorldSession.EntitySpawn incoming)
|
||||
{
|
||||
bool parented = (incoming.ParentGuid
|
||||
?? incoming.Physics?.Parent?.Guid)
|
||||
is not null and not 0u;
|
||||
bool topLevel = !parented
|
||||
&& incoming.Position is { LandblockId: not 0u };
|
||||
return CurrentGeneration().Value != 0UL
|
||||
&& _nextLeaseId != ulong.MaxValue
|
||||
&& (!topLevel
|
||||
|| _setPosition.CanBeginAuthoredPlacementSequence
|
||||
&& RuntimeAuthoritativePositionRouteClassifier
|
||||
.IsValidCreateWirePosition(
|
||||
incoming.Position!.Value));
|
||||
}
|
||||
|
||||
internal RuntimeInitialCreateResidenceLease Begin(
|
||||
RuntimeEntityRecord record,
|
||||
in InboundCreateResult accepted,
|
||||
bool isLocalPlayer)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (!_entities.IsCurrent(record)
|
||||
|| record.Key is not { } key
|
||||
|| record.FullCellId != 0u
|
||||
|| accepted.Snapshot.Guid != record.ServerGuid
|
||||
|| accepted.Snapshot.InstanceSequence != record.Incarnation)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
RuntimeGenerationToken generation = CurrentGeneration();
|
||||
RuntimePositionEntityKind entityKind = isLocalPlayer
|
||||
? RuntimePositionEntityKind.LocalPlayer
|
||||
: (record.FinalPhysicsState & PhysicsStateFlags.Missile) != 0
|
||||
? RuntimePositionEntityKind.Projectile
|
||||
: RuntimePositionEntityKind.Remote;
|
||||
WorldSession.EntitySpawn snapshot = accepted.Snapshot;
|
||||
// PhysicsDesc parent ownership precedes its optional position frame in
|
||||
// retail set_description. A parented Create is not a top-level world
|
||||
// admission merely because ACE also supplied a position payload.
|
||||
RuntimeCreateResidenceKind residence =
|
||||
(snapshot.ParentGuid ?? snapshot.Physics?.Parent?.Guid)
|
||||
is not null and not 0u
|
||||
? RuntimeCreateResidenceKind.Parented
|
||||
: snapshot.Position is { LandblockId: not 0u }
|
||||
? RuntimeCreateResidenceKind.TopLevel
|
||||
: RuntimeCreateResidenceKind.PickedUp;
|
||||
var authority = new RuntimeAuthoritativePositionAuthority(
|
||||
generation,
|
||||
key,
|
||||
record.PositionAuthorityVersion,
|
||||
snapshot.PositionSequence,
|
||||
accepted.Timestamps.Teleport,
|
||||
accepted.Timestamps.Teleport,
|
||||
PositionTimestampDisposition.Apply);
|
||||
RuntimeAuthoritativePositionRoute route =
|
||||
RuntimeAuthoritativePositionRouteClassifier.ClassifyCreate(
|
||||
new RuntimeCreatePositionRouteRequest(
|
||||
authority,
|
||||
entityKind,
|
||||
residence,
|
||||
snapshot.Position,
|
||||
new RuntimePositionPlacementFacts(
|
||||
record.FinalPhysicsState,
|
||||
HasAuthoredMoverShape: snapshot.SetupTableId is not null)));
|
||||
return Own(record, route);
|
||||
}
|
||||
|
||||
internal RuntimeInitialCreateResidenceLease EnqueueAcceptedPosition(
|
||||
RuntimeEntityRecord record,
|
||||
in RuntimeInitialCreateResidenceLease prior,
|
||||
WorldSession.EntityPositionUpdate update,
|
||||
in WorldSession.EntitySpawn accepted,
|
||||
PositionTimestampDisposition disposition,
|
||||
in AcceptedPhysicsTimestamps timestamps,
|
||||
bool isLocalPlayer,
|
||||
Quaternion? forcePositionRotation,
|
||||
Vector3? currentLocalVelocity,
|
||||
bool projectionRequiresTeleportHook)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (!_entities.IsCurrent(record)
|
||||
|| record.Key is not { } key
|
||||
|| update.Guid != record.ServerGuid
|
||||
|| accepted.Guid != record.ServerGuid
|
||||
|| disposition is PositionTimestampDisposition.Rejected)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
RuntimeInitialCreateResidenceLease current;
|
||||
Entry? active = null;
|
||||
CompletedEntry? completed = null;
|
||||
if (_entries.TryGetValue(key, out active)
|
||||
&& ReferenceEquals(active.Record, record)
|
||||
&& active.Lease.Token == prior.Token
|
||||
&& IsCurrent(active))
|
||||
{
|
||||
current = active.Lease;
|
||||
}
|
||||
else if (_completed.TryGetValue(key, out completed)
|
||||
&& ReferenceEquals(completed.Record, record)
|
||||
&& completed.Lease.Token == prior.Token
|
||||
&& IsCompletedCurrent(completed))
|
||||
{
|
||||
current = completed.Lease;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default;
|
||||
}
|
||||
if (current.Continuations.Length == int.MaxValue
|
||||
|| completed is not null
|
||||
&& completed.Receipt.Adoption.Revision == ulong.MaxValue)
|
||||
return default;
|
||||
|
||||
RuntimePositionEntityKind entityKind = isLocalPlayer
|
||||
? RuntimePositionEntityKind.LocalPlayer
|
||||
: (record.FinalPhysicsState & PhysicsStateFlags.Missile) != 0
|
||||
? RuntimePositionEntityKind.Projectile
|
||||
: RuntimePositionEntityKind.Remote;
|
||||
CreateObject.ServerPosition acceptedPosition =
|
||||
accepted.Position ?? update.Position;
|
||||
ushort previousTeleport = current.Continuations.IsEmpty
|
||||
? current.Route.Authority.AcceptedTeleportSequence
|
||||
: current.Continuations[^1].AcceptedTeleportSequence;
|
||||
ulong sequence = (ulong)current.Continuations.Length + 1UL;
|
||||
var continuation = new RuntimeInitialCreateResidenceContinuation(
|
||||
sequence,
|
||||
entityKind,
|
||||
update.InstanceSequence,
|
||||
update.PositionSequence,
|
||||
previousTeleport,
|
||||
update.TeleportSequence,
|
||||
update.ForcePositionSequence,
|
||||
timestamps.Teleport,
|
||||
timestamps.ForcePosition,
|
||||
disposition,
|
||||
acceptedPosition,
|
||||
update.Velocity,
|
||||
accepted.Physics?.Velocity,
|
||||
forcePositionRotation,
|
||||
currentLocalVelocity,
|
||||
projectionRequiresTeleportHook,
|
||||
accepted.PlacementId ?? 0u,
|
||||
record.PositionAuthorityVersion);
|
||||
if (!continuation.IsValid)
|
||||
return default;
|
||||
|
||||
RuntimeInitialCreateResidenceLease revised = current with
|
||||
{
|
||||
Continuations = current.Continuations.Add(continuation),
|
||||
};
|
||||
if (active is not null)
|
||||
{
|
||||
active.Lease = revised;
|
||||
}
|
||||
else
|
||||
{
|
||||
completed!.Lease = revised;
|
||||
RuntimeInitialCreateResidenceAdoptionToken revisedAdoption =
|
||||
completed.Receipt.Adoption with
|
||||
{
|
||||
Revision = completed.Receipt.Adoption.Revision + 1UL,
|
||||
};
|
||||
completed.Receipt = completed.Receipt with
|
||||
{
|
||||
Adoption = revisedAdoption,
|
||||
Continuations = revised.Continuations,
|
||||
};
|
||||
}
|
||||
return revised;
|
||||
}
|
||||
|
||||
internal bool CanEnqueueAcceptedPosition(
|
||||
RuntimeEntityRecord record,
|
||||
in RuntimeInitialCreateResidenceLease prior,
|
||||
in WorldSession.EntityPositionUpdate update)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (record.Key is not { } key
|
||||
|| update.Guid != record.ServerGuid
|
||||
|| !RuntimeAuthoritativePositionRouteClassifier
|
||||
.IsValidCreateWirePosition(update.Position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_entries.TryGetValue(key, out Entry? entry))
|
||||
{
|
||||
return ReferenceEquals(entry.Record, record)
|
||||
&& entry.Lease.Token == prior.Token
|
||||
&& IsCurrent(entry)
|
||||
&& entry.Lease.Continuations.Length < int.MaxValue;
|
||||
}
|
||||
return _completed.TryGetValue(key, out CompletedEntry? completed)
|
||||
&& ReferenceEquals(completed.Record, record)
|
||||
&& completed.Lease.Token == prior.Token
|
||||
&& IsCompletedCurrent(completed)
|
||||
&& completed.Lease.Continuations.Length < int.MaxValue
|
||||
&& completed.Receipt.Adoption.Revision < ulong.MaxValue;
|
||||
}
|
||||
|
||||
internal bool TryGetTransaction(
|
||||
RuntimeEntityRecord record,
|
||||
out RuntimeInitialCreateResidenceLease lease)
|
||||
{
|
||||
if (TryGetCurrent(record, out lease))
|
||||
return true;
|
||||
if (record.Key is { } key
|
||||
&& _completed.TryGetValue(key, out CompletedEntry? completed)
|
||||
&& ReferenceEquals(completed.Record, record))
|
||||
{
|
||||
if (IsCompletedCurrent(completed))
|
||||
{
|
||||
lease = completed.Lease;
|
||||
return true;
|
||||
}
|
||||
Retire(completed);
|
||||
}
|
||||
lease = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private RuntimeInitialCreateResidenceLease Own(
|
||||
RuntimeEntityRecord record,
|
||||
in RuntimeAuthoritativePositionRoute route)
|
||||
{
|
||||
RuntimeEntityKey key = record.Key!.Value;
|
||||
if (_entries.ContainsKey(key)
|
||||
|| _nextLeaseId == ulong.MaxValue)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
ulong leaseId = _nextLeaseId + 1UL;
|
||||
|
||||
RuntimeEntityPlacementToken placement = default;
|
||||
if (route.PerformsSetPosition)
|
||||
{
|
||||
placement = _setPosition.TryBeginExclusiveAuthoredPlacement(
|
||||
record,
|
||||
record.PositionAuthorityVersion,
|
||||
route.OperationKind);
|
||||
if (!placement.IsValid)
|
||||
return default;
|
||||
if (!_setPosition.WatchPlacementCompletion(placement))
|
||||
{
|
||||
_ = _setPosition.ForgetExactPlacement(placement);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
else if (!route.Accepted)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var token = new RuntimeInitialCreateResidenceToken(
|
||||
key,
|
||||
leaseId,
|
||||
_entities.SessionLifetimeVersion,
|
||||
record.PositionAuthorityVersion,
|
||||
record.CreateIntegrationVersion,
|
||||
record.PlacementCommitVersion);
|
||||
var lease = new RuntimeInitialCreateResidenceLease(
|
||||
token,
|
||||
route,
|
||||
placement,
|
||||
ImmutableArray<RuntimeInitialCreateResidenceContinuation>.Empty);
|
||||
_entries.Add(key, new Entry
|
||||
{
|
||||
Record = record,
|
||||
Lease = lease,
|
||||
});
|
||||
_nextLeaseId = leaseId;
|
||||
return lease;
|
||||
}
|
||||
|
||||
internal bool TryGetCurrent(
|
||||
RuntimeEntityRecord record,
|
||||
out RuntimeInitialCreateResidenceLease lease)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (record.Key is { } key
|
||||
&& _entries.TryGetValue(key, out Entry? entry)
|
||||
&& ReferenceEquals(entry.Record, record))
|
||||
{
|
||||
if (IsCurrent(entry))
|
||||
{
|
||||
lease = entry.Lease;
|
||||
return true;
|
||||
}
|
||||
Retire(entry);
|
||||
}
|
||||
lease = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal RuntimeInitialCreateResidenceCompletionStatus Complete(
|
||||
RuntimeEntityRecord record,
|
||||
in RuntimeInitialCreateResidenceToken token,
|
||||
out RuntimeInitialCreateResidenceReceipt receipt)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
receipt = default;
|
||||
if (token.IsValid
|
||||
&& _completed.TryGetValue(token.Entity, out CompletedEntry? completed)
|
||||
&& completed.Receipt.Token == token
|
||||
&& ReferenceEquals(completed.Record, record))
|
||||
{
|
||||
if (IsCompletedCurrent(completed))
|
||||
{
|
||||
receipt = completed.Receipt;
|
||||
return RuntimeInitialCreateResidenceCompletionStatus.Completed;
|
||||
}
|
||||
Retire(completed);
|
||||
return RuntimeInitialCreateResidenceCompletionStatus
|
||||
.RejectedAuthority;
|
||||
}
|
||||
if (!token.IsValid
|
||||
|| !_entries.TryGetValue(token.Entity, out Entry? entry)
|
||||
|| entry.Lease.Token != token
|
||||
|| !ReferenceEquals(entry.Record, record))
|
||||
{
|
||||
return RuntimeInitialCreateResidenceCompletionStatus.RejectedToken;
|
||||
}
|
||||
if (!IsCurrent(entry))
|
||||
{
|
||||
Retire(entry);
|
||||
return RuntimeInitialCreateResidenceCompletionStatus
|
||||
.RejectedAuthority;
|
||||
}
|
||||
|
||||
RuntimeInitialCreateResidenceLease lease = entry.Lease;
|
||||
RuntimePlacementProjectionToken projection = default;
|
||||
if (lease.Route.PerformsSetPosition)
|
||||
{
|
||||
if (_setPosition.IsPlacementCurrent(lease.Placement))
|
||||
{
|
||||
return RuntimeInitialCreateResidenceCompletionStatus
|
||||
.PendingPlacement;
|
||||
}
|
||||
if (!_setPosition.TryPeekAcknowledgedPlacement(
|
||||
lease.Placement,
|
||||
out projection)
|
||||
|| projection.Entity != token.Entity
|
||||
|| projection.PositionAuthorityVersion
|
||||
!= token.PositionAuthorityVersion
|
||||
|| projection.SessionLifetimeVersion
|
||||
!= token.SessionLifetimeVersion
|
||||
|| projection.ExactCellId == 0u
|
||||
|| projection.ExactCellId != record.FullCellId
|
||||
|| projection.PlacementCommitVersion
|
||||
<= token.SourcePlacementCommitVersion
|
||||
|| projection.PlacementCommitVersion
|
||||
!= record.PlacementCommitVersion)
|
||||
{
|
||||
Retire(entry);
|
||||
return RuntimeInitialCreateResidenceCompletionStatus
|
||||
.RejectedAuthority;
|
||||
}
|
||||
}
|
||||
else if (record.FullCellId != 0u)
|
||||
{
|
||||
Retire(entry);
|
||||
return RuntimeInitialCreateResidenceCompletionStatus
|
||||
.RejectedAuthority;
|
||||
}
|
||||
|
||||
var adoption = new RuntimeInitialCreateResidenceAdoptionToken(
|
||||
token.Entity,
|
||||
token.LeaseId,
|
||||
token.LeaseId,
|
||||
token.SessionLifetimeVersion,
|
||||
Revision: 1UL);
|
||||
receipt = new RuntimeInitialCreateResidenceReceipt(
|
||||
token,
|
||||
lease.Route.TeleportHookPhase,
|
||||
projection,
|
||||
record.FullCellId,
|
||||
record.PlacementCommitVersion,
|
||||
adoption,
|
||||
lease.Continuations);
|
||||
_entries.Remove(token.Entity);
|
||||
_completed.Add(token.Entity, new CompletedEntry
|
||||
{
|
||||
Record = record,
|
||||
Lease = lease,
|
||||
Receipt = receipt,
|
||||
});
|
||||
return RuntimeInitialCreateResidenceCompletionStatus.Completed;
|
||||
}
|
||||
|
||||
internal bool AcknowledgeAdoption(
|
||||
RuntimeEntityRecord record,
|
||||
in RuntimeInitialCreateResidenceAdoptionToken token)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (!token.IsValid)
|
||||
return false;
|
||||
if (!_completed.TryGetValue(token.Entity, out CompletedEntry? current)
|
||||
|| !ReferenceEquals(current.Record, record)
|
||||
|| current.Receipt.Adoption != token)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!IsCompletedCurrent(current))
|
||||
{
|
||||
Retire(current);
|
||||
return false;
|
||||
}
|
||||
if (current.Lease.Route.PerformsSetPosition
|
||||
&& !_setPosition.ConsumeAcknowledgedPlacement(
|
||||
current.Lease.Placement,
|
||||
current.Receipt.Projection))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _completed.Remove(token.Entity);
|
||||
}
|
||||
|
||||
internal bool Forget(
|
||||
RuntimeEntityRecord record,
|
||||
out RuntimeInitialCreateResidenceLease lease,
|
||||
out RuntimePlacementCancellationReceipt cancellation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
cancellation = default;
|
||||
if (record.Key is { } key
|
||||
&& _entries.TryGetValue(key, out Entry? entry)
|
||||
&& ReferenceEquals(entry.Record, record)
|
||||
&& _entries.Remove(key))
|
||||
{
|
||||
lease = entry.Lease;
|
||||
cancellation = _setPosition.ForgetExactPlacement(
|
||||
lease.Placement);
|
||||
return true;
|
||||
}
|
||||
if (record.Key is { } completedKey
|
||||
&& _completed.TryGetValue(
|
||||
completedKey,
|
||||
out CompletedEntry? completed)
|
||||
&& ReferenceEquals(completed.Record, record)
|
||||
&& _completed.Remove(completedKey))
|
||||
{
|
||||
lease = completed.Lease;
|
||||
cancellation = _setPosition.ForgetExactPlacement(
|
||||
lease.Placement);
|
||||
return true;
|
||||
}
|
||||
lease = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
Entry[] active = _entries.Values.ToArray();
|
||||
CompletedEntry[] completed = _completed.Values.ToArray();
|
||||
var cancellations = new RuntimePlacementCancellationReceipt[
|
||||
active.Length + completed.Length];
|
||||
_entries.Clear();
|
||||
_completed.Clear();
|
||||
int cancellationCount = 0;
|
||||
foreach (Entry entry in active)
|
||||
{
|
||||
RuntimePlacementCancellationReceipt cancellation =
|
||||
_setPosition.ForgetExactPlacement(
|
||||
entry.Lease.Placement);
|
||||
if (cancellation.IsValid)
|
||||
cancellations[cancellationCount++] = cancellation;
|
||||
}
|
||||
foreach (CompletedEntry entry in completed)
|
||||
{
|
||||
RuntimePlacementCancellationReceipt cancellation =
|
||||
_setPosition.ForgetExactPlacement(
|
||||
entry.Lease.Placement);
|
||||
if (cancellation.IsValid)
|
||||
cancellations[cancellationCount++] = cancellation;
|
||||
}
|
||||
for (int index = 0; index < cancellationCount; index++)
|
||||
{
|
||||
_setPosition.PublishCancellation(cancellations[index]);
|
||||
}
|
||||
}
|
||||
|
||||
internal RuntimeInitialCreateResidenceOwnershipSnapshot CaptureOwnership() =>
|
||||
new(_entries.Count, _completed.Count, _nextLeaseId);
|
||||
|
||||
private bool IsCurrent(Entry entry)
|
||||
{
|
||||
RuntimeInitialCreateResidenceToken token = entry.Lease.Token;
|
||||
bool placementCurrent = !entry.Lease.Route.PerformsSetPosition
|
||||
|| _setPosition.IsPlacementCompletionTracked(
|
||||
entry.Lease.Placement);
|
||||
return placementCurrent
|
||||
&& _entities.IsCurrent(entry.Record)
|
||||
&& entry.Record.Key == token.Entity
|
||||
&& _entities.SessionLifetimeVersion
|
||||
== token.SessionLifetimeVersion
|
||||
&& entry.Record.PositionAuthorityVersion
|
||||
== token.PositionAuthorityVersion
|
||||
&& entry.Record.CreateIntegrationVersion
|
||||
== token.CreateIntegrationVersion
|
||||
&& entry.Lease.Route.Authority.Generation
|
||||
== CurrentGeneration();
|
||||
}
|
||||
|
||||
private RuntimeGenerationToken CurrentGeneration()
|
||||
{
|
||||
return _generation?.Invoke() ?? default;
|
||||
}
|
||||
|
||||
private bool IsCompletedCurrent(CompletedEntry entry)
|
||||
{
|
||||
RuntimeInitialCreateResidenceReceipt receipt = entry.Receipt;
|
||||
return _entities.IsCurrent(entry.Record)
|
||||
&& entry.Record.Key == receipt.Token.Entity
|
||||
&& _entities.SessionLifetimeVersion
|
||||
== receipt.Token.SessionLifetimeVersion
|
||||
&& entry.Record.PositionAuthorityVersion
|
||||
== receipt.Token.PositionAuthorityVersion
|
||||
&& entry.Record.CreateIntegrationVersion
|
||||
== receipt.Token.CreateIntegrationVersion
|
||||
&& entry.Record.FullCellId == receipt.FullCellId
|
||||
&& entry.Record.PlacementCommitVersion
|
||||
== receipt.PlacementCommitVersion
|
||||
&& entry.Lease.Route.Authority.Generation
|
||||
== CurrentGeneration()
|
||||
&& receipt.Token.SessionLifetimeVersion
|
||||
== receipt.Adoption.SessionLifetimeVersion
|
||||
&& receipt.Token.LeaseId == receipt.Adoption.LeaseId
|
||||
&& (!entry.Lease.Route.PerformsSetPosition
|
||||
|| _setPosition.IsPlacementCompletionTracked(
|
||||
entry.Lease.Placement));
|
||||
}
|
||||
|
||||
private void Retire(Entry entry)
|
||||
{
|
||||
_entries.Remove(entry.Lease.Token.Entity);
|
||||
RuntimePlacementCancellationReceipt cancellation =
|
||||
_setPosition.ForgetExactPlacement(entry.Lease.Placement);
|
||||
_setPosition.PublishCancellation(cancellation);
|
||||
}
|
||||
|
||||
private void Retire(CompletedEntry entry)
|
||||
{
|
||||
_completed.Remove(entry.Receipt.Token.Entity);
|
||||
RuntimePlacementCancellationReceipt cancellation =
|
||||
_setPosition.ForgetExactPlacement(entry.Lease.Placement);
|
||||
_setPosition.PublishCancellation(cancellation);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue