refactor(world): extract live appearance and parenting
Move ObjDesc, Parent, Pickup, child-ready, and retained projection recovery into LiveEntityHydrationController while preserving retail timestamp and leave-world semantics. Pin ready publication to exact projection authority and restore attached descendant chains synchronously.
This commit is contained in:
parent
40352d5a7a
commit
fe5514967c
9 changed files with 1098 additions and 199 deletions
|
|
@ -1,16 +1,48 @@
|
|||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Vfx;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
|
||||
namespace AcDream.App.World;
|
||||
|
||||
internal sealed class DelegateLiveEntitySpawnRelationshipSink(
|
||||
Action<WorldSession.EntitySpawn> onSpawn) : ILiveEntitySpawnRelationshipSink
|
||||
internal sealed class LiveEntityRelationshipProjection(
|
||||
EquippedChildRenderController children) : ILiveEntityRelationshipProjection
|
||||
{
|
||||
private readonly Action<WorldSession.EntitySpawn> _onSpawn =
|
||||
onSpawn ?? throw new ArgumentNullException(nameof(onSpawn));
|
||||
private readonly EquippedChildRenderController _children =
|
||||
children ?? throw new ArgumentNullException(nameof(children));
|
||||
|
||||
public void OnSpawn(WorldSession.EntitySpawn spawn) => _onSpawn(spawn);
|
||||
public void OnSpawn(WorldSession.EntitySpawn spawn) => _children.OnSpawn(spawn);
|
||||
public void OnParent(ParentEvent.Parsed update) => _children.OnParentEvent(update);
|
||||
public void OnCreateParentAccepted(CreateParentUpdate update) =>
|
||||
_children.OnCreateParentAccepted(update);
|
||||
public ChildUnparentDisposition OnChildBecameUnparented(uint childGuid) =>
|
||||
_children.OnChildBecameUnparented(childGuid);
|
||||
public bool TryApplyAttachedAppearance(
|
||||
LiveEntityRecord record,
|
||||
ulong objDescAuthorityVersion) =>
|
||||
_children.TryApplyAttachedAppearance(record, objDescAuthorityVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fail-fast construction seam for the retail ParentEvent timestamp gate.
|
||||
/// The equipped-child renderer can be built before hydration, but no live
|
||||
/// session may resolve a relation until hydration binds this once.
|
||||
/// </summary>
|
||||
internal sealed class DeferredLiveEntityParentAcceptance
|
||||
{
|
||||
private Func<ParentEvent.Parsed, bool>? _accept;
|
||||
|
||||
public void Bind(Func<ParentEvent.Parsed, bool> accept)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(accept);
|
||||
if (Interlocked.CompareExchange(ref _accept, accept, null) is not null)
|
||||
throw new InvalidOperationException("Live parent acceptance is already bound.");
|
||||
}
|
||||
|
||||
public bool TryAccept(ParentEvent.Parsed update) =>
|
||||
(_accept ?? throw new InvalidOperationException(
|
||||
"Live parent acceptance must be bound before a session starts."))(update);
|
||||
}
|
||||
|
||||
internal sealed class LiveEntityReadyPublisher : ILiveEntityReadyPublisher
|
||||
|
|
@ -49,31 +81,23 @@ internal sealed class LiveEntityReadyPublisher : ILiveEntityReadyPublisher
|
|||
?? throw new ArgumentNullException(nameof(replayEffects));
|
||||
}
|
||||
|
||||
public bool Publish(LiveEntityRecord expectedRecord)
|
||||
public bool Publish(LiveEntityReadyCandidate candidate)
|
||||
{
|
||||
LiveEntityRecord expectedRecord = candidate.Record;
|
||||
ArgumentNullException.ThrowIfNull(expectedRecord);
|
||||
ulong createIntegrationVersion = expectedRecord.CreateIntegrationVersion;
|
||||
if (!_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion)
|
||||
if (!candidate.IsCurrent(_runtime)
|
||||
|| !_prepareEffects(expectedRecord)
|
||||
|| !_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion))
|
||||
|| !candidate.IsCurrent(_runtime))
|
||||
return false;
|
||||
|
||||
if (!_presentState(expectedRecord)
|
||||
|| !_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion))
|
||||
|| !candidate.IsCurrent(_runtime))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _replayEffects(expectedRecord)
|
||||
&& _runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion);
|
||||
&& candidate.IsCurrent(_runtime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue