refactor(camera): extract the update frame
Move fly/chase publication, combat target tracking, and local player projection behind typed runtime owners. Preserve the inbound-created projection/reconcile barrier while removing GameWindow callbacks and duplicate shadow helpers.
This commit is contained in:
parent
eeb0f6b45c
commit
947c61d2d7
19 changed files with 988 additions and 356 deletions
72
src/AcDream.App/Input/DispatcherCameraInputSource.cs
Normal file
72
src/AcDream.App/Input/DispatcherCameraInputSource.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
using AcDream.UI.Abstractions.Input;
|
||||
|
||||
namespace AcDream.App.Input;
|
||||
|
||||
internal readonly record struct FlyCameraInput(
|
||||
bool Forward,
|
||||
bool Left,
|
||||
bool Backward,
|
||||
bool Right,
|
||||
bool Up,
|
||||
bool Down,
|
||||
bool Boost);
|
||||
|
||||
internal readonly record struct ChaseCameraAdjustmentInput(
|
||||
bool ZoomIn,
|
||||
bool ZoomOut,
|
||||
bool Raise,
|
||||
bool Lower);
|
||||
|
||||
internal interface ICameraFrameInputSource
|
||||
{
|
||||
bool IsAvailable { get; }
|
||||
FlyCameraInput CaptureFly();
|
||||
ChaseCameraAdjustmentInput CaptureChaseAdjustment();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Samples held camera actions from the same semantic dispatcher used by
|
||||
/// gameplay movement. Binding is a one-time startup edge.
|
||||
/// </summary>
|
||||
internal sealed class DispatcherCameraInputSource : ICameraFrameInputSource
|
||||
{
|
||||
private InputDispatcher? _dispatcher;
|
||||
|
||||
public bool IsAvailable => _dispatcher is not null;
|
||||
|
||||
public void Bind(InputDispatcher dispatcher)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dispatcher);
|
||||
if (_dispatcher is not null && !ReferenceEquals(_dispatcher, dispatcher))
|
||||
throw new InvalidOperationException(
|
||||
"The camera input source is already bound to another dispatcher.");
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
public FlyCameraInput CaptureFly()
|
||||
{
|
||||
if (_dispatcher is not { } dispatcher)
|
||||
return default;
|
||||
|
||||
return new FlyCameraInput(
|
||||
dispatcher.IsActionHeld(InputAction.MovementForward),
|
||||
dispatcher.IsActionHeld(InputAction.MovementTurnLeft),
|
||||
dispatcher.IsActionHeld(InputAction.MovementBackup),
|
||||
dispatcher.IsActionHeld(InputAction.MovementTurnRight),
|
||||
dispatcher.IsActionHeld(InputAction.MovementJump),
|
||||
dispatcher.IsActionHeld(InputAction.AcdreamFlyDown),
|
||||
dispatcher.IsActionHeld(InputAction.MovementRunLock));
|
||||
}
|
||||
|
||||
public ChaseCameraAdjustmentInput CaptureChaseAdjustment()
|
||||
{
|
||||
if (_dispatcher is not { } dispatcher)
|
||||
return default;
|
||||
|
||||
return new ChaseCameraAdjustmentInput(
|
||||
dispatcher.IsActionHeld(InputAction.CameraZoomIn),
|
||||
dispatcher.IsActionHeld(InputAction.CameraZoomOut),
|
||||
dispatcher.IsActionHeld(InputAction.CameraRaise),
|
||||
dispatcher.IsActionHeld(InputAction.CameraLower));
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ internal sealed class DispatcherMovementInputSource : IMovementInputSource
|
|||
_capture = capture;
|
||||
|
||||
public bool AutoRunActive { get; private set; }
|
||||
public bool IsAvailable => _dispatcher is not null;
|
||||
|
||||
public void Bind(InputDispatcher dispatcher)
|
||||
{
|
||||
|
|
|
|||
122
src/AcDream.App/Input/LocalPlayerFrameRuntime.cs
Normal file
122
src/AcDream.App/Input/LocalPlayerFrameRuntime.cs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
using AcDream.App.Net;
|
||||
using AcDream.App.Physics;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Core.Physics;
|
||||
|
||||
namespace AcDream.App.Input;
|
||||
|
||||
/// <summary>
|
||||
/// Focused runtime seam for the local player's retail object and command
|
||||
/// phases. The frame controller owns ordering; this seam resolves the current
|
||||
/// session-scoped owners without retaining callbacks into the window host.
|
||||
/// </summary>
|
||||
internal interface ILocalPlayerPresentationRuntime
|
||||
{
|
||||
bool CanPresentPlayer { get; }
|
||||
PlayerMovementController? Controller { get; }
|
||||
}
|
||||
|
||||
internal interface ILocalPlayerFrameRuntime : ILocalPlayerPresentationRuntime
|
||||
{
|
||||
uint ResolveLocalEntityId();
|
||||
void HandleTargeting();
|
||||
bool IsHidden { get; }
|
||||
RetailObjectClockDisposition ObjectClockDisposition { get; }
|
||||
void Project(PlayerMovementController controller, MovementResult movement, bool hidden);
|
||||
void SendPreNetwork(PlayerMovementController controller, MovementResult movement, bool hidden);
|
||||
void SendPostNetwork(PlayerMovementController controller, bool hidden);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Production local-player frame runtime composed from canonical typed owners.
|
||||
/// </summary>
|
||||
internal sealed class LiveLocalPlayerFrameRuntime : ILocalPlayerFrameRuntime
|
||||
{
|
||||
private readonly CameraController _camera;
|
||||
private readonly ILocalPlayerModeSource _mode;
|
||||
private readonly ILocalPlayerControllerSource _controller;
|
||||
private readonly IChaseCameraSource _chase;
|
||||
private readonly DispatcherMovementInputSource _input;
|
||||
private readonly IInputCaptureSource _capture;
|
||||
private readonly LiveEntityRuntime _liveEntities;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly ILocalPlayerPhysicsHostSource _physicsHost;
|
||||
private readonly LocalPlayerProjectionController _projection;
|
||||
private readonly LocalPlayerOutboundController _outbound;
|
||||
private readonly ILiveWorldSessionSource _session;
|
||||
|
||||
public LiveLocalPlayerFrameRuntime(
|
||||
CameraController camera,
|
||||
ILocalPlayerModeSource mode,
|
||||
ILocalPlayerControllerSource controller,
|
||||
IChaseCameraSource chase,
|
||||
DispatcherMovementInputSource input,
|
||||
IInputCaptureSource capture,
|
||||
LiveEntityRuntime liveEntities,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
ILocalPlayerPhysicsHostSource physicsHost,
|
||||
LocalPlayerProjectionController projection,
|
||||
LocalPlayerOutboundController outbound,
|
||||
ILiveWorldSessionSource session)
|
||||
{
|
||||
_camera = camera ?? throw new ArgumentNullException(nameof(camera));
|
||||
_mode = mode ?? throw new ArgumentNullException(nameof(mode));
|
||||
_controller = controller ?? throw new ArgumentNullException(nameof(controller));
|
||||
_chase = chase ?? throw new ArgumentNullException(nameof(chase));
|
||||
_input = input ?? throw new ArgumentNullException(nameof(input));
|
||||
_capture = capture ?? throw new ArgumentNullException(nameof(capture));
|
||||
_liveEntities = liveEntities ?? throw new ArgumentNullException(nameof(liveEntities));
|
||||
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
|
||||
_physicsHost = physicsHost ?? throw new ArgumentNullException(nameof(physicsHost));
|
||||
_projection = projection ?? throw new ArgumentNullException(nameof(projection));
|
||||
_outbound = outbound ?? throw new ArgumentNullException(nameof(outbound));
|
||||
_session = session ?? throw new ArgumentNullException(nameof(session));
|
||||
}
|
||||
|
||||
public bool CanPresentPlayer =>
|
||||
!_camera.IsFlyMode
|
||||
&& _mode.IsPlayerMode
|
||||
&& _controller.Controller is not null
|
||||
&& _chase.Legacy is not null
|
||||
&& _input.IsAvailable
|
||||
&& !_capture.DevToolsWantCaptureKeyboard;
|
||||
|
||||
public PlayerMovementController? Controller => _controller.Controller;
|
||||
|
||||
public uint ResolveLocalEntityId() =>
|
||||
_liveEntities.TryGetWorldEntity(_identity.ServerGuid, out var entity)
|
||||
? entity.Id
|
||||
: 0u;
|
||||
|
||||
public void HandleTargeting() => _physicsHost.Host?.HandleTargetting();
|
||||
|
||||
public bool IsHidden => _liveEntities.IsHidden(_identity.ServerGuid);
|
||||
|
||||
public RetailObjectClockDisposition ObjectClockDisposition =>
|
||||
_liveEntities.GetRootObjectClockDisposition(_identity.ServerGuid);
|
||||
|
||||
public void Project(
|
||||
PlayerMovementController controller,
|
||||
MovementResult movement,
|
||||
bool hidden) =>
|
||||
_projection.Project(controller, movement, hidden);
|
||||
|
||||
public void SendPreNetwork(
|
||||
PlayerMovementController controller,
|
||||
MovementResult movement,
|
||||
bool hidden) =>
|
||||
_outbound.SendPreNetworkActions(
|
||||
_session.CurrentSession,
|
||||
controller,
|
||||
movement,
|
||||
hidden);
|
||||
|
||||
public void SendPostNetwork(
|
||||
PlayerMovementController controller,
|
||||
bool hidden) =>
|
||||
_outbound.SendPostNetworkPosition(
|
||||
_session.CurrentSession,
|
||||
controller,
|
||||
hidden);
|
||||
}
|
||||
|
|
@ -1,47 +1,77 @@
|
|||
using AcDream.Core.World;
|
||||
using AcDream.App.Physics;
|
||||
using AcDream.App.World;
|
||||
|
||||
namespace AcDream.App.Input;
|
||||
|
||||
internal interface ILocalPlayerProjectionRuntime
|
||||
{
|
||||
WorldEntity? ResolveEntity();
|
||||
int LiveCenterX { get; }
|
||||
int LiveCenterY { get; }
|
||||
void SyncShadow(WorldEntity entity, uint cellId);
|
||||
void Rebucket(uint serverGuid, uint landblockId);
|
||||
bool IsCurrentVisibleProjection(WorldEntity entity);
|
||||
void SuspendShadow(WorldEntity entity);
|
||||
}
|
||||
|
||||
internal sealed class LiveLocalPlayerProjectionRuntime
|
||||
: ILocalPlayerProjectionRuntime
|
||||
{
|
||||
private readonly LiveEntityRuntime _liveEntities;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly LiveWorldOriginState _origin;
|
||||
private readonly LocalPlayerShadowSynchronizer _shadow;
|
||||
|
||||
public LiveLocalPlayerProjectionRuntime(
|
||||
LiveEntityRuntime liveEntities,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
LiveWorldOriginState origin,
|
||||
LocalPlayerShadowSynchronizer shadow)
|
||||
{
|
||||
_liveEntities = liveEntities ?? throw new ArgumentNullException(nameof(liveEntities));
|
||||
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
|
||||
_origin = origin ?? throw new ArgumentNullException(nameof(origin));
|
||||
_shadow = shadow ?? throw new ArgumentNullException(nameof(shadow));
|
||||
}
|
||||
|
||||
public WorldEntity? ResolveEntity() =>
|
||||
_liveEntities.TryGetWorldEntity(_identity.ServerGuid, out var entity)
|
||||
? entity
|
||||
: null;
|
||||
|
||||
public int LiveCenterX => _origin.CenterX;
|
||||
public int LiveCenterY => _origin.CenterY;
|
||||
|
||||
public void SyncShadow(WorldEntity entity, uint cellId) =>
|
||||
_shadow.Sync(entity, cellId);
|
||||
|
||||
public void Rebucket(uint serverGuid, uint landblockId) =>
|
||||
_liveEntities.RebucketLiveEntity(serverGuid, landblockId);
|
||||
|
||||
public bool IsCurrentVisibleProjection(WorldEntity entity) =>
|
||||
_shadow.IsCurrentVisibleProjection(entity);
|
||||
|
||||
public void SuspendShadow(WorldEntity entity) => _shadow.Suspend(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects the canonical local physics body into world rendering and spatial
|
||||
/// buckets without advancing it.
|
||||
/// </summary>
|
||||
public sealed class LocalPlayerProjectionController
|
||||
{
|
||||
private readonly Func<WorldEntity?> _resolveEntity;
|
||||
private readonly Func<int> _liveCenterX;
|
||||
private readonly Func<int> _liveCenterY;
|
||||
private readonly Action<WorldEntity, uint> _syncShadow;
|
||||
private readonly Action<uint, uint> _rebucket;
|
||||
private readonly Func<WorldEntity, bool> _isCurrentVisibleProjection;
|
||||
private readonly Action<WorldEntity> _suspendShadow;
|
||||
private readonly ILocalPlayerProjectionRuntime _runtime;
|
||||
|
||||
public LocalPlayerProjectionController(
|
||||
Func<WorldEntity?> resolveEntity,
|
||||
Func<int> liveCenterX,
|
||||
Func<int> liveCenterY,
|
||||
Action<WorldEntity, uint> syncShadow,
|
||||
Action<uint, uint> rebucket,
|
||||
Func<WorldEntity, bool> isCurrentVisibleProjection,
|
||||
Action<WorldEntity> suspendShadow)
|
||||
{
|
||||
_resolveEntity = resolveEntity ?? throw new ArgumentNullException(nameof(resolveEntity));
|
||||
_liveCenterX = liveCenterX ?? throw new ArgumentNullException(nameof(liveCenterX));
|
||||
_liveCenterY = liveCenterY ?? throw new ArgumentNullException(nameof(liveCenterY));
|
||||
_syncShadow = syncShadow ?? throw new ArgumentNullException(nameof(syncShadow));
|
||||
_rebucket = rebucket ?? throw new ArgumentNullException(nameof(rebucket));
|
||||
_isCurrentVisibleProjection = isCurrentVisibleProjection
|
||||
?? throw new ArgumentNullException(nameof(isCurrentVisibleProjection));
|
||||
_suspendShadow = suspendShadow
|
||||
?? throw new ArgumentNullException(nameof(suspendShadow));
|
||||
}
|
||||
internal LocalPlayerProjectionController(ILocalPlayerProjectionRuntime runtime) =>
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
|
||||
public void Project(
|
||||
PlayerMovementController controller,
|
||||
MovementResult movement,
|
||||
bool hidden)
|
||||
{
|
||||
WorldEntity? entity = _resolveEntity();
|
||||
WorldEntity? entity = _runtime.ResolveEntity();
|
||||
if (entity is null)
|
||||
return;
|
||||
|
||||
|
|
@ -62,8 +92,8 @@ public sealed class LocalPlayerProjectionController
|
|||
else
|
||||
{
|
||||
System.Numerics.Vector3 position = controller.Position;
|
||||
int landblockX = _liveCenterX() + (int)Math.Floor(position.X / 192f);
|
||||
int landblockY = _liveCenterY() + (int)Math.Floor(position.Y / 192f);
|
||||
int landblockX = _runtime.LiveCenterX + (int)Math.Floor(position.X / 192f);
|
||||
int landblockY = _runtime.LiveCenterY + (int)Math.Floor(position.Y / 192f);
|
||||
currentLandblock = (uint)((landblockX << 24) | (landblockY << 16) | 0xFFFF);
|
||||
}
|
||||
|
||||
|
|
@ -76,15 +106,15 @@ public sealed class LocalPlayerProjectionController
|
|||
// membership, then replaces collision rows only while the object still
|
||||
// owns a loaded cell. Rebucket is a synchronous callback boundary: it
|
||||
// can move this incarnation to pending or replace the GUID entirely.
|
||||
_rebucket(entity.ServerGuid, currentLandblock);
|
||||
_runtime.Rebucket(entity.ServerGuid, currentLandblock);
|
||||
if (hidden
|
||||
|| movement.CellId == 0
|
||||
|| !_isCurrentVisibleProjection(entity))
|
||||
|| !_runtime.IsCurrentVisibleProjection(entity))
|
||||
{
|
||||
_suspendShadow(entity);
|
||||
_runtime.SuspendShadow(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
_syncShadow(entity, movement.CellId);
|
||||
_runtime.SyncShadow(entity, movement.CellId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,13 @@ internal sealed class SilkMouseLookCursor : IMouseLookCursor
|
|||
/// The current chase-camera input targets. GameWindow keeps compatibility
|
||||
/// properties over this one slot until checkpoint F moves camera ownership.
|
||||
/// </summary>
|
||||
internal sealed class ChaseCameraInputState
|
||||
internal interface IChaseCameraSource
|
||||
{
|
||||
ChaseCamera? Legacy { get; }
|
||||
RetailChaseCamera? Retail { get; }
|
||||
}
|
||||
|
||||
internal sealed class ChaseCameraInputState : IChaseCameraSource
|
||||
{
|
||||
public ChaseCamera? Legacy { get; set; }
|
||||
public RetailChaseCamera? Retail { get; set; }
|
||||
|
|
|
|||
|
|
@ -14,17 +14,8 @@ namespace AcDream.App.Input;
|
|||
/// </remarks>
|
||||
internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFramePhase
|
||||
{
|
||||
private readonly Func<bool> _canPresentPlayer;
|
||||
private readonly Func<PlayerMovementController?> _getController;
|
||||
private readonly ILocalPlayerFrameRuntime _runtime;
|
||||
private readonly IMovementInputSource _movementInput;
|
||||
private readonly Func<uint> _resolveLocalEntityId;
|
||||
private readonly Action _handleTargeting;
|
||||
private readonly Func<bool> _isHidden;
|
||||
private readonly Action<PlayerMovementController, MovementResult, bool> _project;
|
||||
private readonly Action<PlayerMovementController, MovementResult, bool> _sendPreNetwork;
|
||||
private readonly Action<PlayerMovementController, bool> _sendPostNetwork;
|
||||
private readonly Func<AcDream.Core.Physics.RetailObjectClockDisposition>
|
||||
_objectClockDisposition;
|
||||
|
||||
private AdvancedFrame? _advancedFrame;
|
||||
|
||||
|
|
@ -51,38 +42,12 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
};
|
||||
|
||||
public RetailLocalPlayerFrameController(
|
||||
Func<bool> canPresentPlayer,
|
||||
Func<PlayerMovementController?> getController,
|
||||
IMovementInputSource movementInput,
|
||||
Func<uint> resolveLocalEntityId,
|
||||
Action handleTargeting,
|
||||
Func<bool> isHidden,
|
||||
Action<PlayerMovementController, MovementResult, bool> project,
|
||||
Action<PlayerMovementController, MovementResult, bool> sendPreNetwork,
|
||||
Action<PlayerMovementController, bool> sendPostNetwork,
|
||||
Func<AcDream.Core.Physics.RetailObjectClockDisposition>?
|
||||
objectClockDisposition = null)
|
||||
ILocalPlayerFrameRuntime runtime,
|
||||
IMovementInputSource movementInput)
|
||||
{
|
||||
_canPresentPlayer = canPresentPlayer
|
||||
?? throw new ArgumentNullException(nameof(canPresentPlayer));
|
||||
_getController = getController
|
||||
?? throw new ArgumentNullException(nameof(getController));
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_movementInput = movementInput
|
||||
?? throw new ArgumentNullException(nameof(movementInput));
|
||||
_resolveLocalEntityId = resolveLocalEntityId
|
||||
?? throw new ArgumentNullException(nameof(resolveLocalEntityId));
|
||||
_handleTargeting = handleTargeting
|
||||
?? throw new ArgumentNullException(nameof(handleTargeting));
|
||||
_isHidden = isHidden
|
||||
?? throw new ArgumentNullException(nameof(isHidden));
|
||||
_project = project
|
||||
?? throw new ArgumentNullException(nameof(project));
|
||||
_sendPreNetwork = sendPreNetwork
|
||||
?? throw new ArgumentNullException(nameof(sendPreNetwork));
|
||||
_sendPostNetwork = sendPostNetwork
|
||||
?? throw new ArgumentNullException(nameof(sendPostNetwork));
|
||||
_objectClockDisposition = objectClockDisposition
|
||||
?? (() => AcDream.Core.Physics.RetailObjectClockDisposition.Advance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -92,15 +57,15 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
public void AdvanceBeforeNetwork(float deltaSeconds)
|
||||
{
|
||||
_advancedFrame = null;
|
||||
PlayerMovementController? controller = _getController();
|
||||
if (!_canPresentPlayer() || controller is null)
|
||||
PlayerMovementController? controller = _runtime.Controller;
|
||||
if (!_runtime.CanPresentPlayer || controller is null)
|
||||
return;
|
||||
|
||||
if (!float.IsFinite(deltaSeconds) || deltaSeconds <= 0f)
|
||||
{
|
||||
bool rejectedHidden = _isHidden();
|
||||
bool rejectedHidden = _runtime.IsHidden;
|
||||
MovementResult rejected = controller.CapturePresentationResult();
|
||||
_project(controller, rejected, rejectedHidden);
|
||||
_runtime.Project(controller, rejected, rejectedHidden);
|
||||
_advancedFrame = new AdvancedFrame(
|
||||
controller,
|
||||
rejected,
|
||||
|
|
@ -110,10 +75,10 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
return;
|
||||
}
|
||||
|
||||
controller.LocalEntityId = _resolveLocalEntityId();
|
||||
controller.LocalEntityId = _runtime.ResolveLocalEntityId();
|
||||
|
||||
bool hidden = _isHidden();
|
||||
if (_objectClockDisposition()
|
||||
bool hidden = _runtime.IsHidden;
|
||||
if (_runtime.ObjectClockDisposition
|
||||
is AcDream.Core.Physics.RetailObjectClockDisposition.Suspend)
|
||||
{
|
||||
// CPhysicsObj::update_object returns before advancing time for a
|
||||
|
|
@ -122,7 +87,7 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
// physics tick that retail did not run.
|
||||
controller.SuspendObjectUpdate(deltaSeconds);
|
||||
MovementResult paused = controller.CapturePresentationResult();
|
||||
_project(controller, paused, hidden);
|
||||
_runtime.Project(controller, paused, hidden);
|
||||
_advancedFrame = new AdvancedFrame(
|
||||
controller,
|
||||
paused,
|
||||
|
|
@ -133,11 +98,14 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
}
|
||||
|
||||
MovementResult movement = hidden
|
||||
? controller.TickHidden(deltaSeconds, _handleTargeting)
|
||||
: controller.Update(deltaSeconds, _movementInput.Capture(), _handleTargeting);
|
||||
? controller.TickHidden(deltaSeconds, _runtime.HandleTargeting)
|
||||
: controller.Update(
|
||||
deltaSeconds,
|
||||
_movementInput.Capture(),
|
||||
_runtime.HandleTargeting);
|
||||
|
||||
_project(controller, movement, hidden);
|
||||
_sendPreNetwork(controller, movement, hidden);
|
||||
_runtime.Project(controller, movement, hidden);
|
||||
_runtime.SendPreNetwork(controller, movement, hidden);
|
||||
_advancedFrame = new AdvancedFrame(
|
||||
controller,
|
||||
movement,
|
||||
|
|
@ -153,18 +121,18 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
/// </summary>
|
||||
public void RunPostNetworkCommandPhase()
|
||||
{
|
||||
PlayerMovementController? controller = _getController();
|
||||
if (!_canPresentPlayer() || controller is null)
|
||||
PlayerMovementController? controller = _runtime.Controller;
|
||||
if (!_runtime.CanPresentPlayer || controller is null)
|
||||
return;
|
||||
|
||||
bool hidden = _isHidden();
|
||||
bool hidden = _runtime.IsHidden;
|
||||
if (_advancedFrame is { } advanced
|
||||
&& ReferenceEquals(advanced.Controller, controller))
|
||||
{
|
||||
MovementResult movement = RefreshSpatialFields(
|
||||
advanced.Movement,
|
||||
controller);
|
||||
_project(controller, movement, hidden);
|
||||
_runtime.Project(controller, movement, hidden);
|
||||
_advancedFrame = new AdvancedFrame(
|
||||
controller,
|
||||
movement,
|
||||
|
|
@ -176,7 +144,7 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
return;
|
||||
}
|
||||
|
||||
_sendPostNetwork(controller, hidden);
|
||||
_runtime.SendPostNetwork(controller, hidden);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -187,11 +155,11 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
public bool TryGetPresentationAfterNetwork(out PresentationFrame frame)
|
||||
{
|
||||
frame = default;
|
||||
PlayerMovementController? controller = _getController();
|
||||
if (!_canPresentPlayer() || controller is null)
|
||||
PlayerMovementController? controller = _runtime.Controller;
|
||||
if (!_runtime.CanPresentPlayer || controller is null)
|
||||
return false;
|
||||
|
||||
bool hidden = _isHidden();
|
||||
bool hidden = _runtime.IsHidden;
|
||||
if (_advancedFrame is { } advanced
|
||||
&& ReferenceEquals(advanced.Controller, controller))
|
||||
{
|
||||
|
|
@ -206,7 +174,7 @@ internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFram
|
|||
}
|
||||
|
||||
MovementResult initial = controller.CapturePresentationResult();
|
||||
_project(controller, initial, hidden);
|
||||
_runtime.Project(controller, initial, hidden);
|
||||
frame = new PresentationFrame(initial, hidden, AdvancedBeforeNetwork: false);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue