refactor(world): extract live entity hydration
This commit is contained in:
parent
27dcd0ecb7
commit
d10c5f2d54
17 changed files with 4310 additions and 1269 deletions
150
src/AcDream.App/World/LiveEntityHydrationPorts.cs
Normal file
150
src/AcDream.App/World/LiveEntityHydrationPorts.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using AcDream.App.Rendering.Vfx;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.Core.Net;
|
||||
|
||||
namespace AcDream.App.World;
|
||||
|
||||
internal sealed class DelegateLiveEntitySpawnRelationshipSink(
|
||||
Action<WorldSession.EntitySpawn> onSpawn) : ILiveEntitySpawnRelationshipSink
|
||||
{
|
||||
private readonly Action<WorldSession.EntitySpawn> _onSpawn =
|
||||
onSpawn ?? throw new ArgumentNullException(nameof(onSpawn));
|
||||
|
||||
public void OnSpawn(WorldSession.EntitySpawn spawn) => _onSpawn(spawn);
|
||||
}
|
||||
|
||||
internal sealed class LiveEntityReadyPublisher : ILiveEntityReadyPublisher
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly Func<LiveEntityRecord, bool> _prepareEffects;
|
||||
private readonly Func<LiveEntityRecord, bool> _presentState;
|
||||
private readonly Func<LiveEntityRecord, bool> _replayEffects;
|
||||
|
||||
public LiveEntityReadyPublisher(
|
||||
LiveEntityRuntime runtime,
|
||||
EntityEffectController effects,
|
||||
LiveEntityPresentationController presentation)
|
||||
: this(
|
||||
runtime,
|
||||
record => effects.PrepareLiveEntityOwner(record.ServerGuid),
|
||||
record => presentation.OnLiveEntityReady(record.ServerGuid),
|
||||
record => effects.ReplayPendingForLiveEntity(record.ServerGuid))
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(effects);
|
||||
ArgumentNullException.ThrowIfNull(presentation);
|
||||
}
|
||||
|
||||
internal LiveEntityReadyPublisher(
|
||||
LiveEntityRuntime runtime,
|
||||
Func<LiveEntityRecord, bool> prepareEffects,
|
||||
Func<LiveEntityRecord, bool> presentState,
|
||||
Func<LiveEntityRecord, bool> replayEffects)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_prepareEffects = prepareEffects
|
||||
?? throw new ArgumentNullException(nameof(prepareEffects));
|
||||
_presentState = presentState
|
||||
?? throw new ArgumentNullException(nameof(presentState));
|
||||
_replayEffects = replayEffects
|
||||
?? throw new ArgumentNullException(nameof(replayEffects));
|
||||
}
|
||||
|
||||
public bool Publish(LiveEntityRecord expectedRecord)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(expectedRecord);
|
||||
ulong createIntegrationVersion = expectedRecord.CreateIntegrationVersion;
|
||||
if (!_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion)
|
||||
|| !_prepareEffects(expectedRecord)
|
||||
|| !_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion))
|
||||
return false;
|
||||
|
||||
if (!_presentState(expectedRecord)
|
||||
|| !_runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _replayEffects(expectedRecord)
|
||||
&& _runtime.IsCurrentCreateIntegration(
|
||||
expectedRecord,
|
||||
createIntegrationVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the first accepted local-player Position into the shared streaming
|
||||
/// origin. Retail <c>SmartBox::UseTime @ 0x00455410</c> blocks completion until
|
||||
/// destination cells are ready; already-resident landblocks are returned to
|
||||
/// hydration for the same synchronous recovery edge.
|
||||
/// </summary>
|
||||
internal sealed class LiveEntityWorldOriginCoordinator : ILiveEntityWorldOriginCoordinator
|
||||
{
|
||||
private readonly LiveWorldOriginState _origin;
|
||||
private readonly StreamingController _streaming;
|
||||
private readonly GpuWorldState _worldState;
|
||||
private readonly WorldRevealCoordinator _worldReveal;
|
||||
private readonly Func<uint> _playerGuid;
|
||||
private readonly Func<uint, bool> _isSealedDungeonCell;
|
||||
private readonly Action<string>? _diagnostic;
|
||||
|
||||
public LiveEntityWorldOriginCoordinator(
|
||||
LiveWorldOriginState origin,
|
||||
StreamingController streaming,
|
||||
GpuWorldState worldState,
|
||||
WorldRevealCoordinator worldReveal,
|
||||
Func<uint> playerGuid,
|
||||
Func<uint, bool> isSealedDungeonCell,
|
||||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_origin = origin ?? throw new ArgumentNullException(nameof(origin));
|
||||
_streaming = streaming ?? throw new ArgumentNullException(nameof(streaming));
|
||||
_worldState = worldState ?? throw new ArgumentNullException(nameof(worldState));
|
||||
_worldReveal = worldReveal ?? throw new ArgumentNullException(nameof(worldReveal));
|
||||
_playerGuid = playerGuid ?? throw new ArgumentNullException(nameof(playerGuid));
|
||||
_isSealedDungeonCell = isSealedDungeonCell
|
||||
?? throw new ArgumentNullException(nameof(isSealedDungeonCell));
|
||||
_diagnostic = diagnostic;
|
||||
}
|
||||
|
||||
public bool IsKnown => _origin.IsKnown;
|
||||
|
||||
public LiveEntityOriginInitialization TryInitialize(
|
||||
WorldSession.EntitySpawn spawn)
|
||||
{
|
||||
if (spawn.Guid != _playerGuid()
|
||||
|| spawn.Position is not { } position)
|
||||
{
|
||||
return new(_origin.IsKnown, Array.Empty<uint>());
|
||||
}
|
||||
|
||||
int lbX = (int)((position.LandblockId >> 24) & 0xFFu);
|
||||
int lbY = (int)((position.LandblockId >> 16) & 0xFFu);
|
||||
int oldCenterX = _origin.CenterX;
|
||||
int oldCenterY = _origin.CenterY;
|
||||
if (!_origin.TryInitialize(lbX, lbY))
|
||||
return new(true, Array.Empty<uint>());
|
||||
|
||||
if (lbX != oldCenterX || lbY != oldCenterY)
|
||||
{
|
||||
_diagnostic?.Invoke(
|
||||
$"live: first player position — recentering streaming from ({oldCenterX},{oldCenterY}) "
|
||||
+ $"to ({lbX},{lbY}) @0x{position.LandblockId:X8}");
|
||||
}
|
||||
|
||||
_streaming.InitializeKnownLoginCenter(
|
||||
lbX,
|
||||
lbY,
|
||||
isSealedDungeon: _isSealedDungeonCell(position.LandblockId));
|
||||
_worldReveal.Begin(WorldRevealKind.Login);
|
||||
|
||||
return new(
|
||||
true,
|
||||
_worldState.LoadedLandblockIds.ToArray());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue