refactor(runtime): extract local teleport and player mode
Move local teleport, player-mode, animation, shadow, and sealed-dungeon lifetimes out of GameWindow. Make player-mode entry transactional and isolate approach completions by controller lifetime and approach generation so stale callbacks cannot affect replacements. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
parent
c557038353
commit
eeb0f6b45c
29 changed files with 3311 additions and 1073 deletions
75
src/AcDream.App/Input/LocalPlayerAnimationController.cs
Normal file
75
src/AcDream.App/Input/LocalPlayerAnimationController.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
internal sealed class LocalPlayerAnimationController
|
||||
{
|
||||
private readonly LiveEntityRuntime _liveEntities;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly LiveEntityAnimationRuntimeView<LiveEntityAnimationState> _animations;
|
||||
private readonly LiveEntityAnimationPresenter _presenter;
|
||||
private readonly AnimationHookFrameQueue _hooks;
|
||||
|
||||
public LocalPlayerAnimationController(
|
||||
LiveEntityRuntime liveEntities,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
LiveEntityAnimationRuntimeView<LiveEntityAnimationState> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue