test(physics): pin issue 270 animation fixes

This commit is contained in:
Erik 2026-07-31 07:47:06 +02:00
parent bb1640f777
commit 0cb60d98a0
7 changed files with 337 additions and 43 deletions

View file

@ -98,6 +98,7 @@ internal sealed class LiveSessionRuntimeFactory
private readonly LiveSessionWorldRuntime _world;
private readonly LiveSessionCommandSurface _commands;
private readonly Action<string> _log;
private readonly StaminaExhaustionEdgeTracker _staminaExhaustion = new();
public LiveSessionRuntimeFactory(
LiveSessionPlayerRuntime player,
@ -189,6 +190,7 @@ internal sealed class LiveSessionRuntimeFactory
private void ResetPlayerPresentation()
{
_staminaExhaustion.Reset();
_interaction.PlayerMode.ResetSession();
_world.SpawnClaims.Reset();
}
@ -289,13 +291,6 @@ internal sealed class LiveSessionRuntimeFactory
OnMovementStatsUpdated: () => ApplyMovementStats("stats"));
}
/// <summary>
/// Tracks the previous "stamina exhausted" state so
/// <see cref="ApplyMovementStats"/> can fire retail's exhaustion
/// notification on the EDGE only. Null = no stamina reading applied yet.
/// </summary>
private bool? _lastStaminaExhausted;
/// <summary>
/// Re-applies the current <see cref="RuntimeMovementSkillState"/>
/// snapshot (skills/burden/stamina) to the live player controller.
@ -328,14 +323,8 @@ internal sealed class LiveSessionRuntimeFactory
}
RuntimeMovementSkillSnapshot snapshot = _domain.Character.MovementSkills.Snapshot;
bool exhausted = snapshot.CurrentStamina == 0;
if (_lastStaminaExhausted != exhausted)
{
bool isEdge = _lastStaminaExhausted is not null;
_lastStaminaExhausted = exhausted;
if (isEdge)
controller!.Motion.ReportExhaustion();
}
if (_staminaExhaustion.Observe(snapshot.CurrentStamina))
controller!.Motion.ReportExhaustion();
_log(
$"player: applied server movement {reason} "

View file

@ -0,0 +1,32 @@
namespace AcDream.App.Net;
/// <summary>
/// Tracks retail's stamina-exhaustion notification edge for one live-session
/// generation.
/// </summary>
internal sealed class StaminaExhaustionEdgeTracker
{
private bool? _wasExhausted;
/// <summary>
/// Observes the current stamina value and returns <see langword="true"/>
/// only when a previously initialized state changes between exhausted and
/// non-exhausted.
/// </summary>
public bool Observe(int currentStamina)
{
bool exhausted = currentStamina == 0;
if (_wasExhausted == exhausted)
return false;
bool isEdge = _wasExhausted.HasValue;
_wasExhausted = exhausted;
return isEdge;
}
/// <summary>
/// Forgets the retiring character/session sample. The first sample in the
/// next generation establishes a baseline and must not synthesize an edge.
/// </summary>
public void Reset() => _wasExhausted = null;
}