fix: complete retail parity stability pass
This commit is contained in:
parent
d3df4cb20a
commit
f7aa8e0eb7
131 changed files with 7765 additions and 1190 deletions
|
|
@ -192,11 +192,12 @@ public sealed class PhysicsTimestampGate
|
|||
_timestamps[ForcePosition] = forcePosition;
|
||||
|
||||
// SmartBox::HandleReceivedPosition 0x00453FD0: a fresh local
|
||||
// FORCE_POSITION whose teleport is exactly equal blips immediately,
|
||||
// assigns POSITION_TS directly (even equal/older), preserves the
|
||||
// current heading, sends a position event, and returns WITHOUT
|
||||
// advancing TELEPORT_TS.
|
||||
if (teleport == _timestamps[Teleport])
|
||||
// FORCE_POSITION whose teleport stamp is not older (equal OR
|
||||
// newer) blips immediately, assigns POSITION_TS directly (even
|
||||
// equal/older), preserves the current heading, sends a position
|
||||
// event, and returns WITHOUT advancing TELEPORT_TS. The same
|
||||
// wrap-safe predicate is used by IsFreshTeleportStart above.
|
||||
if (!IsNewer(teleport, _timestamps[Teleport]))
|
||||
{
|
||||
_timestamps[Position] = position;
|
||||
return PositionTimestampDisposition.ForcePosition;
|
||||
|
|
|
|||
|
|
@ -16,26 +16,13 @@ namespace AcDream.Core.Physics;
|
|||
/// transitional blending.
|
||||
///
|
||||
/// <para>
|
||||
/// This exact advance-with-wrap-then-lerp/slerp algorithm already exists as
|
||||
/// an inline, App-layer-only implementation for the "legacy" (no
|
||||
/// <see cref="AnimationSequencer"/>) NPC idle-cycle path —
|
||||
/// <c>LiveEntityAnimationPresenter.Present</c>'s non-sequencer branch
|
||||
/// (<c>CurrFrame += legacyAdvanceSeconds * Framerate</c> with the same
|
||||
/// modulo wrap) and its private <c>TryResolvePartFrame</c> helper (the same
|
||||
/// frame-bracket lerp/slerp). That call site has a live entity, a
|
||||
/// This is the shared implementation used by both the "legacy" (no
|
||||
/// <see cref="AnimationSequencer"/>) NPC idle-cycle path and the chargen
|
||||
/// preview. The live presenter has a live entity, a
|
||||
/// <c>LiveEntityRuntime</c> membership, and per-tick elapsed time supplied by
|
||||
/// the render loop; the chargen preview has none of that (there is no live
|
||||
/// entity — character creation hasn't happened yet), so it cannot reuse that
|
||||
/// class directly. Rather than re-typing the same formula a second time,
|
||||
/// this Core, pure, unit-testable class is the shared primitive: the
|
||||
/// chargen preview (<c>AcDream.App.Rendering.ChargenPreviewAnimator</c>)
|
||||
/// consumes it directly, and it is safe for a future pass to redirect
|
||||
/// <c>LiveEntityAnimationPresenter</c>'s inline copy through it as a
|
||||
/// behavior-preserving mechanical follow-up (not done here — that file is
|
||||
/// live, heavily tested production entity-rendering code with zero relation
|
||||
/// to this preview-only feature, so touching it is out of this slice's
|
||||
/// blast radius by design, not oversight). Tracked as
|
||||
/// <c>docs/ISSUES.md</c> #403 so the follow-up has an owner.
|
||||
/// entity — character creation hasn't happened yet), so neither consumer can
|
||||
/// own the primitive. Keeping it here prevents the two paths from drifting.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class RetailAnimationCyclePlayback
|
||||
|
|
@ -43,14 +30,15 @@ public static class RetailAnimationCyclePlayback
|
|||
/// <summary>
|
||||
/// Advances <paramref name="currFrame"/> by <c>elapsedSeconds * framerate</c>
|
||||
/// and wraps it back into <c>[lowFrame, highFrame]</c> with the SAME modulo
|
||||
/// shape <c>LiveEntityAnimationPresenter.Present</c>'s legacy branch uses
|
||||
/// shape retail playback and the live presenter's legacy branch use
|
||||
/// (<c>over % (span + 1)</c>, not a plain clamp — a frame position that
|
||||
/// overshoots the end by more than one span wraps around more than once
|
||||
/// rather than sticking at the boundary, matching a long stall/resume).
|
||||
/// Returns <paramref name="currFrame"/> unchanged for a degenerate cycle
|
||||
/// (<paramref name="highFrame"/> <= <paramref name="lowFrame"/>), a
|
||||
/// non-positive <paramref name="framerate"/>, or a non-positive
|
||||
/// <paramref name="elapsedSeconds"/>.
|
||||
/// (<paramref name="highFrame"/> <= <paramref name="lowFrame"/>) or a
|
||||
/// non-positive <paramref name="elapsedSeconds"/>. A negative framerate
|
||||
/// advances backward and clamps at the low frame, matching the former
|
||||
/// live-presenter implementation exactly.
|
||||
/// </summary>
|
||||
public static float Advance(
|
||||
float currFrame,
|
||||
|
|
@ -60,7 +48,7 @@ public static class RetailAnimationCyclePlayback
|
|||
float elapsedSeconds)
|
||||
{
|
||||
int span = highFrame - lowFrame;
|
||||
if (span <= 0 || framerate <= 0f || elapsedSeconds <= 0f)
|
||||
if (span <= 0 || elapsedSeconds <= 0f)
|
||||
return currFrame;
|
||||
|
||||
float next = currFrame + elapsedSeconds * framerate;
|
||||
|
|
@ -84,8 +72,7 @@ public static class RetailAnimationCyclePlayback
|
|||
/// back to <paramref name="lowFrame"/>). Returns <c>false</c> — with
|
||||
/// <c>default</c> outputs — when <paramref name="partIndex"/> is outside
|
||||
/// the bracketing frame's part list, matching
|
||||
/// <c>LiveEntityAnimationPresenter.TryResolvePartFrame</c>'s no-
|
||||
/// sequence-frames branch exactly.
|
||||
/// the live presenter's no-sequence-frames branch exactly.
|
||||
/// </summary>
|
||||
public static bool TryInterpolatePart(
|
||||
Animation animation,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue