refactor(app): compose live presentation startup
This commit is contained in:
parent
aa6ffa5176
commit
88f32dc4e2
23 changed files with 1767 additions and 626 deletions
|
|
@ -0,0 +1,66 @@
|
|||
namespace AcDream.App.World;
|
||||
|
||||
internal interface ILiveEntityLandblockLoadedSink
|
||||
{
|
||||
void OnLandblockLoaded(uint landblockId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase-6 bridge for the Phase-7 hydration owner. The presentation pipeline
|
||||
/// can publish a loaded landblock without capturing a future nullable owner.
|
||||
/// </summary>
|
||||
internal sealed class DeferredLiveEntityLandblockLoadedSink
|
||||
: ILiveEntityLandblockLoadedSink
|
||||
{
|
||||
private ILiveEntityLandblockLoadedSink? _target;
|
||||
private bool _deactivated;
|
||||
|
||||
public void OnLandblockLoaded(uint landblockId)
|
||||
{
|
||||
if (!_deactivated)
|
||||
_target?.OnLandblockLoaded(landblockId);
|
||||
}
|
||||
|
||||
public IDisposable Bind(ILiveEntityLandblockLoadedSink target)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(target);
|
||||
ObjectDisposedException.ThrowIf(_deactivated, this);
|
||||
if (_target is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Live-entity landblock hydration is already bound.");
|
||||
}
|
||||
|
||||
_target = target;
|
||||
return new Binding(this, target);
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
_deactivated = true;
|
||||
_target = null;
|
||||
}
|
||||
|
||||
private void Unbind(ILiveEntityLandblockLoadedSink expected)
|
||||
{
|
||||
if (ReferenceEquals(_target, expected))
|
||||
_target = null;
|
||||
}
|
||||
|
||||
private sealed class Binding : IDisposable
|
||||
{
|
||||
private DeferredLiveEntityLandblockLoadedSink? _owner;
|
||||
private readonly ILiveEntityLandblockLoadedSink _expected;
|
||||
|
||||
public Binding(
|
||||
DeferredLiveEntityLandblockLoadedSink owner,
|
||||
ILiveEntityLandblockLoadedSink expected)
|
||||
{
|
||||
_owner = owner;
|
||||
_expected = expected;
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Interlocked.Exchange(ref _owner, null)?.Unbind(_expected);
|
||||
}
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ internal interface ILiveEntityWorldOriginCoordinator
|
|||
/// Retail anchors: <c>SmartBox::HandleCreateObject @ 0x00454C80</c> and
|
||||
/// <c>ACCObjectMaint::CreateObject @ 0x00558870</c>.
|
||||
/// </summary>
|
||||
internal sealed class LiveEntityHydrationController
|
||||
internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoadedSink
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly ClientObjectTable _objects;
|
||||
|
|
|
|||
|
|
@ -21,4 +21,31 @@ internal sealed class LiveEntityRuntimeSlot : ILiveEntityRuntimeSource
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue