using AcDream.App.Rendering;
using AcDream.App.Rendering.Vfx;
using AcDream.App.World;
using AcDream.Core.Physics.Motion;
using DatReaderWriter.Types;
namespace AcDream.App.Input;
///
/// Owns the local player's sequencer root-motion and deferred-hook seams.
/// The movement controller borrows these methods when player mode is entered;
/// no animation lifetime is stored in the window host.
///
internal sealed class LocalPlayerAnimationController
{
private readonly LiveEntityRuntime _liveEntities;
private readonly ILocalPlayerIdentitySource _identity;
private readonly LiveEntityAnimationRuntimeView _animations;
private readonly LiveEntityAnimationPresenter _presenter;
private readonly AnimationHookFrameQueue _hooks;
public LocalPlayerAnimationController(
LiveEntityRuntime liveEntities,
ILocalPlayerIdentitySource identity,
LiveEntityAnimationRuntimeView animations,
LiveEntityAnimationPresenter presenter,
AnimationHookFrameQueue hooks)
{
_liveEntities = liveEntities ?? throw new ArgumentNullException(nameof(liveEntities));
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
_animations = animations ?? throw new ArgumentNullException(nameof(animations));
_presenter = presenter ?? throw new ArgumentNullException(nameof(presenter));
_hooks = hooks ?? throw new ArgumentNullException(nameof(hooks));
}
public void AdvanceRoot(float deltaSeconds, MotionDeltaFrame output)
{
ArgumentNullException.ThrowIfNull(output);
output.Reset();
uint playerGuid = _identity.ServerGuid;
if (!_liveEntities.MaterializedWorldEntities.TryGetValue(playerGuid, out var entity)
|| !_animations.TryGetValue(entity.Id, out var animation)
|| animation.Sequencer is not { } sequencer
|| !_liveEntities.ShouldAdvanceRootRuntime(playerGuid)
|| _liveEntities.IsHidden(playerGuid))
{
return;
}
if (_liveEntities.TryGetRecord(playerGuid, out LiveEntityRecord record))
_presenter.PrepareAnimation(record, animation);
Frame rootFrame = animation.RootMotionScratch;
rootFrame.Origin = System.Numerics.Vector3.Zero;
rootFrame.Orientation = System.Numerics.Quaternion.Identity;
animation.PreparedSequenceFrames = animation.CaptureSequenceFrames(
sequencer.Advance(deltaSeconds, rootFrame));
animation.SequenceAdvancedBeforeAnimationPass = true;
output.Origin = rootFrame.Origin;
output.Orientation = rootFrame.Orientation;
}
public void CaptureHooks()
{
uint playerGuid = _identity.ServerGuid;
if (_liveEntities.MaterializedWorldEntities.TryGetValue(playerGuid, out var entity)
&& _animations.TryGetValue(entity.Id, out var animation)
&& animation.Sequencer is { } sequencer)
{
_hooks.Capture(animation.Entity.Id, sequencer);
}
}
}