feat(runtime): own initial create residence transaction

This commit is contained in:
Erik 2026-08-01 19:35:08 +02:00
parent 74103f75b5
commit 38fd4b8dc9
10 changed files with 3031 additions and 17 deletions

View file

@ -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);
}
}