feat(runtime): expose dormant placement receipts
This commit is contained in:
parent
4c02ac4259
commit
270f5154b9
9 changed files with 223 additions and 4 deletions
|
|
@ -118,6 +118,9 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
|
|||
InventoryView = views.Inventory;
|
||||
Events = new RuntimeEntityObjectEventStream(Entities, Objects);
|
||||
Physics.SetPosition.BindEventStream(Events);
|
||||
Placements = new RuntimePlacementProjectionChannel(
|
||||
Events,
|
||||
Physics.SetPosition);
|
||||
}
|
||||
|
||||
internal RuntimeEntityObjectLifetime(
|
||||
|
|
@ -140,6 +143,9 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
|
|||
InventoryView = views.Inventory;
|
||||
Events = new RuntimeEntityObjectEventStream(Entities, Objects);
|
||||
Physics.SetPosition.BindEventStream(Events);
|
||||
Placements = new RuntimePlacementProjectionChannel(
|
||||
Events,
|
||||
Physics.SetPosition);
|
||||
}
|
||||
|
||||
internal RuntimeEntityObjectLifetime(
|
||||
|
|
@ -162,6 +168,9 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
|
|||
InventoryView = views.Inventory;
|
||||
Events = new RuntimeEntityObjectEventStream(Entities, Objects);
|
||||
Physics.SetPosition.BindEventStream(Events);
|
||||
Placements = new RuntimePlacementProjectionChannel(
|
||||
Events,
|
||||
Physics.SetPosition);
|
||||
}
|
||||
|
||||
public RuntimeEntityDirectory Entities { get; }
|
||||
|
|
@ -170,6 +179,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
|
|||
public IRuntimeEntityView EntityView { get; }
|
||||
public IRuntimeInventoryView InventoryView { get; }
|
||||
public RuntimeEntityObjectEventStream Events { get; }
|
||||
public RuntimePlacementProjectionChannel Placements { get; }
|
||||
|
||||
public RuntimeEntityObjectOwnershipSnapshot CaptureOwnership()
|
||||
{
|
||||
|
|
@ -204,6 +214,7 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
|
|||
{
|
||||
EnsureNotDisposed();
|
||||
Events.BindContext(generation, frameNumber);
|
||||
Placements.BindGeneration(generation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Physics;
|
||||
using AcDream.Runtime.Session;
|
||||
using AcDream.Runtime.World;
|
||||
|
||||
|
|
@ -303,6 +304,8 @@ public sealed class GameRuntime
|
|||
public RuntimeWorldEnvironmentState EnvironmentOwner { get; }
|
||||
public RuntimeWorldTransitState TransitOwner { get; }
|
||||
public RuntimeGenerationReset GenerationReset { get; }
|
||||
public RuntimePlacementProjectionChannel Placements =>
|
||||
EntityObjects.Placements;
|
||||
|
||||
public RuntimeGenerationToken Generation => Session.Generation;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.Runtime.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Public host boundary for Runtime-owned SetPosition projection receipts.
|
||||
/// The channel owns no placement state: observation, retry, and exact-token
|
||||
/// acknowledgement delegate to the canonical entity lifetime's event stream
|
||||
/// and SetPosition owner.
|
||||
/// </summary>
|
||||
public sealed class RuntimePlacementProjectionChannel
|
||||
{
|
||||
private readonly RuntimeEntityObjectEventStream _events;
|
||||
private readonly RuntimeSetPositionState _setPosition;
|
||||
private Func<RuntimeGenerationToken> _generation = static () => default;
|
||||
private bool _generationBound;
|
||||
|
||||
internal RuntimePlacementProjectionChannel(
|
||||
RuntimeEntityObjectEventStream events,
|
||||
RuntimeSetPositionState setPosition)
|
||||
{
|
||||
_events = events ?? throw new ArgumentNullException(nameof(events));
|
||||
_setPosition = setPosition
|
||||
?? throw new ArgumentNullException(nameof(setPosition));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes ordered immutable projection receipts on the Runtime commit
|
||||
/// thread. A host must acknowledge only after its projection succeeds.
|
||||
/// </summary>
|
||||
public IDisposable Subscribe(IRuntimePlacementObserver observer) =>
|
||||
_events.SubscribePlacement(observer);
|
||||
|
||||
internal void BindGeneration(Func<RuntimeGenerationToken> generation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generation);
|
||||
if (_generationBound)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The Runtime placement generation source is already bound.");
|
||||
}
|
||||
|
||||
_generation = generation;
|
||||
_generationBound = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Acknowledges only the exact oldest outstanding receipt. Stale,
|
||||
/// reordered, superseded, or already acknowledged tokens are rejected.
|
||||
/// </summary>
|
||||
public bool Acknowledge(
|
||||
RuntimeGenerationToken expectedGeneration,
|
||||
in RuntimePlacementProjectionToken token) =>
|
||||
IsCurrent(expectedGeneration)
|
||||
&& _setPosition.AcknowledgeProjection(token);
|
||||
|
||||
/// <summary>
|
||||
/// Republishes every still-pending immutable receipt in canonical order.
|
||||
/// Runtime authority is never replayed or recommitted by a retry.
|
||||
/// </summary>
|
||||
public bool RetryPending(RuntimeGenerationToken expectedGeneration)
|
||||
{
|
||||
if (!IsCurrent(expectedGeneration))
|
||||
return false;
|
||||
_setPosition.RetryPendingProjections();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the exact oldest outstanding receipt without consuming it.
|
||||
/// </summary>
|
||||
public bool TryPeek(
|
||||
RuntimeGenerationToken expectedGeneration,
|
||||
out RuntimePlacementProjectionSnapshot projection)
|
||||
{
|
||||
if (IsCurrent(expectedGeneration))
|
||||
return _setPosition.TryPeekProjection(out projection);
|
||||
projection = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int PendingCount => _setPosition.PendingProjectionCount;
|
||||
|
||||
private bool IsCurrent(RuntimeGenerationToken expectedGeneration) =>
|
||||
_generationBound
|
||||
&& expectedGeneration.Value != 0UL
|
||||
&& expectedGeneration == _generation();
|
||||
}
|
||||
|
|
@ -283,6 +283,8 @@ internal sealed class RuntimeSetPositionState : IDisposable
|
|||
_preparedMovers.Count);
|
||||
}
|
||||
|
||||
internal int PendingProjectionCount => _pendingProjection.Count;
|
||||
|
||||
internal void BindEventStream(RuntimeEntityObjectEventStream events)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue