refactor(animation): extract live PartArray presenter
Move final live part composition, exact-incarnation schedule handoff, MotionDone binding, and presentation diagnostics out of GameWindow while preserving the retail frame order. Reject stale schedule and completion ABA at the new owner boundary. Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
9760ff5a8d
commit
f004ac5562
14 changed files with 963 additions and 438 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering.Vfx;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Physics.Motion;
|
||||
using AcDream.Core.World;
|
||||
|
|
@ -17,7 +18,7 @@ namespace AcDream.App.Rendering;
|
|||
/// resource lifetime. Setup default installation itself is unconditional and
|
||||
/// belongs to PartArray construction; this class owns only the Static workset.
|
||||
/// </summary>
|
||||
internal sealed class RetailStaticAnimatingObjectScheduler
|
||||
internal sealed class RetailStaticAnimatingObjectScheduler : ILiveStaticPartFrameSource
|
||||
{
|
||||
private const double FrameEpsilon = 0.000199999995;
|
||||
private const float MaximumElapsed = 2f;
|
||||
|
|
@ -162,10 +163,24 @@ internal sealed class RetailStaticAnimatingObjectScheduler
|
|||
/// the single owner of mesh identity, overrides, and appearance rebinding.
|
||||
/// </summary>
|
||||
public bool TryTakeLivePartFrames(
|
||||
uint ownerId,
|
||||
LiveEntityRecord record,
|
||||
WorldEntity entity,
|
||||
LiveEntityAnimationState animation,
|
||||
ulong objectClockEpoch,
|
||||
ulong projectionMutationVersion,
|
||||
out IReadOnlyList<PartTransform> frames)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
ArgumentNullException.ThrowIfNull(animation);
|
||||
uint ownerId = entity.Id;
|
||||
if (_owners.TryGetValue(ownerId, out Owner? owner)
|
||||
&& ReferenceEquals(record.WorldEntity, entity)
|
||||
&& ReferenceEquals(record.AnimationRuntime, animation)
|
||||
&& record.ObjectClockEpoch == objectClockEpoch
|
||||
&& record.ProjectionMutationVersion == projectionMutationVersion
|
||||
&& ReferenceEquals(owner.Entity, entity)
|
||||
&& ReferenceEquals(owner.Sequencer, animation.Sequencer)
|
||||
&& owner.Entity.ServerGuid != 0
|
||||
&& owner.PreparedLivePartFrames is { } prepared
|
||||
&& IsResidentAtVersion(owner, owner.PendingResidencyVersion))
|
||||
|
|
@ -182,6 +197,29 @@ internal sealed class RetailStaticAnimatingObjectScheduler
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scheduler-only test seam for DAT/static timing tests which deliberately
|
||||
/// do not construct a <see cref="LiveEntityRuntime"/>. Runtime integration
|
||||
/// must use the exact-incarnation overload above.
|
||||
/// </summary>
|
||||
internal bool TryTakePreparedFramesForTest(
|
||||
uint ownerId,
|
||||
out IReadOnlyList<PartTransform> frames)
|
||||
{
|
||||
if (_owners.TryGetValue(ownerId, out Owner? owner)
|
||||
&& owner.PreparedLivePartFrames is { } prepared
|
||||
&& IsResidentAtVersion(owner, owner.PendingResidencyVersion))
|
||||
{
|
||||
owner.PreparedLivePartFrames = null;
|
||||
frames = prepared;
|
||||
return true;
|
||||
}
|
||||
if (_owners.TryGetValue(ownerId, out owner))
|
||||
InvalidatePending(owner);
|
||||
frames = Array.Empty<PartTransform>();
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Unregister(uint ownerId) => _owners.Remove(ownerId);
|
||||
|
||||
public void CopyAnimatedEntityIdsTo(HashSet<uint> destination)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue