51 lines
1.4 KiB
C#
51 lines
1.4 KiB
C#
namespace AcDream.App.World;
|
|
|
|
internal interface ILiveEntityRuntimeSource
|
|
{
|
|
LiveEntityRuntime? Current { get; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// One-time composition bridge for the resource-activation/runtime cycle.
|
|
/// It owns no identity or entity state; all authority remains in the bound
|
|
/// <see cref="LiveEntityRuntime"/>.
|
|
/// </summary>
|
|
internal sealed class LiveEntityRuntimeSlot : ILiveEntityRuntimeSource
|
|
{
|
|
public LiveEntityRuntime? Current { get; private set; }
|
|
|
|
public void Bind(LiveEntityRuntime runtime)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(runtime);
|
|
if (Current is not null)
|
|
throw new InvalidOperationException("The live entity runtime is already bound.");
|
|
Current = runtime;
|
|
}
|
|
|
|
public IDisposable BindOwned(LiveEntityRuntime runtime)
|
|
{
|
|
Bind(runtime);
|
|
return new Binding(this, runtime);
|
|
}
|
|
|
|
private void Unbind(LiveEntityRuntime expected)
|
|
{
|
|
if (ReferenceEquals(Current, expected))
|
|
Current = null;
|
|
}
|
|
|
|
private sealed class Binding : IDisposable
|
|
{
|
|
private LiveEntityRuntimeSlot? _owner;
|
|
private readonly LiveEntityRuntime _expected;
|
|
|
|
public Binding(LiveEntityRuntimeSlot owner, LiveEntityRuntime expected)
|
|
{
|
|
_owner = owner;
|
|
_expected = expected;
|
|
}
|
|
|
|
public void Dispose() =>
|
|
Interlocked.Exchange(ref _owner, null)?.Unbind(_expected);
|
|
}
|
|
}
|