fix(gameplay): reconcile wield ownership and target facing
Preserve PlayerDescription inventory/equipment ownership across authoritative manifest replacement, make weapon switching and combat/UI consumers read the same canonical object state, and carry the complete outbound player position frame across landblocks. Route target-facing and mouse-look through the shared MovementManager and MotionInterpreter completion owner. Match retail input aggregation, toggle ordering, turn/sidestep remapping, per-axis hold keys, and synchronous movement publication without render-only heading state. Initialize the live streaming origin from the first accepted canonical player Position, defer other projections until that origin exists, and retain logical entity identity through hydration. Advance the project ledger from completed M2 to active M3, synchronize CLAUDE.md/AGENTS.md and durable memory, and record the next cast-lifecycle, spellbook/enchantment, and two-client portal gates. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
b26f84cc69
commit
7b7ffcd278
36 changed files with 3884 additions and 761 deletions
|
|
@ -5,11 +5,10 @@ namespace AcDream.UI.Abstractions.Input;
|
|||
/// <summary>
|
||||
/// Phase K.2 — state machine for MMB-hold "instant mouse-look" mode
|
||||
/// (retail's <c>CameraInstantMouseLook</c>). While active, mouse-X
|
||||
/// delta drives the character's heading AND the chase camera yaw
|
||||
/// together (combined drive — the camera "instantly" follows the
|
||||
/// character because mouse-X moves the character, and the chase
|
||||
/// camera always tracks the character). Mouse-Y is left to the
|
||||
/// caller — typically pitches the chase camera only.
|
||||
/// delta produces retail's signed horizontal camera adjustment. The host
|
||||
/// routes that adjustment through the player's TurnLeft/TurnRight movement
|
||||
/// commands; the chase camera follows the resulting character heading.
|
||||
/// Mouse-Y is left to the caller — typically pitches the chase camera only.
|
||||
///
|
||||
/// <para>
|
||||
/// The class owns three transitions:
|
||||
|
|
@ -27,17 +26,28 @@ namespace AcDream.UI.Abstractions.Input;
|
|||
/// <para>
|
||||
/// <see cref="ApplyDelta"/> is the per-frame mouse-move hook: when
|
||||
/// active, scales <paramref name="dx"/> by sensitivity and feeds the
|
||||
/// caller-supplied yaw mutator. The mutator is the only side-channel —
|
||||
/// the class doesn't know about <c>PlayerMovementController</c> or
|
||||
/// <c>ChaseCamera</c>.
|
||||
/// caller-supplied movement-adjustment sink. The sink is the only
|
||||
/// side-channel — the class doesn't know about
|
||||
/// <c>PlayerMovementController</c> or <c>ChaseCamera</c>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class MouseLookState
|
||||
{
|
||||
private readonly Action<float> _applyYawDelta;
|
||||
private readonly Action<float> _applyHorizontalAdjustment;
|
||||
private int _horizontalExtent;
|
||||
private float _queuedDeltaX;
|
||||
private float _queuedDeltaY;
|
||||
private float _lastMouseInputTime;
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CInputManager_WIN32::GetInput @ 0x006897A0</c> does not
|
||||
/// synthesize an idle sample until the cursor has been still for strictly
|
||||
/// more than 0.2 seconds.
|
||||
/// </summary>
|
||||
public const float IdleZeroDelaySeconds = 0.2f;
|
||||
|
||||
/// <summary>True while MMB is held AND ImGui isn't capturing the
|
||||
/// mouse. Mouse-X deltas drive yaw only when this is true.</summary>
|
||||
/// mouse. Mouse-X deltas drive turn adjustment only when this is true.</summary>
|
||||
public bool Active { get; private set; }
|
||||
|
||||
/// <summary>Cursor X at the moment <see cref="Press"/> activated.
|
||||
|
|
@ -48,17 +58,19 @@ public sealed class MouseLookState
|
|||
public float CapturedCursorY { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Per-radian yaw multiplier applied to mouse-X delta. The same
|
||||
/// Per-pixel adjustment multiplier applied to mouse-X delta. The same
|
||||
/// chase-camera sensitivity factor used elsewhere in GameWindow is
|
||||
/// folded in by the caller; this class only owns the constant
|
||||
/// scale that converts pixels to radians. Default 0.004 matches
|
||||
/// the K.1b RMB-orbit factor.
|
||||
/// scale used before CameraSet's ×2 speed and 1.5 cap. Retail
|
||||
/// <c>MouseLookHandler</c> uses exactly 0.0666666701 after the configured
|
||||
/// input sensitivity.
|
||||
/// </summary>
|
||||
public float SensitivityRadiansPerPixel { get; set; } = 0.004f;
|
||||
public float SensitivityPerPixel { get; set; } = 0.0666666701f;
|
||||
|
||||
public MouseLookState(Action<float> applyYawDelta)
|
||||
public MouseLookState(Action<float> applyHorizontalAdjustment)
|
||||
{
|
||||
_applyYawDelta = applyYawDelta ?? throw new ArgumentNullException(nameof(applyYawDelta));
|
||||
_applyHorizontalAdjustment = applyHorizontalAdjustment
|
||||
?? throw new ArgumentNullException(nameof(applyHorizontalAdjustment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -71,13 +83,21 @@ public sealed class MouseLookState
|
|||
/// <param name="wantCaptureMouse">Mirror of
|
||||
/// <c>ImGui.GetIO().WantCaptureMouse</c>. When true, the press is
|
||||
/// ignored so a hover-over-panel MMB doesn't grab the cursor.</param>
|
||||
public void Press(float cursorX, float cursorY, bool wantCaptureMouse)
|
||||
public void Press(
|
||||
float cursorX,
|
||||
float cursorY,
|
||||
bool wantCaptureMouse,
|
||||
float nowSeconds = 0f)
|
||||
{
|
||||
if (wantCaptureMouse) return;
|
||||
if (Active) return;
|
||||
Active = true;
|
||||
CapturedCursorX = cursorX;
|
||||
CapturedCursorY = cursorY;
|
||||
_horizontalExtent = 0;
|
||||
_queuedDeltaX = 0f;
|
||||
_queuedDeltaY = 0f;
|
||||
_lastMouseInputTime = nowSeconds;
|
||||
}
|
||||
|
||||
/// <summary>MMB release transition. Always deactivates if active.</summary>
|
||||
|
|
@ -85,6 +105,9 @@ public sealed class MouseLookState
|
|||
{
|
||||
if (!Active) return;
|
||||
Active = false;
|
||||
_horizontalExtent = 0;
|
||||
_queuedDeltaX = 0f;
|
||||
_queuedDeltaY = 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -94,24 +117,83 @@ public sealed class MouseLookState
|
|||
/// </summary>
|
||||
public void OnWantCaptureMouseChanged(bool wantCaptureMouse)
|
||||
{
|
||||
if (Active && wantCaptureMouse) Active = false;
|
||||
if (Active && wantCaptureMouse)
|
||||
{
|
||||
Active = false;
|
||||
_horizontalExtent = 0;
|
||||
_queuedDeltaX = 0f;
|
||||
_queuedDeltaY = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accumulates event-driven Silk mouse motion for the next update sample.
|
||||
/// Retail's extent gate is clocked by samples, not by the number of native
|
||||
/// mouse messages delivered during one frame.
|
||||
/// </summary>
|
||||
public void QueueDelta(float dx, float dy = 0f)
|
||||
{
|
||||
if (Active && float.IsFinite(dx) && float.IsFinite(dy))
|
||||
{
|
||||
_queuedDeltaX += dx;
|
||||
_queuedDeltaY += dy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Consumes the frame's accumulated raw device motion once. When there is
|
||||
/// no net movement, returns a synthetic zero only after the strict retail
|
||||
/// 0.2-second idle boundary. The caller filters this one aggregate and then
|
||||
/// passes its horizontal component to <see cref="ApplyDelta"/>.
|
||||
/// </summary>
|
||||
public bool TryTakeRawSample(
|
||||
float nowSeconds,
|
||||
out float dx,
|
||||
out float dy)
|
||||
{
|
||||
dx = 0f;
|
||||
dy = 0f;
|
||||
if (!Active)
|
||||
{
|
||||
_queuedDeltaX = 0f;
|
||||
_queuedDeltaY = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
dx = _queuedDeltaX;
|
||||
dy = _queuedDeltaY;
|
||||
_queuedDeltaX = 0f;
|
||||
_queuedDeltaY = 0f;
|
||||
|
||||
if (dx != 0f || dy != 0f)
|
||||
{
|
||||
_lastMouseInputTime = nowSeconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
return nowSeconds > _lastMouseInputTime + IdleZeroDelaySeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply a per-frame mouse-X delta. When active, scales by
|
||||
/// <see cref="SensitivityRadiansPerPixel"/> times the
|
||||
/// <see cref="SensitivityPerPixel"/> times the
|
||||
/// caller-supplied <paramref name="extraSensitivity"/> (typically
|
||||
/// the chase-camera sens) and feeds it to the yaw mutator. Sign
|
||||
/// the chase-camera sens) and feeds it to the movement sink. Sign
|
||||
/// matches retail: dragging the mouse RIGHT yaws the character to
|
||||
/// the right (positive yaw delta).
|
||||
/// the right (a negative adjustment in acdream's turn convention).
|
||||
/// </summary>
|
||||
/// <param name="dx">Pixels of horizontal mouse motion since the
|
||||
/// last frame.</param>
|
||||
/// <param name="extraSensitivity">Multiplier (e.g. chase-camera
|
||||
/// sensitivity) applied on top of the radians-per-pixel scale.</param>
|
||||
/// sensitivity) applied on top of the per-pixel scale.</param>
|
||||
public void ApplyDelta(float dx, float extraSensitivity)
|
||||
{
|
||||
if (!Active) return;
|
||||
ProcessDelta(dx, extraSensitivity);
|
||||
}
|
||||
|
||||
private void ProcessDelta(float dx, float extraSensitivity)
|
||||
{
|
||||
// Sign: dragging the mouse RIGHT (dx > 0) should yaw the
|
||||
// character to the right. With the acdream Yaw convention
|
||||
// (where Yaw 0 = +X, increasing to +Y), positive yaw is
|
||||
|
|
@ -119,6 +201,20 @@ public sealed class MouseLookState
|
|||
// yaw goes DOWN (more clockwise). The dispatcher convention
|
||||
// for chase YawOffset is `YawOffset -= dx * factor`; we keep
|
||||
// the same sign here so character + camera rotate identically.
|
||||
_applyYawDelta(-dx * SensitivityRadiansPerPixel * extraSensitivity);
|
||||
float adjustment = -dx * SensitivityPerPixel * extraSensitivity;
|
||||
if (adjustment == 0f)
|
||||
{
|
||||
_horizontalExtent = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// MouseLookHandler @ 0x00458D80 increments mouselook_x_extent and
|
||||
// calls Rotate only after five consecutive non-zero samples. A zero
|
||||
// sample resets the extent.
|
||||
_horizontalExtent++;
|
||||
if (_horizontalExtent <= 5)
|
||||
return;
|
||||
|
||||
_applyHorizontalAdjustment(adjustment);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue